diff options
Diffstat (limited to 'indra')
423 files changed, 16508 insertions, 10624 deletions
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 86fc2dfff5..adc134c48c 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -83,8 +83,8 @@ if (WINDOWS) add_definitions(/WX) endif (NOT VS_DISABLE_FATAL_WARNINGS) - # configure win32 API for windows XP+ compatibility - set(WINVER "0x0501" CACHE STRING "Win32 API Target version (see http://msdn.microsoft.com/en-us/library/aa383745%28v=VS.85%29.aspx)") + # configure Win32 API for Windows Vista+ compatibility + set(WINVER "0x0600" CACHE STRING "Win32 API Target version (see http://msdn.microsoft.com/en-us/library/aa383745%28v=VS.85%29.aspx)") add_definitions("/DWINVER=${WINVER}" "/D_WIN32_WINNT=${WINVER}") endif (WINDOWS) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 6dc8e3dfbf..13a31cbce7 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -24,7 +24,6 @@ set(cmake_SOURCE_FILES DirectX.cmake DragDrop.cmake EXPAT.cmake -## ExamplePlugin.cmake FindAPR.cmake FindAutobuild.cmake FindBerkeleyDB.cmake @@ -100,6 +99,7 @@ set(cmake_SOURCE_FILES Variables.cmake ViewerMiscLibs.cmake VisualLeakDetector.cmake + LibVLCPlugin.cmake XmlRpcEpi.cmake ZLIB.cmake ) diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake index ba07a80f05..80af7ff2ab 100644 --- a/indra/cmake/LLWindow.cmake +++ b/indra/cmake/LLWindow.cmake @@ -18,7 +18,7 @@ else (USESYSTEMLIBS) use_prebuilt_binary(SDL) set (SDL_FOUND TRUE) set (SDL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/i686-linux) - set (SDL_LIBRARY SDL directfb fusion direct) + set (SDL_LIBRARY SDL directfb fusion direct X11) endif (LINUX) endif (USESYSTEMLIBS) diff --git a/indra/cmake/LibVLCPlugin.cmake b/indra/cmake/LibVLCPlugin.cmake new file mode 100644 index 0000000000..4472676fb4 --- /dev/null +++ b/indra/cmake/LibVLCPlugin.cmake @@ -0,0 +1,27 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) + +if (USESYSTEMLIBS) + set(LIBVLCPLUGIN OFF CACHE BOOL + "LIBVLCPLUGIN support for the llplugin/llmedia test apps.") +else (USESYSTEMLIBS) + use_prebuilt_binary(vlc-bin) + set(LIBVLCPLUGIN ON CACHE BOOL + "LIBVLCPLUGIN support for the llplugin/llmedia test apps.") + set(VLC_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/vlc) +endif (USESYSTEMLIBS) + +if (WINDOWS) + set(VLC_PLUGIN_LIBRARIES + libvlc.lib + libvlccore.lib + ) +elseif (DARWIN) +elseif (LINUX) + # Specify a full path to make sure we get a static link + set(VLC_PLUGIN_LIBRARIES + ${LIBS_PREBUILT_DIR}/lib/libvlc.a + ${LIBS_PREBUILT_DIR}/lib/libvlccore.a + ) +endif (WINDOWS) diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt index 32aa08a2b7..9f9ca6c39c 100644 --- a/indra/edit-me-to-trigger-new-build.txt +++ b/indra/edit-me-to-trigger-new-build.txt @@ -1,3 +1,4 @@ 2014-02-25 10:34 + diff --git a/indra/lib/python/indra/base/__init__.py b/indra/lib/python/indra/base/__init__.py deleted file mode 100755 index 2904fd3380..0000000000 --- a/indra/lib/python/indra/base/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -"""\ -@file __init__.py -@brief Initialization file for the indra.base module. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" diff --git a/indra/lib/python/indra/base/cllsd_test.py b/indra/lib/python/indra/base/cllsd_test.py deleted file mode 100755 index 1f06898ffd..0000000000 --- a/indra/lib/python/indra/base/cllsd_test.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python -## -## $LicenseInfo:firstyear=2011&license=viewerlgpl$ -## Second Life Viewer Source Code -## Copyright (C) 2011, Linden Research, Inc. -## -## This library is free software; you can redistribute it and/or -## modify it under the terms of the GNU Lesser General Public -## License as published by the Free Software Foundation; -## version 2.1 of the License only. -## -## This library is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## Lesser General Public License for more details. -## -## You should have received a copy of the GNU Lesser General Public -## License along with this library; if not, write to the Free Software -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -## -## Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -## $/LicenseInfo$ -from indra.base import llsd, lluuid -from datetime import datetime -import cllsd -import time, sys - -class myint(int): - pass - -values = ( - '&<>', - u'\u81acj', - llsd.uri('http://foo<'), - lluuid.UUID(), - llsd.LLSD(['thing']), - 1, - myint(31337), - sys.maxint + 10, - llsd.binary('foo'), - [], - {}, - {u'f&\u1212': 3}, - 3.1, - True, - None, - datetime.fromtimestamp(time.time()), - ) - -def valuator(values): - for v in values: - yield v - -longvalues = () # (values, list(values), iter(values), valuator(values)) - -for v in values + longvalues: - print '%r => %r' % (v, cllsd.llsd_to_xml(v)) - -a = [[{'a':3}]] * 1000000 - -s = time.time() -print hash(cllsd.llsd_to_xml(a)) -e = time.time() -t1 = e - s -print t1 - -s = time.time() -print hash(llsd.LLSDXMLFormatter()._format(a)) -e = time.time() -t2 = e - s -print t2 - -print 'Speedup:', t2 / t1 diff --git a/indra/lib/python/indra/base/config.py b/indra/lib/python/indra/base/config.py deleted file mode 100755 index adafa29b51..0000000000 --- a/indra/lib/python/indra/base/config.py +++ /dev/null @@ -1,266 +0,0 @@ -"""\ -@file config.py -@brief Utility module for parsing and accessing the indra.xml config file. - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import copy -import errno -import os -import traceback -import time -import types - -from os.path import dirname, getmtime, join, realpath -from indra.base import llsd - -_g_config = None - -class IndraConfig(object): - """ - IndraConfig loads a 'indra' xml configuration file - and loads into memory. This representation in memory - can get updated to overwrite values or add new values. - - The xml configuration file is considered a live file and changes - to the file are checked and reloaded periodically. If a value had - been overwritten via the update or set method, the loaded values - from the file are ignored (the values from the update/set methods - override) - """ - def __init__(self, indra_config_file): - self._indra_config_file = indra_config_file - self._reload_check_interval = 30 # seconds - self._last_check_time = 0 - self._last_mod_time = 0 - - self._config_overrides = {} - self._config_file_dict = {} - self._combined_dict = {} - - self._load() - - def _load(self): - # if you initialize the IndraConfig with None, no attempt - # is made to load any files - if self._indra_config_file is None: - return - - config_file = open(self._indra_config_file) - self._config_file_dict = llsd.parse(config_file.read()) - self._combine_dictionaries() - config_file.close() - - self._last_mod_time = self._get_last_modified_time() - self._last_check_time = time.time() # now - - def _get_last_modified_time(self): - """ - Returns the mtime (last modified time) of the config file, - if such exists. - """ - if self._indra_config_file is not None: - return os.path.getmtime(self._indra_config_file) - - return 0 - - def _combine_dictionaries(self): - self._combined_dict = {} - self._combined_dict.update(self._config_file_dict) - self._combined_dict.update(self._config_overrides) - - def _reload_if_necessary(self): - now = time.time() - - if (now - self._last_check_time) > self._reload_check_interval: - self._last_check_time = now - try: - modtime = self._get_last_modified_time() - if modtime > self._last_mod_time: - self._load() - except OSError, e: - if e.errno == errno.ENOENT: # file not found - # someone messed with our internal state - # or removed the file - - print 'WARNING: Configuration file has been removed ' + (self._indra_config_file) - print 'Disabling reloading of configuration file.' - - traceback.print_exc() - - self._indra_config_file = None - self._last_check_time = 0 - self._last_mod_time = 0 - else: - raise # pass the exception along to the caller - - def __getitem__(self, key): - self._reload_if_necessary() - - return self._combined_dict[key] - - def get(self, key, default = None): - try: - return self.__getitem__(key) - except KeyError: - return default - - def __setitem__(self, key, value): - """ - Sets the value of the config setting of key to be newval - - Once any key/value pair is changed via the set method, - that key/value pair will remain set with that value until - change via the update or set method - """ - self._config_overrides[key] = value - self._combine_dictionaries() - - def set(self, key, newval): - return self.__setitem__(key, newval) - - def update(self, new_conf): - """ - Load an XML file and apply its map as overrides or additions - to the existing config. Update can be a file or a dict. - - Once any key/value pair is changed via the update method, - that key/value pair will remain set with that value until - change via the update or set method - """ - if isinstance(new_conf, dict): - overrides = new_conf - else: - # assuming that it is a filename - config_file = open(new_conf) - overrides = llsd.parse(config_file.read()) - config_file.close() - - self._config_overrides.update(overrides) - self._combine_dictionaries() - - def as_dict(self): - """ - Returns immutable copy of the IndraConfig as a dictionary - """ - return copy.deepcopy(self._combined_dict) - -def load(config_xml_file = None): - global _g_config - - load_default_files = config_xml_file is None - if load_default_files: - ## going from: - ## "/opt/linden/indra/lib/python/indra/base/config.py" - ## to: - ## "/opt/linden/etc/indra.xml" - config_xml_file = realpath( - dirname(realpath(__file__)) + "../../../../../../etc/indra.xml") - - try: - _g_config = IndraConfig(config_xml_file) - except IOError: - # Failure to load passed in file - # or indra.xml default file - if load_default_files: - try: - config_xml_file = realpath( - dirname(realpath(__file__)) + "../../../../../../etc/globals.xml") - _g_config = IndraConfig(config_xml_file) - return - except IOError: - # Failure to load globals.xml - # fall to code below - pass - - # Either failed to load passed in file - # or failed to load all default files - _g_config = IndraConfig(None) - -def dump(indra_xml_file, indra_cfg = None, update_in_mem=False): - ''' - Dump config contents into a file - Kindof reverse of load. - Optionally takes a new config to dump. - Does NOT update global config unless requested. - ''' - global _g_config - - if not indra_cfg: - if _g_config is None: - return - - indra_cfg = _g_config.as_dict() - - if not indra_cfg: - return - - config_file = open(indra_xml_file, 'w') - _config_xml = llsd.format_xml(indra_cfg) - config_file.write(_config_xml) - config_file.close() - - if update_in_mem: - update(indra_cfg) - -def update(new_conf): - global _g_config - - if _g_config is None: - # To keep with how this function behaved - # previously, a call to update - # before the global is defined - # make a new global config which does not - # load data from a file. - _g_config = IndraConfig(None) - - return _g_config.update(new_conf) - -def get(key, default = None): - global _g_config - - if _g_config is None: - load() - - return _g_config.get(key, default) - -def set(key, newval): - """ - Sets the value of the config setting of key to be newval - - Once any key/value pair is changed via the set method, - that key/value pair will remain set with that value until - change via the update or set method or program termination - """ - global _g_config - - if _g_config is None: - _g_config = IndraConfig(None) - - _g_config.set(key, newval) - -def get_config(): - global _g_config - return _g_config diff --git a/indra/lib/python/indra/base/llsd.py b/indra/lib/python/indra/base/llsd.py deleted file mode 100755 index 4527b115f9..0000000000 --- a/indra/lib/python/indra/base/llsd.py +++ /dev/null @@ -1,1052 +0,0 @@ -"""\ -@file llsd.py -@brief Types as well as parsing and formatting functions for handling LLSD. - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import datetime -import base64 -import string -import struct -import time -import types -import re - -from indra.util.fastest_elementtree import ElementTreeError, fromstring -from indra.base import lluuid - -# cllsd.c in server/server-1.25 has memory leaks, -# so disabling cllsd for now -#try: -# import cllsd -#except ImportError: -# cllsd = None -cllsd = None - -int_regex = re.compile(r"[-+]?\d+") -real_regex = re.compile(r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?") -alpha_regex = re.compile(r"[a-zA-Z]+") -date_regex = re.compile(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})T" - r"(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})" - r"(?P<second_float>(\.\d+)?)Z") -#date: d"YYYY-MM-DDTHH:MM:SS.FFFFFFZ" - -class LLSDParseError(Exception): - pass - -class LLSDSerializationError(TypeError): - pass - - -class binary(str): - pass - -class uri(str): - pass - - -BOOL_TRUE = ('1', '1.0', 'true') -BOOL_FALSE = ('0', '0.0', 'false', '') - - -def format_datestr(v): - """ Formats a datetime or date object into the string format shared by xml and notation serializations.""" - if hasattr(v, 'microsecond'): - return v.isoformat() + 'Z' - else: - return v.strftime('%Y-%m-%dT%H:%M:%SZ') - -def parse_datestr(datestr): - """Parses a datetime object from the string format shared by xml and notation serializations.""" - if datestr == "": - return datetime.datetime(1970, 1, 1) - - match = re.match(date_regex, datestr) - if not match: - raise LLSDParseError("invalid date string '%s'." % datestr) - - year = int(match.group('year')) - month = int(match.group('month')) - day = int(match.group('day')) - hour = int(match.group('hour')) - minute = int(match.group('minute')) - second = int(match.group('second')) - seconds_float = match.group('second_float') - microsecond = 0 - if seconds_float: - microsecond = int(float('0' + seconds_float) * 1e6) - return datetime.datetime(year, month, day, hour, minute, second, microsecond) - - -def bool_to_python(node): - val = node.text or '' - if val in BOOL_TRUE: - return True - else: - return False - -def int_to_python(node): - val = node.text or '' - if not val.strip(): - return 0 - return int(val) - -def real_to_python(node): - val = node.text or '' - if not val.strip(): - return 0.0 - return float(val) - -def uuid_to_python(node): - return lluuid.UUID(node.text) - -def str_to_python(node): - return node.text or '' - -def bin_to_python(node): - return binary(base64.decodestring(node.text or '')) - -def date_to_python(node): - val = node.text or '' - if not val: - val = "1970-01-01T00:00:00Z" - return parse_datestr(val) - - -def uri_to_python(node): - val = node.text or '' - if not val: - return None - return uri(val) - -def map_to_python(node): - result = {} - for index in range(len(node))[::2]: - result[node[index].text] = to_python(node[index+1]) - return result - -def array_to_python(node): - return [to_python(child) for child in node] - - -NODE_HANDLERS = dict( - undef=lambda x: None, - boolean=bool_to_python, - integer=int_to_python, - real=real_to_python, - uuid=uuid_to_python, - string=str_to_python, - binary=bin_to_python, - date=date_to_python, - uri=uri_to_python, - map=map_to_python, - array=array_to_python, - ) - -def to_python(node): - return NODE_HANDLERS[node.tag](node) - -class Nothing(object): - pass - - -class LLSDXMLFormatter(object): - def __init__(self): - self.type_map = { - type(None) : self.UNDEF, - bool : self.BOOLEAN, - int : self.INTEGER, - long : self.INTEGER, - float : self.REAL, - lluuid.UUID : self.UUID, - binary : self.BINARY, - str : self.STRING, - unicode : self.STRING, - uri : self.URI, - datetime.datetime : self.DATE, - datetime.date : self.DATE, - list : self.ARRAY, - tuple : self.ARRAY, - types.GeneratorType : self.ARRAY, - dict : self.MAP, - LLSD : self.LLSD - } - - def elt(self, name, contents=None): - if(contents is None or contents is ''): - return "<%s />" % (name,) - else: - if type(contents) is unicode: - contents = contents.encode('utf-8') - return "<%s>%s</%s>" % (name, contents, name) - - def xml_esc(self, v): - if type(v) is unicode: - v = v.encode('utf-8') - return v.replace('&', '&').replace('<', '<').replace('>', '>') - - def LLSD(self, v): - return self.generate(v.thing) - def UNDEF(self, v): - return self.elt('undef') - def BOOLEAN(self, v): - if v: - return self.elt('boolean', 'true') - else: - return self.elt('boolean', 'false') - def INTEGER(self, v): - return self.elt('integer', v) - def REAL(self, v): - return self.elt('real', v) - def UUID(self, v): - if(v.isNull()): - return self.elt('uuid') - else: - return self.elt('uuid', v) - def BINARY(self, v): - return self.elt('binary', base64.encodestring(v)) - def STRING(self, v): - return self.elt('string', self.xml_esc(v)) - def URI(self, v): - return self.elt('uri', self.xml_esc(str(v))) - def DATE(self, v): - return self.elt('date', format_datestr(v)) - def ARRAY(self, v): - return self.elt('array', ''.join([self.generate(item) for item in v])) - def MAP(self, v): - return self.elt( - 'map', - ''.join(["%s%s" % (self.elt('key', self.xml_esc(str(key))), self.generate(value)) - for key, value in v.items()])) - - typeof = type - def generate(self, something): - t = self.typeof(something) - if self.type_map.has_key(t): - return self.type_map[t](something) - else: - raise LLSDSerializationError("Cannot serialize unknown type: %s (%s)" % ( - t, something)) - - def _format(self, something): - return '<?xml version="1.0" ?>' + self.elt("llsd", self.generate(something)) - - def format(self, something): - if cllsd: - return cllsd.llsd_to_xml(something) - return self._format(something) - -_g_xml_formatter = None -def format_xml(something): - global _g_xml_formatter - if _g_xml_formatter is None: - _g_xml_formatter = LLSDXMLFormatter() - return _g_xml_formatter.format(something) - -class LLSDXMLPrettyFormatter(LLSDXMLFormatter): - def __init__(self, indent_atom = None): - # Call the super class constructor so that we have the type map - super(LLSDXMLPrettyFormatter, self).__init__() - - # Override the type map to use our specialized formatters to - # emit the pretty output. - self.type_map[list] = self.PRETTY_ARRAY - self.type_map[tuple] = self.PRETTY_ARRAY - self.type_map[types.GeneratorType] = self.PRETTY_ARRAY, - self.type_map[dict] = self.PRETTY_MAP - - # Private data used for indentation. - self._indent_level = 1 - if indent_atom is None: - self._indent_atom = ' ' - else: - self._indent_atom = indent_atom - - def _indent(self): - "Return an indentation based on the atom and indentation level." - return self._indent_atom * self._indent_level - - def PRETTY_ARRAY(self, v): - rv = [] - rv.append('<array>\n') - self._indent_level = self._indent_level + 1 - rv.extend(["%s%s\n" % - (self._indent(), - self.generate(item)) - for item in v]) - self._indent_level = self._indent_level - 1 - rv.append(self._indent()) - rv.append('</array>') - return ''.join(rv) - - def PRETTY_MAP(self, v): - rv = [] - rv.append('<map>\n') - self._indent_level = self._indent_level + 1 - keys = v.keys() - keys.sort() - rv.extend(["%s%s\n%s%s\n" % - (self._indent(), - self.elt('key', key), - self._indent(), - self.generate(v[key])) - for key in keys]) - self._indent_level = self._indent_level - 1 - rv.append(self._indent()) - rv.append('</map>') - return ''.join(rv) - - def format(self, something): - data = [] - data.append('<?xml version="1.0" ?>\n<llsd>') - data.append(self.generate(something)) - data.append('</llsd>\n') - return '\n'.join(data) - -def format_pretty_xml(something): - """@brief Serialize a python object as 'pretty' llsd xml. - - The output conforms to the LLSD DTD, unlike the output from the - standard python xml.dom DOM::toprettyxml() method which does not - preserve significant whitespace. - This function is not necessarily suited for serializing very large - objects. It is not optimized by the cllsd module, and sorts on - dict (llsd map) keys alphabetically to ease human reading. - """ - return LLSDXMLPrettyFormatter().format(something) - -class LLSDNotationFormatter(object): - def __init__(self): - self.type_map = { - type(None) : self.UNDEF, - bool : self.BOOLEAN, - int : self.INTEGER, - long : self.INTEGER, - float : self.REAL, - lluuid.UUID : self.UUID, - binary : self.BINARY, - str : self.STRING, - unicode : self.STRING, - uri : self.URI, - datetime.datetime : self.DATE, - datetime.date : self.DATE, - list : self.ARRAY, - tuple : self.ARRAY, - types.GeneratorType : self.ARRAY, - dict : self.MAP, - LLSD : self.LLSD - } - - def LLSD(self, v): - return self.generate(v.thing) - def UNDEF(self, v): - return '!' - def BOOLEAN(self, v): - if v: - return 'true' - else: - return 'false' - def INTEGER(self, v): - return "i%s" % v - def REAL(self, v): - return "r%s" % v - def UUID(self, v): - return "u%s" % v - def BINARY(self, v): - return 'b64"' + base64.encodestring(v) + '"' - def STRING(self, v): - if isinstance(v, unicode): - v = v.encode('utf-8') - return "'%s'" % v.replace("\\", "\\\\").replace("'", "\\'") - def URI(self, v): - return 'l"%s"' % str(v).replace("\\", "\\\\").replace('"', '\\"') - def DATE(self, v): - return 'd"%s"' % format_datestr(v) - def ARRAY(self, v): - return "[%s]" % ','.join([self.generate(item) for item in v]) - def MAP(self, v): - def fix(key): - if isinstance(key, unicode): - return key.encode('utf-8') - return key - return "{%s}" % ','.join(["'%s':%s" % (fix(key).replace("\\", "\\\\").replace("'", "\\'"), self.generate(value)) - for key, value in v.items()]) - - def generate(self, something): - t = type(something) - handler = self.type_map.get(t) - if handler: - return handler(something) - else: - try: - return self.ARRAY(iter(something)) - except TypeError: - raise LLSDSerializationError( - "Cannot serialize unknown type: %s (%s)" % (t, something)) - - def format(self, something): - return self.generate(something) - -def format_notation(something): - return LLSDNotationFormatter().format(something) - -def _hex_as_nybble(hex): - if (hex >= '0') and (hex <= '9'): - return ord(hex) - ord('0') - elif (hex >= 'a') and (hex <='f'): - return 10 + ord(hex) - ord('a') - elif (hex >= 'A') and (hex <='F'): - return 10 + ord(hex) - ord('A'); - -class LLSDBinaryParser(object): - def __init__(self): - pass - - def parse(self, buffer, ignore_binary = False): - """ - This is the basic public interface for parsing. - - @param buffer the binary data to parse in an indexable sequence. - @param ignore_binary parser throws away data in llsd binary nodes. - @return returns a python object. - """ - self._buffer = buffer - self._index = 0 - self._keep_binary = not ignore_binary - return self._parse() - - def _parse(self): - cc = self._buffer[self._index] - self._index += 1 - if cc == '{': - return self._parse_map() - elif cc == '[': - return self._parse_array() - elif cc == '!': - return None - elif cc == '0': - return False - elif cc == '1': - return True - elif cc == 'i': - # 'i' = integer - idx = self._index - self._index += 4 - return struct.unpack("!i", self._buffer[idx:idx+4])[0] - elif cc == ('r'): - # 'r' = real number - idx = self._index - self._index += 8 - return struct.unpack("!d", self._buffer[idx:idx+8])[0] - elif cc == 'u': - # 'u' = uuid - idx = self._index - self._index += 16 - return lluuid.uuid_bits_to_uuid(self._buffer[idx:idx+16]) - elif cc == 's': - # 's' = string - return self._parse_string() - elif cc in ("'", '"'): - # delimited/escaped string - return self._parse_string_delim(cc) - elif cc == 'l': - # 'l' = uri - return uri(self._parse_string()) - elif cc == ('d'): - # 'd' = date in seconds since epoch - idx = self._index - self._index += 8 - seconds = struct.unpack("!d", self._buffer[idx:idx+8])[0] - return datetime.datetime.fromtimestamp(seconds) - elif cc == 'b': - binary = self._parse_string() - if self._keep_binary: - return binary - # *NOTE: maybe have a binary placeholder which has the - # length. - return None - else: - raise LLSDParseError("invalid binary token at byte %d: %d" % ( - self._index - 1, ord(cc))) - - def _parse_map(self): - rv = {} - size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0] - self._index += 4 - count = 0 - cc = self._buffer[self._index] - self._index += 1 - key = '' - while (cc != '}') and (count < size): - if cc == 'k': - key = self._parse_string() - elif cc in ("'", '"'): - key = self._parse_string_delim(cc) - else: - raise LLSDParseError("invalid map key at byte %d." % ( - self._index - 1,)) - value = self._parse() - rv[key] = value - count += 1 - cc = self._buffer[self._index] - self._index += 1 - if cc != '}': - raise LLSDParseError("invalid map close token at byte %d." % ( - self._index,)) - return rv - - def _parse_array(self): - rv = [] - size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0] - self._index += 4 - count = 0 - cc = self._buffer[self._index] - while (cc != ']') and (count < size): - rv.append(self._parse()) - count += 1 - cc = self._buffer[self._index] - if cc != ']': - raise LLSDParseError("invalid array close token at byte %d." % ( - self._index,)) - self._index += 1 - return rv - - def _parse_string(self): - size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0] - self._index += 4 - rv = self._buffer[self._index:self._index+size] - self._index += size - return rv - - def _parse_string_delim(self, delim): - list = [] - found_escape = False - found_hex = False - found_digit = False - byte = 0 - while True: - cc = self._buffer[self._index] - self._index += 1 - if found_escape: - if found_hex: - if found_digit: - found_escape = False - found_hex = False - found_digit = False - byte <<= 4 - byte |= _hex_as_nybble(cc) - list.append(chr(byte)) - byte = 0 - else: - found_digit = True - byte = _hex_as_nybble(cc) - elif cc == 'x': - found_hex = True - else: - if cc == 'a': - list.append('\a') - elif cc == 'b': - list.append('\b') - elif cc == 'f': - list.append('\f') - elif cc == 'n': - list.append('\n') - elif cc == 'r': - list.append('\r') - elif cc == 't': - list.append('\t') - elif cc == 'v': - list.append('\v') - else: - list.append(cc) - found_escape = False - elif cc == '\\': - found_escape = True - elif cc == delim: - break - else: - list.append(cc) - return ''.join(list) - -class LLSDNotationParser(object): - """ Parse LLSD notation: - map: { string:object, string:object } - array: [ object, object, object ] - undef: ! - boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE - integer: i#### - real: r#### - uuid: u#### - string: "g\'day" | 'have a "nice" day' | s(size)"raw data" - uri: l"escaped" - date: d"YYYY-MM-DDTHH:MM:SS.FFZ" - binary: b##"ff3120ab1" | b(size)"raw data" - """ - def __init__(self): - pass - - def parse(self, buffer, ignore_binary = False): - """ - This is the basic public interface for parsing. - - @param buffer the notation string to parse. - @param ignore_binary parser throws away data in llsd binary nodes. - @return returns a python object. - """ - if buffer == "": - return False - - self._buffer = buffer - self._index = 0 - return self._parse() - - def _parse(self): - cc = self._buffer[self._index] - self._index += 1 - if cc == '{': - return self._parse_map() - elif cc == '[': - return self._parse_array() - elif cc == '!': - return None - elif cc == '0': - return False - elif cc == '1': - return True - elif cc in ('F', 'f'): - self._skip_alpha() - return False - elif cc in ('T', 't'): - self._skip_alpha() - return True - elif cc == 'i': - # 'i' = integer - return self._parse_integer() - elif cc == ('r'): - # 'r' = real number - return self._parse_real() - elif cc == 'u': - # 'u' = uuid - return self._parse_uuid() - elif cc in ("'", '"', 's'): - return self._parse_string(cc) - elif cc == 'l': - # 'l' = uri - delim = self._buffer[self._index] - self._index += 1 - val = uri(self._parse_string(delim)) - if len(val) == 0: - return None - return val - elif cc == ('d'): - # 'd' = date in seconds since epoch - return self._parse_date() - elif cc == 'b': - return self._parse_binary() - else: - raise LLSDParseError("invalid token at index %d: %d" % ( - self._index - 1, ord(cc))) - - def _parse_binary(self): - i = self._index - if self._buffer[i:i+2] == '64': - q = self._buffer[i+2] - e = self._buffer.find(q, i+3) - try: - return base64.decodestring(self._buffer[i+3:e]) - finally: - self._index = e + 1 - else: - raise LLSDParseError('random horrible binary format not supported') - - def _parse_map(self): - """ map: { string:object, string:object } """ - rv = {} - cc = self._buffer[self._index] - self._index += 1 - key = '' - found_key = False - while (cc != '}'): - if not found_key: - if cc in ("'", '"', 's'): - key = self._parse_string(cc) - found_key = True - elif cc.isspace() or cc == ',': - cc = self._buffer[self._index] - self._index += 1 - else: - raise LLSDParseError("invalid map key at byte %d." % ( - self._index - 1,)) - elif cc.isspace() or cc == ':': - cc = self._buffer[self._index] - self._index += 1 - continue - else: - self._index += 1 - value = self._parse() - rv[key] = value - found_key = False - cc = self._buffer[self._index] - self._index += 1 - - return rv - - def _parse_array(self): - """ array: [ object, object, object ] """ - rv = [] - cc = self._buffer[self._index] - while (cc != ']'): - if cc.isspace() or cc == ',': - self._index += 1 - cc = self._buffer[self._index] - continue - rv.append(self._parse()) - cc = self._buffer[self._index] - - if cc != ']': - raise LLSDParseError("invalid array close token at index %d." % ( - self._index,)) - self._index += 1 - return rv - - def _parse_uuid(self): - match = re.match(lluuid.UUID.uuid_regex, self._buffer[self._index:]) - if not match: - raise LLSDParseError("invalid uuid token at index %d." % self._index) - - (start, end) = match.span() - start += self._index - end += self._index - self._index = end - return lluuid.UUID(self._buffer[start:end]) - - def _skip_alpha(self): - match = re.match(alpha_regex, self._buffer[self._index:]) - if match: - self._index += match.end() - - def _parse_date(self): - delim = self._buffer[self._index] - self._index += 1 - datestr = self._parse_string(delim) - return parse_datestr(datestr) - - def _parse_real(self): - match = re.match(real_regex, self._buffer[self._index:]) - if not match: - raise LLSDParseError("invalid real token at index %d." % self._index) - - (start, end) = match.span() - start += self._index - end += self._index - self._index = end - return float( self._buffer[start:end] ) - - def _parse_integer(self): - match = re.match(int_regex, self._buffer[self._index:]) - if not match: - raise LLSDParseError("invalid integer token at index %d." % self._index) - - (start, end) = match.span() - start += self._index - end += self._index - self._index = end - return int( self._buffer[start:end] ) - - def _parse_string(self, delim): - """ string: "g\'day" | 'have a "nice" day' | s(size)"raw data" """ - rv = "" - - if delim in ("'", '"'): - rv = self._parse_string_delim(delim) - elif delim == 's': - rv = self._parse_string_raw() - else: - raise LLSDParseError("invalid string token at index %d." % self._index) - - return rv - - - def _parse_string_delim(self, delim): - """ string: "g'day 'un" | 'have a "nice" day' """ - list = [] - found_escape = False - found_hex = False - found_digit = False - byte = 0 - while True: - cc = self._buffer[self._index] - self._index += 1 - if found_escape: - if found_hex: - if found_digit: - found_escape = False - found_hex = False - found_digit = False - byte <<= 4 - byte |= _hex_as_nybble(cc) - list.append(chr(byte)) - byte = 0 - else: - found_digit = True - byte = _hex_as_nybble(cc) - elif cc == 'x': - found_hex = True - else: - if cc == 'a': - list.append('\a') - elif cc == 'b': - list.append('\b') - elif cc == 'f': - list.append('\f') - elif cc == 'n': - list.append('\n') - elif cc == 'r': - list.append('\r') - elif cc == 't': - list.append('\t') - elif cc == 'v': - list.append('\v') - else: - list.append(cc) - found_escape = False - elif cc == '\\': - found_escape = True - elif cc == delim: - break - else: - list.append(cc) - return ''.join(list) - - def _parse_string_raw(self): - """ string: s(size)"raw data" """ - # Read the (size) portion. - cc = self._buffer[self._index] - self._index += 1 - if cc != '(': - raise LLSDParseError("invalid string token at index %d." % self._index) - - rparen = self._buffer.find(')', self._index) - if rparen == -1: - raise LLSDParseError("invalid string token at index %d." % self._index) - - size = int(self._buffer[self._index:rparen]) - - self._index = rparen + 1 - delim = self._buffer[self._index] - self._index += 1 - if delim not in ("'", '"'): - raise LLSDParseError("invalid string token at index %d." % self._index) - - rv = self._buffer[self._index:(self._index + size)] - self._index += size - cc = self._buffer[self._index] - self._index += 1 - if cc != delim: - raise LLSDParseError("invalid string token at index %d." % self._index) - - return rv - -def format_binary(something): - return '<?llsd/binary?>\n' + _format_binary_recurse(something) - -def _format_binary_recurse(something): - def _format_list(something): - array_builder = [] - array_builder.append('[' + struct.pack('!i', len(something))) - for item in something: - array_builder.append(_format_binary_recurse(item)) - array_builder.append(']') - return ''.join(array_builder) - - if something is None: - return '!' - elif isinstance(something, LLSD): - return _format_binary_recurse(something.thing) - elif isinstance(something, bool): - if something: - return '1' - else: - return '0' - elif isinstance(something, (int, long)): - return 'i' + struct.pack('!i', something) - elif isinstance(something, float): - return 'r' + struct.pack('!d', something) - elif isinstance(something, lluuid.UUID): - return 'u' + something._bits - elif isinstance(something, binary): - return 'b' + struct.pack('!i', len(something)) + something - elif isinstance(something, str): - return 's' + struct.pack('!i', len(something)) + something - elif isinstance(something, unicode): - something = something.encode('utf-8') - return 's' + struct.pack('!i', len(something)) + something - elif isinstance(something, uri): - return 'l' + struct.pack('!i', len(something)) + something - elif isinstance(something, datetime.datetime): - seconds_since_epoch = time.mktime(something.timetuple()) - return 'd' + struct.pack('!d', seconds_since_epoch) - elif isinstance(something, (list, tuple)): - return _format_list(something) - elif isinstance(something, dict): - map_builder = [] - map_builder.append('{' + struct.pack('!i', len(something))) - for key, value in something.items(): - if isinstance(key, unicode): - key = key.encode('utf-8') - map_builder.append('k' + struct.pack('!i', len(key)) + key) - map_builder.append(_format_binary_recurse(value)) - map_builder.append('}') - return ''.join(map_builder) - else: - try: - return _format_list(list(something)) - except TypeError: - raise LLSDSerializationError( - "Cannot serialize unknown type: %s (%s)" % - (type(something), something)) - - -def parse_binary(binary): - if binary.startswith('<?llsd/binary?>'): - just_binary = binary.split('\n', 1)[1] - else: - just_binary = binary - return LLSDBinaryParser().parse(just_binary) - -def parse_xml(something): - try: - return to_python(fromstring(something)[0]) - except ElementTreeError, err: - raise LLSDParseError(*err.args) - -def parse_notation(something): - return LLSDNotationParser().parse(something) - -def parse(something): - try: - something = string.lstrip(something) #remove any pre-trailing whitespace - if something.startswith('<?llsd/binary?>'): - return parse_binary(something) - # This should be better. - elif something.startswith('<'): - return parse_xml(something) - else: - return parse_notation(something) - except KeyError, e: - raise Exception('LLSD could not be parsed: %s' % (e,)) - -class LLSD(object): - def __init__(self, thing=None): - self.thing = thing - - def __str__(self): - return self.toXML(self.thing) - - parse = staticmethod(parse) - toXML = staticmethod(format_xml) - toPrettyXML = staticmethod(format_pretty_xml) - toBinary = staticmethod(format_binary) - toNotation = staticmethod(format_notation) - - -undef = LLSD(None) - -XML_MIME_TYPE = 'application/llsd+xml' -BINARY_MIME_TYPE = 'application/llsd+binary' - -# register converters for llsd in mulib, if it is available -try: - from mulib import stacked, mu - stacked.NoProducer() # just to exercise stacked - mu.safe_load(None) # just to exercise mu -except: - # mulib not available, don't print an error message since this is normal - pass -else: - mu.add_parser(parse, XML_MIME_TYPE) - mu.add_parser(parse, 'application/llsd+binary') - - def llsd_convert_xml(llsd_stuff, request): - request.write(format_xml(llsd_stuff)) - - def llsd_convert_binary(llsd_stuff, request): - request.write(format_binary(llsd_stuff)) - - for typ in [LLSD, dict, list, tuple, str, int, long, float, bool, unicode, type(None)]: - stacked.add_producer(typ, llsd_convert_xml, XML_MIME_TYPE) - stacked.add_producer(typ, llsd_convert_xml, 'application/xml') - stacked.add_producer(typ, llsd_convert_xml, 'text/xml') - - stacked.add_producer(typ, llsd_convert_binary, 'application/llsd+binary') - - stacked.add_producer(LLSD, llsd_convert_xml, '*/*') - - # in case someone is using the legacy mu.xml wrapper, we need to - # tell mu to produce application/xml or application/llsd+xml - # (based on the accept header) from raw xml. Phoenix 2008-07-21 - stacked.add_producer(mu.xml, mu.produce_raw, XML_MIME_TYPE) - stacked.add_producer(mu.xml, mu.produce_raw, 'application/xml') - - - -# mulib wsgi stuff -# try: -# from mulib import mu, adapters -# -# # try some known attributes from mulib to be ultra-sure we've imported it -# mu.get_current -# adapters.handlers -# except: -# # mulib not available, don't print an error message since this is normal -# pass -# else: -# def llsd_xml_handler(content_type): -# def handle_llsd_xml(env, start_response): -# llsd_stuff, _ = mu.get_current(env) -# result = format_xml(llsd_stuff) -# start_response("200 OK", [('Content-Type', content_type)]) -# env['mu.negotiated_type'] = content_type -# yield result -# return handle_llsd_xml -# -# def llsd_binary_handler(content_type): -# def handle_llsd_binary(env, start_response): -# llsd_stuff, _ = mu.get_current(env) -# result = format_binary(llsd_stuff) -# start_response("200 OK", [('Content-Type', content_type)]) -# env['mu.negotiated_type'] = content_type -# yield result -# return handle_llsd_binary -# -# adapters.DEFAULT_PARSERS[XML_MIME_TYPE] = parse - -# for typ in [LLSD, dict, list, tuple, str, int, float, bool, unicode, type(None)]: -# for content_type in (XML_MIME_TYPE, 'application/xml'): -# adapters.handlers.set_handler(typ, llsd_xml_handler(content_type), content_type) -# -# adapters.handlers.set_handler(typ, llsd_binary_handler(BINARY_MIME_TYPE), BINARY_MIME_TYPE) -# -# adapters.handlers.set_handler(LLSD, llsd_xml_handler(XML_MIME_TYPE), '*/*') diff --git a/indra/lib/python/indra/base/lluuid.py b/indra/lib/python/indra/base/lluuid.py deleted file mode 100755 index 7413ffe10d..0000000000 --- a/indra/lib/python/indra/base/lluuid.py +++ /dev/null @@ -1,319 +0,0 @@ -"""\ -@file lluuid.py -@brief UUID parser/generator. - -$LicenseInfo:firstyear=2004&license=mit$ - -Copyright (c) 2004-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import random, socket, string, time, re -import uuid -try: - # Python 2.6 - from hashlib import md5 -except ImportError: - # Python 2.5 and earlier - from md5 import new as md5 - -def _int2binstr(i,l): - s='' - for a in range(l): - s=chr(i&0xFF)+s - i>>=8 - return s - -def _binstr2int(s): - i = long(0) - for c in s: - i = (i<<8) + ord(c) - return i - -class UUID(object): - """ - A class which represents a 16 byte integer. Stored as a 16 byte 8 - bit character string. - - The string version is to be of the form: - AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex) - where A=network address, B=timestamp, C=random. - """ - - NULL_STR = "00000000-0000-0000-0000-000000000000" - - # the UUIDREGEX_STRING is helpful for parsing UUID's in text - hex_wildcard = r"[0-9a-fA-F]" - word = hex_wildcard + r"{4,4}-" - long_word = hex_wildcard + r"{8,8}-" - very_long_word = hex_wildcard + r"{12,12}" - UUID_REGEX_STRING = long_word + word + word + word + very_long_word - uuid_regex = re.compile(UUID_REGEX_STRING) - - rand = random.Random() - ip = '' - try: - ip = socket.gethostbyname(socket.gethostname()) - except(socket.gaierror, socket.error): - # no ip address, so just default to somewhere in 10.x.x.x - ip = '10' - for i in range(3): - ip += '.' + str(rand.randrange(1,254)) - hexip = ''.join(["%04x" % long(i) for i in ip.split('.')]) - lastid = '' - - def __init__(self, possible_uuid=None): - """ - Initialize to first valid UUID in argument (if a string), - or to null UUID if none found or argument is not supplied. - - If the argument is a UUID, the constructed object will be a copy of it. - """ - self._bits = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - if possible_uuid is None: - return - - if isinstance(possible_uuid, type(self)): - self.set(possible_uuid) - return - - uuid_match = UUID.uuid_regex.search(possible_uuid) - if uuid_match: - uuid_string = uuid_match.group() - s = string.replace(uuid_string, '-', '') - self._bits = _int2binstr(string.atol(s[:8],16),4) + \ - _int2binstr(string.atol(s[8:16],16),4) + \ - _int2binstr(string.atol(s[16:24],16),4) + \ - _int2binstr(string.atol(s[24:],16),4) - - def __len__(self): - """ - Used by the len() builtin. - """ - return 36 - - def __nonzero__(self): - return self._bits != "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - - def __str__(self): - uuid_string = self.toString() - return uuid_string - - __repr__ = __str__ - - def __getitem__(self, index): - return str(self)[index] - - def __eq__(self, other): - if isinstance(other, (str, unicode)): - return other == str(self) - return self._bits == getattr(other, '_bits', '') - - def __ne__(self, other): - return not self.__eq__(other) - - def __le__(self, other): - return self._bits <= other._bits - - def __ge__(self, other): - return self._bits >= other._bits - - def __lt__(self, other): - return self._bits < other._bits - - def __gt__(self, other): - return self._bits > other._bits - - def __hash__(self): - return hash(self._bits) - - def set(self, uuid): - self._bits = uuid._bits - - def setFromString(self, uuid_string): - """ - Given a string version of a uuid, set self bits - appropriately. Returns self. - """ - s = string.replace(uuid_string, '-', '') - self._bits = _int2binstr(string.atol(s[:8],16),4) + \ - _int2binstr(string.atol(s[8:16],16),4) + \ - _int2binstr(string.atol(s[16:24],16),4) + \ - _int2binstr(string.atol(s[24:],16),4) - return self - - def setFromMemoryDump(self, gdb_string): - """ - We expect to get gdb_string as four hex units. eg: - 0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2 - Which will be translated to: - db547d14-1b3f4bc3-9b984f71-d22f890a - Returns self. - """ - s = string.replace(gdb_string, '0x', '') - s = string.replace(s, ' ', '') - t = '' - for i in range(8,40,8): - for j in range(0,8,2): - t = t + s[i-j-2:i-j] - self.setFromString(t) - - def toString(self): - """ - Return as a string matching the LL standard - AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex) - where A=network address, B=timestamp, C=random. - """ - return uuid_bits_to_string(self._bits) - - def getAsString(self): - """ - Return a different string representation of the form - AAAAAAAA-AAAABBBB-BBBBBBBB-BBCCCCCC (a 128-bit number in hex) - where A=network address, B=timestamp, C=random. - """ - i1 = _binstr2int(self._bits[0:4]) - i2 = _binstr2int(self._bits[4:8]) - i3 = _binstr2int(self._bits[8:12]) - i4 = _binstr2int(self._bits[12:16]) - return '%08lx-%08lx-%08lx-%08lx' % (i1,i2,i3,i4) - - def generate(self): - """ - Generate a new uuid. This algorithm is slightly different - from c++ implementation for portability reasons. - Returns self. - """ - m = md5() - m.update(uuid.uuid1().bytes) - self._bits = m.digest() - return self - - def isNull(self): - """ - Returns 1 if the uuid is null - ie, equal to default uuid. - """ - return (self._bits == "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0") - - def xor(self, rhs): - """ - xors self with rhs. - """ - v1 = _binstr2int(self._bits[0:4]) ^ _binstr2int(rhs._bits[0:4]) - v2 = _binstr2int(self._bits[4:8]) ^ _binstr2int(rhs._bits[4:8]) - v3 = _binstr2int(self._bits[8:12]) ^ _binstr2int(rhs._bits[8:12]) - v4 = _binstr2int(self._bits[12:16]) ^ _binstr2int(rhs._bits[12:16]) - self._bits = _int2binstr(v1,4) + \ - _int2binstr(v2,4) + \ - _int2binstr(v3,4) + \ - _int2binstr(v4,4) - - -# module-level null constant -NULL = UUID() - -def printTranslatedMemory(four_hex_uints): - """ - We expect to get the string as four hex units. eg: - 0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2 - Which will be translated to: - db547d14-1b3f4bc3-9b984f71-d22f890a - """ - uuid = UUID() - uuid.setFromMemoryDump(four_hex_uints) - print uuid.toString() - -def isUUID(id_str): - """ - This function returns: - - 1 if the string passed is a UUID - - 0 is the string passed is not a UUID - - None if it neither of the if's below is satisfied - """ - if not id_str or len(id_str) < 5 or len(id_str) > 36: - return 0 - - if isinstance(id_str, UUID) or UUID.uuid_regex.match(id_str): - return 1 - - return None - -def isPossiblyID(id_str): - """ - This function returns 1 if the string passed has some uuid-like - characteristics. Otherwise returns 0. - """ - - is_uuid = isUUID(id_str) - if is_uuid is not None: - return is_uuid - - # build a string which matches every character. - hex_wildcard = r"[0-9a-fA-F]" - chars = len(id_str) - next = min(chars, 8) - matcher = hex_wildcard+"{"+str(next)+","+str(next)+"}" - chars = chars - next - if chars > 0: - matcher = matcher + "-" - chars = chars - 1 - for block in range(3): - next = max(min(chars, 4), 0) - if next: - matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}" - chars = chars - next - if chars > 0: - matcher = matcher + "-" - chars = chars - 1 - if chars > 0: - next = min(chars, 12) - matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}" - #print matcher - uuid_matcher = re.compile(matcher) - if uuid_matcher.match(id_str): - return 1 - return 0 - -def uuid_bits_to_string(bits): - i1 = _binstr2int(bits[0:4]) - i2 = _binstr2int(bits[4:6]) - i3 = _binstr2int(bits[6:8]) - i4 = _binstr2int(bits[8:10]) - i5 = _binstr2int(bits[10:12]) - i6 = _binstr2int(bits[12:16]) - return '%08lx-%04lx-%04lx-%04lx-%04lx%08lx' % (i1,i2,i3,i4,i5,i6) - -def uuid_bits_to_uuid(bits): - return UUID(uuid_bits_to_string(bits)) - - -try: - from mulib import stacked - stacked.NoProducer() # just to exercise stacked -except: - #print "Couldn't import mulib.stacked, not registering UUID converter" - pass -else: - def convertUUID(uuid, req): - req.write(str(uuid)) - - stacked.add_producer(UUID, convertUUID, "*/*") - stacked.add_producer(UUID, convertUUID, "text/html") diff --git a/indra/lib/python/indra/base/metrics.py b/indra/lib/python/indra/base/metrics.py deleted file mode 100755 index ff8380265f..0000000000 --- a/indra/lib/python/indra/base/metrics.py +++ /dev/null @@ -1,121 +0,0 @@ -"""\ -@file metrics.py -@author Phoenix -@date 2007-11-27 -@brief simple interface for logging metrics - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys -try: - import syslog -except ImportError: - # Windows - import sys - class syslog(object): - # wrap to a lame syslog for windows - _logfp = sys.stderr - def syslog(msg): - _logfp.write(msg) - if not msg.endswith('\n'): - _logfp.write('\n') - syslog = staticmethod(syslog) - -from indra.base.llsd import format_notation - -def record_metrics(table, stats): - "Write a standard metrics log" - _log("LLMETRICS", table, stats) - -def record_event(table, data): - "Write a standard logmessage log" - _log("LLLOGMESSAGE", table, data) - -def set_destination(dest): - """Set the destination of metrics logs for this process. - - If you do not call this function prior to calling a logging - method, that function will open sys.stdout as a destination. - Attempts to set dest to None will throw a RuntimeError. - @param dest a file-like object which will be the destination for logs.""" - if dest is None: - raise RuntimeError("Attempt to unset metrics destination.") - global _destination - _destination = dest - -def destination(): - """Get the destination of the metrics logs for this process. - Returns None if no destination is set""" - global _destination - return _destination - -class SysLogger(object): - "A file-like object which writes to syslog." - def __init__(self, ident='indra', logopt = None, facility = None): - try: - if logopt is None: - logopt = syslog.LOG_CONS | syslog.LOG_PID - if facility is None: - facility = syslog.LOG_LOCAL0 - syslog.openlog(ident, logopt, facility) - import atexit - atexit.register(syslog.closelog) - except AttributeError: - # No syslog module on Windows - pass - - def write(str): - syslog.syslog(str) - write = staticmethod(write) - - def flush(): - pass - flush = staticmethod(flush) - -# -# internal API -# -_sequence_id = 0 -_destination = None - -def _next_id(): - global _sequence_id - next = _sequence_id - _sequence_id += 1 - return next - -def _dest(): - global _destination - if _destination is None: - # this default behavior is documented in the metrics functions above. - _destination = sys.stdout - return _destination - -def _log(header, table, data): - log_line = "%s (%d) %s %s" \ - % (header, _next_id(), table, format_notation(data)) - dest = _dest() - dest.write(log_line) - dest.flush() diff --git a/indra/lib/python/indra/ipc/httputil.py b/indra/lib/python/indra/ipc/httputil.py deleted file mode 100755 index d53f34a771..0000000000 --- a/indra/lib/python/indra/ipc/httputil.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/python -## $LicenseInfo:firstyear=2011&license=viewerlgpl$ -## Second Life Viewer Source Code -## Copyright (C) 2011, Linden Research, Inc. -## -## This library is free software; you can redistribute it and/or -## modify it under the terms of the GNU Lesser General Public -## License as published by the Free Software Foundation; -## version 2.1 of the License only. -## -## This library is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## Lesser General Public License for more details. -## -## You should have received a copy of the GNU Lesser General Public -## License along with this library; if not, write to the Free Software -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -## -## Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -## $/LicenseInfo$ - -import warnings - -warnings.warn("indra.ipc.httputil has been deprecated; use eventlet.httpc instead", DeprecationWarning, 2) - -from eventlet.httpc import * - - -makeConnection = make_connection diff --git a/indra/lib/python/indra/ipc/llsdhttp.py b/indra/lib/python/indra/ipc/llsdhttp.py deleted file mode 100755 index cbe8ee1eca..0000000000 --- a/indra/lib/python/indra/ipc/llsdhttp.py +++ /dev/null @@ -1,100 +0,0 @@ -"""\ -@file llsdhttp.py -@brief Functions to ease moving llsd over http - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import os.path -import os -import urlparse - -from indra.base import llsd - -from eventlet import httpc - -suite = httpc.HttpSuite(llsd.format_xml, llsd.parse, 'application/llsd+xml') -delete = suite.delete -delete_ = suite.delete_ -get = suite.get -get_ = suite.get_ -head = suite.head -head_ = suite.head_ -post = suite.post -post_ = suite.post_ -put = suite.put -put_ = suite.put_ -request = suite.request -request_ = suite.request_ - -# import every httpc error exception into our namespace for convenience -for x in httpc.status_to_error_map.itervalues(): - globals()[x.__name__] = x -ConnectionError = httpc.ConnectionError -Retriable = httpc.Retriable - -for x in (httpc.ConnectionError,): - globals()[x.__name__] = x - - -def postFile(url, filename): - f = open(filename) - body = f.read() - f.close() - llsd_body = llsd.parse(body) - return post_(url, llsd_body) - - -# deprecated in favor of get_ -def getStatus(url, use_proxy=False): - status, _headers, _body = get_(url, use_proxy=use_proxy) - return status - -# deprecated in favor of put_ -def putStatus(url, data): - status, _headers, _body = put_(url, data) - return status - -# deprecated in favor of delete_ -def deleteStatus(url): - status, _headers, _body = delete_(url) - return status - -# deprecated in favor of post_ -def postStatus(url, data): - status, _headers, _body = post_(url, data) - return status - - -def postFileStatus(url, filename): - status, _headers, body = postFile(url, filename) - return status, body - - -def getFromSimulator(path, use_proxy=False): - return get('http://' + simulatorHostAndPort + path, use_proxy=use_proxy) - - -def postToSimulator(path, data=None): - return post('http://' + simulatorHostAndPort + path, data) diff --git a/indra/lib/python/indra/ipc/mysql_pool.py b/indra/lib/python/indra/ipc/mysql_pool.py deleted file mode 100755 index e5855a3091..0000000000 --- a/indra/lib/python/indra/ipc/mysql_pool.py +++ /dev/null @@ -1,81 +0,0 @@ -"""\ -@file mysql_pool.py -@brief Thin wrapper around eventlet.db_pool that chooses MySQLdb and Tpool. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import MySQLdb -from eventlet import db_pool - -class DatabaseConnector(db_pool.DatabaseConnector): - def __init__(self, credentials, *args, **kwargs): - super(DatabaseConnector, self).__init__(MySQLdb, credentials, - conn_pool=db_pool.ConnectionPool, - *args, **kwargs) - - # get is extended relative to eventlet.db_pool to accept a port argument - def get(self, host, dbname, port=3306): - key = (host, dbname, port) - if key not in self._databases: - new_kwargs = self._kwargs.copy() - new_kwargs['db'] = dbname - new_kwargs['host'] = host - new_kwargs['port'] = port - new_kwargs.update(self.credentials_for(host)) - dbpool = ConnectionPool(*self._args, **new_kwargs) - self._databases[key] = dbpool - - return self._databases[key] - -class ConnectionPool(db_pool.TpooledConnectionPool): - """A pool which gives out saranwrapped MySQLdb connections from a pool - """ - - def __init__(self, *args, **kwargs): - super(ConnectionPool, self).__init__(MySQLdb, *args, **kwargs) - - def get(self): - conn = super(ConnectionPool, self).get() - # annotate the connection object with the details on the - # connection; this is used elsewhere to check that you haven't - # suddenly changed databases in midstream while making a - # series of queries on a connection. - arg_names = ['host','user','passwd','db','port','unix_socket','conv','connect_timeout', - 'compress', 'named_pipe', 'init_command', 'read_default_file', 'read_default_group', - 'cursorclass', 'use_unicode', 'charset', 'sql_mode', 'client_flag', 'ssl', - 'local_infile'] - # you could have constructed this connectionpool with a mix of - # keyword and non-keyword arguments, but we want to annotate - # the connection object with a dict so it's easy to check - # against so here we are converting the list of non-keyword - # arguments (in self._args) into a dict of keyword arguments, - # and merging that with the actual keyword arguments - # (self._kwargs). The arg_names variable lists the - # constructor arguments for MySQLdb Connection objects. - converted_kwargs = dict([ (arg_names[i], arg) for i, arg in enumerate(self._args) ]) - converted_kwargs.update(self._kwargs) - conn.connection_parameters = converted_kwargs - return conn - diff --git a/indra/lib/python/indra/ipc/russ.py b/indra/lib/python/indra/ipc/russ.py deleted file mode 100755 index ac780f128b..0000000000 --- a/indra/lib/python/indra/ipc/russ.py +++ /dev/null @@ -1,165 +0,0 @@ -"""\ -@file russ.py -@brief Recursive URL Substitution Syntax helpers -@author Phoenix - -Many details on how this should work is available on the wiki: -https://wiki.secondlife.com/wiki/Recursive_URL_Substitution_Syntax - -Adding features to this should be reflected in that page in the -implementations section. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import urllib -from indra.ipc import llsdhttp - -class UnbalancedBraces(Exception): - pass - -class UnknownDirective(Exception): - pass - -class BadDirective(Exception): - pass - -def format_value_for_path(value): - if type(value) in [list, tuple]: - # *NOTE: treat lists as unquoted path components so that the quoting - # doesn't get out-of-hand. This is a workaround for the fact that - # russ always quotes, even if the data it's given is already quoted, - # and it's not safe to simply unquote a path directly, so if we want - # russ to substitute urls parts inside other url parts we always - # have to do so via lists of unquoted path components. - return '/'.join([urllib.quote(str(item)) for item in value]) - else: - return urllib.quote(str(value)) - -def format(format_str, context): - """@brief Format format string according to rules for RUSS. -@see https://osiris.lindenlab.com/mediawiki/index.php/Recursive_URL_Substitution_Syntax -@param format_str The input string to format. -@param context A map used for string substitutions. -@return Returns the formatted string. If no match, the braces remain intact. -""" - while True: - #print "format_str:", format_str - all_matches = _find_sub_matches(format_str) - if not all_matches: - break - substitutions = 0 - while True: - matches = all_matches.pop() - # we work from right to left to make sure we do not - # invalidate positions earlier in format_str - matches.reverse() - for pos in matches: - # Use index since _find_sub_matches should have raised - # an exception, and failure to find now is an exception. - end = format_str.index('}', pos) - #print "directive:", format_str[pos+1:pos+5] - if format_str[pos + 1] == '$': - value = context[format_str[pos + 2:end]] - if value is not None: - value = format_value_for_path(value) - elif format_str[pos + 1] == '%': - value = _build_query_string( - context.get(format_str[pos + 2:end])) - elif format_str[pos+1:pos+5] == 'http' or format_str[pos+1:pos+5] == 'file': - value = _fetch_url_directive(format_str[pos + 1:end]) - else: - raise UnknownDirective, format_str[pos:end + 1] - if value is not None: - format_str = format_str[:pos]+str(value)+format_str[end+1:] - substitutions += 1 - - # If there were any substitutions at this depth, re-parse - # since this may have revealed new things to substitute - if substitutions: - break - if not all_matches: - break - - # If there were no substitutions at all, and we have exhausted - # the possible matches, bail. - if not substitutions: - break - return format_str - -def _find_sub_matches(format_str): - """@brief Find all of the substitution matches. -@param format_str the RUSS conformant format string. -@return Returns an array of depths of arrays of positional matches in input. -""" - depth = 0 - matches = [] - for pos in range(len(format_str)): - if format_str[pos] == '{': - depth += 1 - if not len(matches) == depth: - matches.append([]) - matches[depth - 1].append(pos) - continue - if format_str[pos] == '}': - depth -= 1 - continue - if not depth == 0: - raise UnbalancedBraces, format_str - return matches - -def _build_query_string(query_dict): - """\ - @breif given a dict, return a query string. utility wrapper for urllib. - @param query_dict input query dict - @returns Returns an urlencoded query string including leading '?'. - """ - if query_dict: - keys = query_dict.keys() - keys.sort() - def stringize(value): - if type(value) in (str,unicode): - return value - else: - return str(value) - query_list = [urllib.quote(str(key)) + '=' + urllib.quote(stringize(query_dict[key])) for key in keys] - return '?' + '&'.join(query_list) - else: - return '' - -def _fetch_url_directive(directive): - "*FIX: This only supports GET" - commands = directive.split('|') - resource = llsdhttp.get(commands[0]) - if len(commands) == 3: - resource = _walk_resource(resource, commands[2]) - return resource - -def _walk_resource(resource, path): - path = path.split('/') - for child in path: - if not child: - continue - resource = resource[child] - return resource diff --git a/indra/lib/python/indra/ipc/servicebuilder.py b/indra/lib/python/indra/ipc/servicebuilder.py deleted file mode 100755 index 0a0ce2b4e2..0000000000 --- a/indra/lib/python/indra/ipc/servicebuilder.py +++ /dev/null @@ -1,134 +0,0 @@ -"""\ -@file servicebuilder.py -@author Phoenix -@brief Class which will generate service urls. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -from indra.base import config -from indra.ipc import llsdhttp -from indra.ipc import russ - -# *NOTE: agent presence relies on this variable existing and being current, it is a huge hack -services_config = {} -try: - services_config = llsdhttp.get(config.get('services-config')) -except: - pass - -_g_builder = None -def _builder(): - global _g_builder - if _g_builder is None: - _g_builder = ServiceBuilder() - return _g_builder - -def build(name, context={}, **kwargs): - """ Convenience method for using a global, singleton, service builder. Pass arguments either via a dict or via python keyword arguments, or both! - - Example use: - > context = {'channel':'Second Life Release', 'version':'1.18.2.0'} - > servicebuilder.build('version-manager-version', context) - 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0' - > servicebuilder.build('version-manager-version', channel='Second Life Release', version='1.18.2.0') - 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0' - > servicebuilder.build('version-manager-version', context, version='1.18.1.2') - 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.1.2' - """ - global _g_builder - if _g_builder is None: - _g_builder = ServiceBuilder() - return _g_builder.buildServiceURL(name, context, **kwargs) - -def build_path(name, context={}, **kwargs): - context = context.copy() # shouldn't modify the caller's dictionary - context.update(kwargs) - return _builder().buildPath(name, context) - -class ServiceBuilder(object): - def __init__(self, services_definition = services_config): - """\ - @brief - @brief Create a ServiceBuilder. - @param services_definition Complete services definition, services.xml. - """ - # no need to keep a copy of the services section of the - # complete services definition, but it doesn't hurt much. - self.services = services_definition['services'] - self.builders = {} - for service in self.services: - service_builder = service.get('service-builder') - if not service_builder: - continue - if isinstance(service_builder, dict): - # We will be constructing several builders - for name, builder in service_builder.iteritems(): - full_builder_name = service['name'] + '-' + name - self.builders[full_builder_name] = builder - else: - self.builders[service['name']] = service_builder - - def buildPath(self, name, context): - """\ - @brief given the environment on construction, return a service path. - @param name The name of the service. - @param context A dict of name value lookups for the service. - @returns Returns the - """ - return russ.format(self.builders[name], context) - - def buildServiceURL(self, name, context={}, **kwargs): - """\ - @brief given the environment on construction, return a service URL. - @param name The name of the service. - @param context A dict of name value lookups for the service. - @param kwargs Any keyword arguments are treated as members of the - context, this allows you to be all 31337 by writing shit like: - servicebuilder.build('name', param=value) - @returns Returns the - """ - context = context.copy() # shouldn't modify the caller's dictionary - context.update(kwargs) - base_url = config.get('services-base-url') - svc_path = russ.format(self.builders[name], context) - return base_url + svc_path - - -def on_in(query_name, host_key, schema_key): - """\ - @brief Constructs an on/in snippet (for running named queries) - from a schema name and two keys referencing values stored in - indra.xml. - - @param query_name Name of the query. - @param host_key Logical name of destination host. Will be - looked up in indra.xml. - @param schema_key Logical name of destination schema. Will - be looked up in indra.xml. - """ - return "on/config:%s/in/config:%s/%s" % (host_key.strip('/'), - schema_key.strip('/'), - query_name.lstrip('/')) - diff --git a/indra/lib/python/indra/ipc/siesta.py b/indra/lib/python/indra/ipc/siesta.py deleted file mode 100755 index d867e71537..0000000000 --- a/indra/lib/python/indra/ipc/siesta.py +++ /dev/null @@ -1,468 +0,0 @@ -"""\ -@file siesta.py -@brief A tiny llsd based RESTful web services framework - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -from indra.base import config -from indra.base import llsd -from webob import exc -import webob -import re, socket - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -try: - import cjson - json_decode = cjson.decode - json_encode = cjson.encode - JsonDecodeError = cjson.DecodeError - JsonEncodeError = cjson.EncodeError -except ImportError: - import simplejson - json_decode = simplejson.loads - json_encode = simplejson.dumps - JsonDecodeError = ValueError - JsonEncodeError = TypeError - - -llsd_parsers = { - 'application/json': json_decode, - llsd.BINARY_MIME_TYPE: llsd.parse_binary, - 'application/llsd+notation': llsd.parse_notation, - llsd.XML_MIME_TYPE: llsd.parse_xml, - 'application/xml': llsd.parse_xml, - } - - -def mime_type(content_type): - '''Given a Content-Type header, return only the MIME type.''' - - return content_type.split(';', 1)[0].strip().lower() - -class BodyLLSD(object): - '''Give a webob Request or Response an llsd based "content" property. - - Getting the content property parses the body, and caches the result. - - Setting the content property formats a payload, and the body property - is set.''' - - def _llsd__get(self): - '''Get, set, or delete the LLSD value stored in this object.''' - - try: - return self._llsd - except AttributeError: - if not self.body: - raise AttributeError('No llsd attribute has been set') - else: - mtype = mime_type(self.content_type) - try: - parser = llsd_parsers[mtype] - except KeyError: - raise exc.HTTPUnsupportedMediaType( - 'Content type %s not supported' % mtype).exception - try: - self._llsd = parser(self.body) - except (llsd.LLSDParseError, JsonDecodeError, TypeError), err: - raise exc.HTTPBadRequest( - 'Could not parse body: %r' % err.args).exception - return self._llsd - - def _llsd__set(self, val): - req = getattr(self, 'request', None) - if req is not None: - formatter, ctype = formatter_for_request(req) - self.content_type = ctype - else: - formatter, ctype = formatter_for_mime_type( - mime_type(self.content_type)) - self.body = formatter(val) - - def _llsd__del(self): - if hasattr(self, '_llsd'): - del self._llsd - - content = property(_llsd__get, _llsd__set, _llsd__del) - - -class Response(webob.Response, BodyLLSD): - '''Response class with LLSD support. - - A sensible default content type is used. - - Setting the llsd property also sets the body. Getting the llsd - property parses the body if necessary. - - If you set the body property directly, the llsd property will be - deleted.''' - - default_content_type = 'application/llsd+xml' - - def _body__set(self, body): - if hasattr(self, '_llsd'): - del self._llsd - super(Response, self)._body__set(body) - - def cache_forever(self): - self.cache_expires(86400 * 365) - - body = property(webob.Response._body__get, _body__set, - webob.Response._body__del, - webob.Response._body__get.__doc__) - - -class Request(webob.Request, BodyLLSD): - '''Request class with LLSD support. - - Sensible content type and accept headers are used by default. - - Setting the content property also sets the body. Getting the content - property parses the body if necessary. - - If you set the body property directly, the content property will be - deleted.''' - - default_content_type = 'application/llsd+xml' - default_accept = ('application/llsd+xml; q=0.5, ' - 'application/llsd+notation; q=0.3, ' - 'application/llsd+binary; q=0.2, ' - 'application/xml; q=0.1, ' - 'application/json; q=0.0') - - def __init__(self, environ=None, *args, **kwargs): - if environ is None: - environ = {} - else: - environ = environ.copy() - if 'CONTENT_TYPE' not in environ: - environ['CONTENT_TYPE'] = self.default_content_type - if 'HTTP_ACCEPT' not in environ: - environ['HTTP_ACCEPT'] = self.default_accept - super(Request, self).__init__(environ, *args, **kwargs) - - def _body__set(self, body): - if hasattr(self, '_llsd'): - del self._llsd - super(Request, self)._body__set(body) - - def path_urljoin(self, *parts): - return '/'.join([path_url.rstrip('/')] + list(parts)) - - body = property(webob.Request._body__get, _body__set, - webob.Request._body__del, webob.Request._body__get.__doc__) - - def create_response(self, content=None, status='200 OK', - conditional_response=webob.NoDefault): - resp = self.ResponseClass(status=status, request=self, - conditional_response=conditional_response) - resp.content = content - return resp - - def curl(self): - '''Create and fill out a pycurl easy object from this request.''' - - import pycurl - c = pycurl.Curl() - c.setopt(pycurl.URL, self.url()) - if self.headers: - c.setopt(pycurl.HTTPHEADER, - ['%s: %s' % (k, self.headers[k]) for k in self.headers]) - c.setopt(pycurl.FOLLOWLOCATION, True) - c.setopt(pycurl.AUTOREFERER, True) - c.setopt(pycurl.MAXREDIRS, 16) - c.setopt(pycurl.NOSIGNAL, True) - c.setopt(pycurl.READFUNCTION, self.body_file.read) - c.setopt(pycurl.SSL_VERIFYHOST, 2) - - if self.method == 'POST': - c.setopt(pycurl.POST, True) - post301 = getattr(pycurl, 'POST301', None) - if post301 is not None: - # Added in libcurl 7.17.1. - c.setopt(post301, True) - elif self.method == 'PUT': - c.setopt(pycurl.PUT, True) - elif self.method != 'GET': - c.setopt(pycurl.CUSTOMREQUEST, self.method) - return c - -Request.ResponseClass = Response -Response.RequestClass = Request - - -llsd_formatters = { - 'application/json': json_encode, - 'application/llsd+binary': llsd.format_binary, - 'application/llsd+notation': llsd.format_notation, - 'application/llsd+xml': llsd.format_xml, - 'application/xml': llsd.format_xml, - } - -formatter_qualities = ( - ('application/llsd+xml', 1.0), - ('application/llsd+notation', 0.5), - ('application/llsd+binary', 0.4), - ('application/xml', 0.3), - ('application/json', 0.2), - ) - -def formatter_for_mime_type(mime_type): - '''Return a formatter that encodes to the given MIME type. - - The result is a pair of function and MIME type.''' - try: - return llsd_formatters[mime_type], mime_type - except KeyError: - raise exc.HTTPInternalServerError( - 'Could not use MIME type %r to format response' % - mime_type).exception - - -def formatter_for_request(req): - '''Return a formatter that encodes to the preferred type of the client. - - The result is a pair of function and actual MIME type.''' - ctype = req.accept.best_match(formatter_qualities) - try: - return llsd_formatters[ctype], ctype - except KeyError: - raise exc.HTTPNotAcceptable().exception - - -def wsgi_adapter(func, environ, start_response): - '''Adapt a Siesta callable to act as a WSGI application.''' - # Process the request as appropriate. - try: - req = Request(environ) - #print req.urlvars - resp = func(req, **req.urlvars) - if not isinstance(resp, webob.Response): - try: - formatter, ctype = formatter_for_request(req) - resp = req.ResponseClass(formatter(resp), content_type=ctype) - resp._llsd = resp - except (JsonEncodeError, TypeError), err: - resp = exc.HTTPInternalServerError( - detail='Could not format response') - except exc.HTTPException, e: - resp = e - except socket.error, e: - resp = exc.HTTPInternalServerError(detail=e.args[1]) - return resp(environ, start_response) - - -def llsd_callable(func): - '''Turn a callable into a Siesta application.''' - - def replacement(environ, start_response): - return wsgi_adapter(func, environ, start_response) - - return replacement - - -def llsd_method(http_method, func): - def replacement(environ, start_response): - if environ['REQUEST_METHOD'] == http_method: - return wsgi_adapter(func, environ, start_response) - return exc.HTTPMethodNotAllowed()(environ, start_response) - - return replacement - - -http11_methods = 'OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT'.split() -http11_methods.sort() - -def llsd_class(cls): - '''Turn a class into a Siesta application. - - A new instance is created for each request. A HTTP method FOO is - turned into a call to the handle_foo method of the instance.''' - - def foo(req, **kwargs): - instance = cls() - method = req.method.lower() - try: - handler = getattr(instance, 'handle_' + method) - except AttributeError: - allowed = [m for m in http11_methods - if hasattr(instance, 'handle_' + m.lower())] - raise exc.HTTPMethodNotAllowed( - headers={'Allow': ', '.join(allowed)}).exception - #print "kwargs: ", kwargs - return handler(req, **kwargs) - - def replacement(environ, start_response): - return wsgi_adapter(foo, environ, start_response) - - return replacement - - -def curl(reqs): - import pycurl - - m = pycurl.CurlMulti() - curls = [r.curl() for r in reqs] - io = {} - for c in curls: - fp = StringIO() - hdr = StringIO() - c.setopt(pycurl.WRITEFUNCTION, fp.write) - c.setopt(pycurl.HEADERFUNCTION, hdr.write) - io[id(c)] = fp, hdr - m.handles = curls - try: - while True: - ret, num_handles = m.perform() - if ret != pycurl.E_CALL_MULTI_PERFORM: - break - finally: - m.close() - - for req, c in zip(reqs, curls): - fp, hdr = io[id(c)] - hdr.seek(0) - status = hdr.readline().rstrip() - headers = [] - name, values = None, None - - # XXX We don't currently handle bogus header data. - - for line in hdr.readlines(): - if not line[0].isspace(): - if name: - headers.append((name, ' '.join(values))) - name, value = line.strip().split(':', 1) - value = [value] - else: - values.append(line.strip()) - if name: - headers.append((name, ' '.join(values))) - - resp = c.ResponseClass(fp.getvalue(), status, headers, request=req) - - -route_re = re.compile(r''' - \{ # exact character "{" - (\w*) # "config" or variable (restricted to a-z, 0-9, _) - (?:([:~])([^}]+))? # optional :type or ~regex part - \} # exact character "}" - ''', re.VERBOSE) - -predefined_regexps = { - 'uuid': r'[a-f0-9][a-f0-9-]{31,35}', - 'int': r'\d+', - 'host': r'[a-z0-9][a-z0-9\-\.]*', - } - -def compile_route(route): - fp = StringIO() - last_pos = 0 - for match in route_re.finditer(route): - #print "matches: ", match.groups() - fp.write(re.escape(route[last_pos:match.start()])) - var_name = match.group(1) - sep = match.group(2) - expr = match.group(3) - if var_name == 'config': - expr = re.escape(str(config.get(var_name))) - else: - if expr: - if sep == ':': - expr = predefined_regexps[expr] - # otherwise, treat what follows '~' as a regexp - else: - expr = '[^/]+' - if var_name != '': - expr = '(?P<%s>%s)' % (var_name, expr) - else: - expr = '(%s)' % (expr,) - fp.write(expr) - last_pos = match.end() - fp.write(re.escape(route[last_pos:])) - compiled_route = '^%s$' % fp.getvalue() - #print route, "->", compiled_route - return compiled_route - -class Router(object): - '''WSGI routing class. Parses a URL and hands off a request to - some other WSGI application. If no suitable application is found, - responds with a 404.''' - - def __init__(self): - self._new_routes = [] - self._routes = [] - self._paths = [] - - def add(self, route, app, methods=None): - self._new_routes.append((route, app, methods)) - - def _create_routes(self): - for route, app, methods in self._new_routes: - self._paths.append(route) - self._routes.append( - (re.compile(compile_route(route)), - app, - methods and dict.fromkeys(methods))) - self._new_routes = [] - - def __call__(self, environ, start_response): - # load up the config from the config file. Only needs to be - # done once per interpreter. This is the entry point of all - # siesta applications, so this is where we trap it. - _conf = config.get_config() - if _conf is None: - import os.path - fname = os.path.join( - environ.get('ll.config_dir', '/local/linden/etc'), - 'indra.xml') - config.load(fname) - - # proceed with handling the request - self._create_routes() - path_info = environ['PATH_INFO'] - request_method = environ['REQUEST_METHOD'] - allowed = [] - for regex, app, methods in self._routes: - m = regex.match(path_info) - if m: - #print "groupdict:",m.groupdict() - if not methods or request_method in methods: - environ['paste.urlvars'] = m.groupdict() - return app(environ, start_response) - else: - allowed += methods - if allowed: - allowed = dict.fromkeys(allows).keys() - allowed.sort() - resp = exc.HTTPMethodNotAllowed( - headers={'Allow': ', '.join(allowed)}) - else: - resp = exc.HTTPNotFound() - return resp(environ, start_response) diff --git a/indra/lib/python/indra/ipc/siesta_test.py b/indra/lib/python/indra/ipc/siesta_test.py deleted file mode 100755 index a35eed2460..0000000000 --- a/indra/lib/python/indra/ipc/siesta_test.py +++ /dev/null @@ -1,235 +0,0 @@ -#!/usr/bin/python -## $LicenseInfo:firstyear=2011&license=viewerlgpl$ -## Second Life Viewer Source Code -## Copyright (C) 2011, Linden Research, Inc. -## -## This library is free software; you can redistribute it and/or -## modify it under the terms of the GNU Lesser General Public -## License as published by the Free Software Foundation; -## version 2.1 of the License only. -## -## This library is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## Lesser General Public License for more details. -## -## You should have received a copy of the GNU Lesser General Public -## License along with this library; if not, write to the Free Software -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -## -## Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -## $/LicenseInfo$ -from indra.base import llsd, lluuid -from indra.ipc import siesta -import datetime, math, unittest -from webob import exc - - -class ClassApp(object): - def handle_get(self, req): - pass - - def handle_post(self, req): - return req.llsd - - -def callable_app(req): - if req.method == 'UNDERPANTS': - raise exc.HTTPMethodNotAllowed() - elif req.method == 'GET': - return None - return req.llsd - - -class TestBase: - def test_basic_get(self): - req = siesta.Request.blank('/') - self.assertEquals(req.get_response(self.server).body, - llsd.format_xml(None)) - - def test_bad_method(self): - req = siesta.Request.blank('/') - req.environ['REQUEST_METHOD'] = 'UNDERPANTS' - self.assertEquals(req.get_response(self.server).status_int, - exc.HTTPMethodNotAllowed.code) - - json_safe = { - 'none': None, - 'bool_true': True, - 'bool_false': False, - 'int_zero': 0, - 'int_max': 2147483647, - 'int_min': -2147483648, - 'long_zero': 0, - 'long_max': 2147483647L, - 'long_min': -2147483648L, - 'float_zero': 0, - 'float': math.pi, - 'float_huge': 3.14159265358979323846e299, - 'str_empty': '', - 'str': 'foo', - u'unic\u1e51de_empty': u'', - u'unic\u1e51de': u'\u1e4exx\u10480', - } - json_safe['array'] = json_safe.values() - json_safe['tuple'] = tuple(json_safe.values()) - json_safe['dict'] = json_safe.copy() - - json_unsafe = { - 'uuid_empty': lluuid.UUID(), - 'uuid_full': lluuid.UUID('dc61ab0530200d7554d23510559102c1a98aab1b'), - 'binary_empty': llsd.binary(), - 'binary': llsd.binary('f\0\xff'), - 'uri_empty': llsd.uri(), - 'uri': llsd.uri('http://www.secondlife.com/'), - 'datetime_empty': datetime.datetime(1970,1,1), - 'datetime': datetime.datetime(1999,9,9,9,9,9), - } - json_unsafe.update(json_safe) - json_unsafe['array'] = json_unsafe.values() - json_unsafe['tuple'] = tuple(json_unsafe.values()) - json_unsafe['dict'] = json_unsafe.copy() - json_unsafe['iter'] = iter(json_unsafe.values()) - - def _test_client_content_type_good(self, content_type, ll): - def run(ll): - req = siesta.Request.blank('/') - req.environ['REQUEST_METHOD'] = 'POST' - req.content_type = content_type - req.llsd = ll - req.accept = content_type - resp = req.get_response(self.server) - self.assertEquals(resp.status_int, 200) - return req, resp - - if False and isinstance(ll, dict): - def fixup(v): - if isinstance(v, float): - return '%.5f' % v - if isinstance(v, long): - return int(v) - if isinstance(v, (llsd.binary, llsd.uri)): - return v - if isinstance(v, (tuple, list)): - return [fixup(i) for i in v] - if isinstance(v, dict): - return dict([(k, fixup(i)) for k, i in v.iteritems()]) - return v - for k, v in ll.iteritems(): - l = [k, v] - req, resp = run(l) - self.assertEquals(fixup(resp.llsd), fixup(l)) - - run(ll) - - def test_client_content_type_json_good(self): - self._test_client_content_type_good('application/json', self.json_safe) - - def test_client_content_type_llsd_xml_good(self): - self._test_client_content_type_good('application/llsd+xml', - self.json_unsafe) - - def test_client_content_type_llsd_notation_good(self): - self._test_client_content_type_good('application/llsd+notation', - self.json_unsafe) - - def test_client_content_type_llsd_binary_good(self): - self._test_client_content_type_good('application/llsd+binary', - self.json_unsafe) - - def test_client_content_type_xml_good(self): - self._test_client_content_type_good('application/xml', - self.json_unsafe) - - def _test_client_content_type_bad(self, content_type): - req = siesta.Request.blank('/') - req.environ['REQUEST_METHOD'] = 'POST' - req.body = '\0invalid nonsense under all encodings' - req.content_type = content_type - self.assertEquals(req.get_response(self.server).status_int, - exc.HTTPBadRequest.code) - - def test_client_content_type_json_bad(self): - self._test_client_content_type_bad('application/json') - - def test_client_content_type_llsd_xml_bad(self): - self._test_client_content_type_bad('application/llsd+xml') - - def test_client_content_type_llsd_notation_bad(self): - self._test_client_content_type_bad('application/llsd+notation') - - def test_client_content_type_llsd_binary_bad(self): - self._test_client_content_type_bad('application/llsd+binary') - - def test_client_content_type_xml_bad(self): - self._test_client_content_type_bad('application/xml') - - def test_client_content_type_bad(self): - req = siesta.Request.blank('/') - req.environ['REQUEST_METHOD'] = 'POST' - req.body = 'XXX' - req.content_type = 'application/nonsense' - self.assertEquals(req.get_response(self.server).status_int, - exc.HTTPUnsupportedMediaType.code) - - def test_request_default_content_type(self): - req = siesta.Request.blank('/') - self.assertEquals(req.content_type, req.default_content_type) - - def test_request_default_accept(self): - req = siesta.Request.blank('/') - from webob import acceptparse - self.assertEquals(str(req.accept).replace(' ', ''), - req.default_accept.replace(' ', '')) - - def test_request_llsd_auto_body(self): - req = siesta.Request.blank('/') - req.llsd = {'a': 2} - self.assertEquals(req.body, '<?xml version="1.0" ?><llsd><map>' - '<key>a</key><integer>2</integer></map></llsd>') - - def test_request_llsd_mod_body_changes_llsd(self): - req = siesta.Request.blank('/') - req.llsd = {'a': 2} - req.body = '<?xml version="1.0" ?><llsd><integer>1337</integer></llsd>' - self.assertEquals(req.llsd, 1337) - - def test_request_bad_llsd_fails(self): - def crashme(ctype): - def boom(): - class foo(object): pass - req = siesta.Request.blank('/') - req.content_type = ctype - req.llsd = foo() - for mime_type in siesta.llsd_parsers: - self.assertRaises(TypeError, crashme(mime_type)) - - -class ClassServer(TestBase, unittest.TestCase): - def __init__(self, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - self.server = siesta.llsd_class(ClassApp) - - -class CallableServer(TestBase, unittest.TestCase): - def __init__(self, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - self.server = siesta.llsd_callable(callable_app) - - -class RouterServer(unittest.TestCase): - def test_router(self): - def foo(req, quux): - print quux - - r = siesta.Router() - r.add('/foo/{quux:int}', siesta.llsd_callable(foo), methods=['GET']) - req = siesta.Request.blank('/foo/33') - req.get_response(r) - - req = siesta.Request.blank('/foo/bar') - self.assertEquals(req.get_response(r).status_int, - exc.HTTPNotFound.code) - -if __name__ == '__main__': - unittest.main() diff --git a/indra/lib/python/indra/ipc/webdav.py b/indra/lib/python/indra/ipc/webdav.py deleted file mode 100755 index 98b8499b6a..0000000000 --- a/indra/lib/python/indra/ipc/webdav.py +++ /dev/null @@ -1,597 +0,0 @@ -""" -@file webdav.py -@brief Classes to make manipulation of a webdav store easier. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys, os, httplib, urlparse -import socket, time -import xml.dom.minidom -import syslog -# import signal - -__revision__ = '0' - -dav_debug = False - - -# def urlsafe_b64decode (enc): -# return base64.decodestring (enc.replace ('_', '/').replace ('-', '+')) - -# def urlsafe_b64encode (str): -# return base64.encodestring (str).replace ('+', '-').replace ('/', '_') - - -class DAVError (Exception): - """ Base class for exceptions in this module. """ - def __init__ (self, status=0, message='', body='', details=''): - self.status = status - self.message = message - self.body = body - self.details = details - Exception.__init__ (self, '%d:%s:%s%s' % (self.status, self.message, - self.body, self.details)) - - def print_to_stderr (self): - """ print_to_stderr docstring """ - print >> sys.stderr, str (self.status) + ' ' + self.message - print >> sys.stderr, str (self.details) - - -class Timeout (Exception): - """ Timeout docstring """ - def __init__ (self, arg=''): - Exception.__init__ (self, arg) - - -def alarm_handler (signum, frame): - """ alarm_handler docstring """ - raise Timeout ('caught alarm') - - -class WebDAV: - """ WebDAV docstring """ - def __init__ (self, url, proxy=None, retries_before_fail=6): - self.init_url = url - self.init_proxy = proxy - self.retries_before_fail = retries_before_fail - url_parsed = urlparse.urlsplit (url) - - self.top_path = url_parsed[ 2 ] - # make sure top_path has a trailing / - if self.top_path == None or self.top_path == '': - self.top_path = '/' - elif len (self.top_path) > 1 and self.top_path[-1:] != '/': - self.top_path += '/' - - if dav_debug: - syslog.syslog ('new WebDAV %s : %s' % (str (url), str (proxy))) - - if proxy: - proxy_parsed = urlparse.urlsplit (proxy) - self.host_header = url_parsed[ 1 ] - host_and_port = proxy_parsed[ 1 ].split (':') - self.host = host_and_port[ 0 ] - if len (host_and_port) > 1: - self.port = int(host_and_port[ 1 ]) - else: - self.port = 80 - else: # no proxy - host_and_port = url_parsed[ 1 ].split (':') - self.host_header = None - self.host = host_and_port[ 0 ] - if len (host_and_port) > 1: - self.port = int(host_and_port[ 1 ]) - else: - self.port = 80 - - self.connection = False - self.connect () - - - def log (self, msg, depth=0): - """ log docstring """ - if dav_debug and depth == 0: - host = str (self.init_url) - if host == 'http://int.tuco.lindenlab.com:80/asset/': - host = 'tuco' - if host == 'http://harriet.lindenlab.com/asset-keep/': - host = 'harriet/asset-keep' - if host == 'http://harriet.lindenlab.com/asset-flag/': - host = 'harriet/asset-flag' - if host == 'http://harriet.lindenlab.com/asset/': - host = 'harriet/asset' - if host == 'http://ozzy.lindenlab.com/asset/': - host = 'ozzy/asset' - if host == 'http://station11.lindenlab.com:12041/:': - host = 'station11:12041' - proxy = str (self.init_proxy) - if proxy == 'None': - proxy = '' - if proxy == 'http://int.tuco.lindenlab.com:3128/': - proxy = 'tuco' - syslog.syslog ('WebDAV (%s:%s) %s' % (host, proxy, str (msg))) - - - def connect (self): - """ connect docstring """ - self.log ('connect') - self.connection = httplib.HTTPConnection (self.host, self.port) - - def __err (self, response, details): - """ __err docstring """ - raise DAVError (response.status, response.reason, response.read (), - str (self.init_url) + ':' + \ - str (self.init_proxy) + ':' + str (details)) - - def request (self, method, path, body=None, headers=None, - read_all=True, body_hook = None, recurse=0, allow_cache=True): - """ request docstring """ - # self.log ('request %s %s' % (method, path)) - if headers == None: - headers = {} - if not allow_cache: - headers['Pragma'] = 'no-cache' - headers['cache-control'] = 'no-cache' - try: - if method.lower () != 'purge': - if path.startswith ('/'): - path = path[1:] - if self.host_header: # use proxy - headers[ 'host' ] = self.host_header - fullpath = 'http://%s%s%s' % (self.host_header, - self.top_path, path) - else: # no proxy - fullpath = self.top_path + path - else: - fullpath = path - - self.connection.request (method, fullpath, body, headers) - if body_hook: - body_hook () - - # signal.signal (signal.SIGALRM, alarm_handler) - # try: - # signal.alarm (120) - # signal.alarm (0) - # except Timeout, e: - # if recurse < 6: - # return self.retry_request (method, path, body, headers, - # read_all, body_hook, recurse) - # else: - # raise DAVError (0, 'timeout', self.host, - # (method, path, body, headers, recurse)) - - response = self.connection.getresponse () - - if read_all: - while len (response.read (1024)) > 0: - pass - if (response.status == 500 or \ - response.status == 503 or \ - response.status == 403) and \ - recurse < self.retries_before_fail: - return self.retry_request (method, path, body, headers, - read_all, body_hook, recurse) - return response - except (httplib.ResponseNotReady, - httplib.BadStatusLine, - socket.error): - # if the server hangs up on us (keepalive off, broken pipe), - # we need to reconnect and try again. - if recurse < self.retries_before_fail: - return self.retry_request (method, path, body, headers, - read_all, body_hook, recurse) - raise DAVError (0, 'reconnect failed', self.host, - (method, path, body, headers, recurse)) - - - def retry_request (self, method, path, body, headers, - read_all, body_hook, recurse): - """ retry_request docstring """ - time.sleep (10.0 * recurse) - self.connect () - return self.request (method, path, body, headers, - read_all, body_hook, recurse+1) - - - - def propfind (self, path, body=None, depth=1): - """ propfind docstring """ - # self.log ('propfind %s' % path) - headers = {'Content-Type':'text/xml; charset="utf-8"', - 'Depth':str(depth)} - response = self.request ('PROPFIND', path, body, headers, False) - if response.status == 207: - return response # Multi-Status - self.__err (response, ('PROPFIND', path, body, headers, 0)) - - - def purge (self, path): - """ issue a squid purge command """ - headers = {'Accept':'*/*'} - response = self.request ('PURGE', path, None, headers) - if response.status == 200 or response.status == 404: - # 200 if it was purge, 404 if it wasn't there. - return response - self.__err (response, ('PURGE', path, None, headers)) - - - def get_file_size (self, path): - """ - Use propfind to ask a webdav server what the size of - a file is. If used on a directory (collection) return 0 - """ - self.log ('get_file_size %s' % path) - # "getcontentlength" property - # 8.1.1 Example - Retrieving Named Properties - # http://docs.python.org/lib/module-xml.dom.html - nsurl = 'http://apache.org/dav/props/' - doc = xml.dom.minidom.Document () - propfind_element = doc.createElementNS (nsurl, "D:propfind") - propfind_element.setAttributeNS (nsurl, 'xmlns:D', 'DAV:') - doc.appendChild (propfind_element) - prop_element = doc.createElementNS (nsurl, "D:prop") - propfind_element.appendChild (prop_element) - con_len_element = doc.createElementNS (nsurl, "D:getcontentlength") - prop_element.appendChild (con_len_element) - - response = self.propfind (path, doc.toxml ()) - doc.unlink () - - resp_doc = xml.dom.minidom.parseString (response.read ()) - cln = resp_doc.getElementsByTagNameNS ('DAV:','getcontentlength')[ 0 ] - try: - content_length = int (cln.childNodes[ 0 ].nodeValue) - except IndexError: - return 0 - resp_doc.unlink () - return content_length - - - def file_exists (self, path): - """ - do an http head on the given file. return True if it succeeds - """ - self.log ('file_exists %s' % path) - expect_gzip = path.endswith ('.gz') - response = self.request ('HEAD', path) - got_gzip = response.getheader ('Content-Encoding', '').strip () - if got_gzip.lower () == 'x-gzip' and expect_gzip == False: - # the asset server fakes us out if we ask for the non-gzipped - # version of an asset, but the server has the gzipped version. - return False - return response.status == 200 - - - def mkdir (self, path): - """ mkdir docstring """ - self.log ('mkdir %s' % path) - headers = {} - response = self.request ('MKCOL', path, None, headers) - if response.status == 201: - return # success - if response.status == 405: - return # directory already existed? - self.__err (response, ('MKCOL', path, None, headers, 0)) - - - def delete (self, path): - """ delete docstring """ - self.log ('delete %s' % path) - headers = {'Depth':'infinity'} # collections require infinity - response = self.request ('DELETE', path, None, headers) - if response.status == 204: - return # no content - if response.status == 404: - return # hmm - self.__err (response, ('DELETE', path, None, headers, 0)) - - - def list_directory (self, path, dir_filter=None, allow_cache=True, - minimum_cache_time=False): - """ - Request an http directory listing and parse the filenames out of lines - like: '<LI><A HREF="X"> X</A>'. If a filter function is provided, - only return filenames that the filter returns True for. - - This is sort of grody, but it seems faster than other ways of getting - this information from an isilon. - """ - self.log ('list_directory %s' % path) - - def try_match (lline, before, after): - """ try_match docstring """ - try: - blen = len (before) - asset_start_index = lline.index (before) - asset_end_index = lline.index (after, asset_start_index + blen) - asset = line[ asset_start_index + blen : asset_end_index ] - - if not dir_filter or dir_filter (asset): - return [ asset ] - return [] - except ValueError: - return [] - - if len (path) > 0 and path[-1:] != '/': - path += '/' - - response = self.request ('GET', path, None, {}, False, - allow_cache=allow_cache) - - if allow_cache and minimum_cache_time: # XXX - print response.getheader ('Date') - # s = "2005-12-06T12:13:14" - # from datetime import datetime - # from time import strptime - # datetime(*strptime(s, "%Y-%m-%dT%H:%M:%S")[0:6]) - # datetime.datetime(2005, 12, 6, 12, 13, 14) - - if response.status != 200: - self.__err (response, ('GET', path, None, {}, 0)) - assets = [] - for line in response.read ().split ('\n'): - lline = line.lower () - if lline.find ("parent directory") == -1: - # isilon file - assets += try_match (lline, '<li><a href="', '"> ') - # apache dir - assets += try_match (lline, 'alt="[dir]"> <a href="', '/">') - # apache file - assets += try_match (lline, 'alt="[ ]"> <a href="', '">') - return assets - - - def __tmp_filename (self, path_and_file): - """ __tmp_filename docstring """ - head, tail = os.path.split (path_and_file) - if head != '': - return head + '/.' + tail + '.' + str (os.getpid ()) - else: - return head + '.' + tail + '.' + str (os.getpid ()) - - - def __put__ (self, filesize, body_hook, remotefile): - """ __put__ docstring """ - headers = {'Content-Length' : str (filesize)} - remotefile_tmp = self.__tmp_filename (remotefile) - response = self.request ('PUT', remotefile_tmp, None, - headers, True, body_hook) - if not response.status in (201, 204): # created, no content - self.__err (response, ('PUT', remotefile, None, headers, 0)) - if filesize != self.get_file_size (remotefile_tmp): - try: - self.delete (remotefile_tmp) - except: - pass - raise DAVError (0, 'tmp upload error', remotefile_tmp) - # move the file to its final location - try: - self.rename (remotefile_tmp, remotefile) - except DAVError, exc: - if exc.status == 403: # try to clean up the tmp file - try: - self.delete (remotefile_tmp) - except: - pass - raise - if filesize != self.get_file_size (remotefile): - raise DAVError (0, 'file upload error', str (remotefile_tmp)) - - - def put_string (self, strng, remotefile): - """ put_string docstring """ - self.log ('put_string %d -> %s' % (len (strng), remotefile)) - filesize = len (strng) - def body_hook (): - """ body_hook docstring """ - self.connection.send (strng) - self.__put__ (filesize, body_hook, remotefile) - - - def put_file (self, localfile, remotefile): - """ - Send a local file to a remote webdav store. First, upload to - a temporary filename. Next make sure the file is the size we - expected. Next, move the file to its final location. Next, - check the file size at the final location. - """ - self.log ('put_file %s -> %s' % (localfile, remotefile)) - filesize = os.path.getsize (localfile) - def body_hook (): - """ body_hook docstring """ - handle = open (localfile) - while True: - data = handle.read (1300) - if len (data) == 0: - break - self.connection.send (data) - handle.close () - self.__put__ (filesize, body_hook, remotefile) - - - def create_empty_file (self, remotefile): - """ create an empty file """ - self.log ('touch_file %s' % (remotefile)) - headers = {'Content-Length' : '0'} - response = self.request ('PUT', remotefile, None, headers) - if not response.status in (201, 204): # created, no content - self.__err (response, ('PUT', remotefile, None, headers, 0)) - if self.get_file_size (remotefile) != 0: - raise DAVError (0, 'file upload error', str (remotefile)) - - - def __get_file_setup (self, remotefile, check_size=True): - """ __get_file_setup docstring """ - if check_size: - remotesize = self.get_file_size (remotefile) - response = self.request ('GET', remotefile, None, {}, False) - if response.status != 200: - self.__err (response, ('GET', remotefile, None, {}, 0)) - try: - content_length = int (response.getheader ("Content-Length")) - except TypeError: - content_length = None - if check_size: - if content_length != remotesize: - raise DAVError (0, 'file DL size error', remotefile) - return (response, content_length) - - - def __get_file_read (self, writehandle, response, content_length): - """ __get_file_read docstring """ - if content_length != None: - so_far_length = 0 - while so_far_length < content_length: - data = response.read (content_length - so_far_length) - if len (data) == 0: - raise DAVError (0, 'short file download') - so_far_length += len (data) - writehandle.write (data) - while len (response.read ()) > 0: - pass - else: - while True: - data = response.read () - if (len (data) < 1): - break - writehandle.write (data) - - - def get_file (self, remotefile, localfile, check_size=True): - """ - Get a remote file from a webdav server. Download to a local - tmp file, then move into place. Sanity check file sizes as - we go. - """ - self.log ('get_file %s -> %s' % (remotefile, localfile)) - (response, content_length) = \ - self.__get_file_setup (remotefile, check_size) - localfile_tmp = self.__tmp_filename (localfile) - handle = open (localfile_tmp, 'w') - self.__get_file_read (handle, response, content_length) - handle.close () - if check_size: - if content_length != os.path.getsize (localfile_tmp): - raise DAVError (0, 'file DL size error', - remotefile+','+localfile) - os.rename (localfile_tmp, localfile) - - - def get_file_as_string (self, remotefile, check_size=True): - """ - download a file from a webdav server and return it as a string. - """ - self.log ('get_file_as_string %s' % remotefile) - (response, content_length) = \ - self.__get_file_setup (remotefile, check_size) - # (tmp_handle, tmp_filename) = tempfile.mkstemp () - tmp_handle = os.tmpfile () - self.__get_file_read (tmp_handle, response, content_length) - tmp_handle.seek (0) - ret = tmp_handle.read () - tmp_handle.close () - # os.unlink (tmp_filename) - return ret - - - def get_post_as_string (self, remotefile, body): - """ - Do an http POST, send body, get response and return it. - """ - self.log ('get_post_as_string %s' % remotefile) - # headers = {'Content-Type':'application/x-www-form-urlencoded'} - headers = {'Content-Type':'text/xml; charset="utf-8"'} - # b64body = urlsafe_b64encode (asset_url) - response = self.request ('POST', remotefile, body, headers, False) - if response.status != 200: - self.__err (response, ('POST', remotefile, body, headers, 0)) - try: - content_length = int (response.getheader ('Content-Length')) - except TypeError: - content_length = None - tmp_handle = os.tmpfile () - self.__get_file_read (tmp_handle, response, content_length) - tmp_handle.seek (0) - ret = tmp_handle.read () - tmp_handle.close () - return ret - - - def __destination_command (self, verb, remotesrc, dstdav, remotedst): - """ - self and dstdav should point to the same http server. - """ - if len (remotedst) > 0 and remotedst[ 0 ] == '/': - remotedst = remotedst[1:] - headers = {'Destination': 'http://%s:%d%s%s' % (dstdav.host, - dstdav.port, - dstdav.top_path, - remotedst)} - response = self.request (verb, remotesrc, None, headers) - if response.status == 201: - return # created - if response.status == 204: - return # no content - self.__err (response, (verb, remotesrc, None, headers, 0)) - - - def rename (self, remotesrc, remotedst): - """ rename a file on a webdav server """ - self.log ('rename %s -> %s' % (remotesrc, remotedst)) - self.__destination_command ('MOVE', remotesrc, self, remotedst) - def xrename (self, remotesrc, dstdav, remotedst): - """ rename a file on a webdav server """ - self.log ('xrename %s -> %s' % (remotesrc, remotedst)) - self.__destination_command ('MOVE', remotesrc, dstdav, remotedst) - - - def copy (self, remotesrc, remotedst): - """ copy a file on a webdav server """ - self.log ('copy %s -> %s' % (remotesrc, remotedst)) - self.__destination_command ('COPY', remotesrc, self, remotedst) - def xcopy (self, remotesrc, dstdav, remotedst): - """ copy a file on a webdav server """ - self.log ('xcopy %s -> %s' % (remotesrc, remotedst)) - self.__destination_command ('COPY', remotesrc, dstdav, remotedst) - - -def put_string (data, url): - """ - upload string s to a url - """ - url_parsed = urlparse.urlsplit (url) - dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ])) - dav.put_string (data, url_parsed[ 2 ]) - - -def get_string (url, check_size=True): - """ - return the contents of a url as a string - """ - url_parsed = urlparse.urlsplit (url) - dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ])) - return dav.get_file_as_string (url_parsed[ 2 ], check_size) diff --git a/indra/lib/python/indra/ipc/xml_rpc.py b/indra/lib/python/indra/ipc/xml_rpc.py deleted file mode 100755 index 47536c10c3..0000000000 --- a/indra/lib/python/indra/ipc/xml_rpc.py +++ /dev/null @@ -1,273 +0,0 @@ -"""\ -@file xml_rpc.py -@brief An implementation of a parser/generator for the XML-RPC xml format. - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - - -from greenlet import greenlet - -from mulib import mu - -from xml.sax import handler -from xml.sax import parseString - - -# States -class Expected(object): - def __init__(self, tag): - self.tag = tag - - def __getattr__(self, name): - return type(self)(name) - - def __repr__(self): - return '%s(%r)' % ( - type(self).__name__, self.tag) - - -class START(Expected): - pass - - -class END(Expected): - pass - - -class STR(object): - tag = '' - - -START = START('') -END = END('') - - -class Malformed(Exception): - pass - - -class XMLParser(handler.ContentHandler): - def __init__(self, state_machine, next_states): - handler.ContentHandler.__init__(self) - self.state_machine = state_machine - if not isinstance(next_states, tuple): - next_states = (next_states, ) - self.next_states = next_states - self._character_buffer = '' - - def assertState(self, state, name, *rest): - if not isinstance(self.next_states, tuple): - self.next_states = (self.next_states, ) - for next in self.next_states: - if type(state) == type(next): - if next.tag and next.tag != name: - raise Malformed( - "Expected %s, got %s %s %s" % ( - next, state, name, rest)) - break - else: - raise Malformed( - "Expected %s, got %s %s %s" % ( - self.next_states, state, name, rest)) - - def startElement(self, name, attrs): - self.assertState(START, name.lower(), attrs) - self.next_states = self.state_machine.switch(START, (name.lower(), dict(attrs))) - - def endElement(self, name): - if self._character_buffer.strip(): - characters = self._character_buffer.strip() - self._character_buffer = '' - self.assertState(STR, characters) - self.next_states = self.state_machine.switch(characters) - self.assertState(END, name.lower()) - self.next_states = self.state_machine.switch(END, name.lower()) - - def error(self, exc): - self.bozo = 1 - self.exc = exc - - def fatalError(self, exc): - self.error(exc) - raise exc - - def characters(self, characters): - self._character_buffer += characters - - -def parse(what): - child = greenlet(xml_rpc) - me = greenlet.getcurrent() - startup_states = child.switch(me) - parser = XMLParser(child, startup_states) - try: - parseString(what, parser) - except Malformed: - print what - raise - return child.switch() - - -def xml_rpc(yielder): - yielder.switch(START.methodcall) - yielder.switch(START.methodname) - methodName = yielder.switch(STR) - yielder.switch(END.methodname) - - yielder.switch(START.params) - - root = None - params = [] - while True: - state, _ = yielder.switch(START.param, END.params) - if state == END: - break - - yielder.switch(START.value) - - params.append( - handle(yielder)) - - yielder.switch(END.value) - yielder.switch(END.param) - - yielder.switch(END.methodcall) - ## Resume parse - yielder.switch() - ## Return result to parse - return methodName.strip(), params - - -def handle(yielder): - _, (tag, attrs) = yielder.switch(START) - if tag in ['int', 'i4']: - result = int(yielder.switch(STR)) - elif tag == 'boolean': - result = bool(int(yielder.switch(STR))) - elif tag == 'string': - result = yielder.switch(STR) - elif tag == 'double': - result = float(yielder.switch(STR)) - elif tag == 'datetime.iso8601': - result = yielder.switch(STR) - elif tag == 'base64': - result = base64.b64decode(yielder.switch(STR)) - elif tag == 'struct': - result = {} - while True: - state, _ = yielder.switch(START.member, END.struct) - if state == END: - break - - yielder.switch(START.name) - key = yielder.switch(STR) - yielder.switch(END.name) - - yielder.switch(START.value) - result[key] = handle(yielder) - yielder.switch(END.value) - - yielder.switch(END.member) - ## We already handled </struct> above, don't want to handle it below - return result - elif tag == 'array': - result = [] - yielder.switch(START.data) - while True: - state, _ = yielder.switch(START.value, END.data) - if state == END: - break - - result.append(handle(yielder)) - - yielder.switch(END.value) - - yielder.switch(getattr(END, tag)) - - return result - - -VALUE = mu.tag_factory('value') -BOOLEAN = mu.tag_factory('boolean') -INT = mu.tag_factory('int') -STRUCT = mu.tag_factory('struct') -MEMBER = mu.tag_factory('member') -NAME = mu.tag_factory('name') -ARRAY = mu.tag_factory('array') -DATA = mu.tag_factory('data') -STRING = mu.tag_factory('string') -DOUBLE = mu.tag_factory('double') -METHODRESPONSE = mu.tag_factory('methodResponse') -PARAMS = mu.tag_factory('params') -PARAM = mu.tag_factory('param') - -mu.inline_elements['string'] = True -mu.inline_elements['boolean'] = True -mu.inline_elements['name'] = True - - -def _generate(something): - if isinstance(something, dict): - result = STRUCT() - for key, value in something.items(): - result[ - MEMBER[ - NAME[key], _generate(value)]] - return VALUE[result] - elif isinstance(something, list): - result = DATA() - for item in something: - result[_generate(item)] - return VALUE[ARRAY[[result]]] - elif isinstance(something, basestring): - return VALUE[STRING[something]] - elif isinstance(something, bool): - if something: - return VALUE[BOOLEAN['1']] - return VALUE[BOOLEAN['0']] - elif isinstance(something, int): - return VALUE[INT[something]] - elif isinstance(something, float): - return VALUE[DOUBLE[something]] - -def generate(*args): - params = PARAMS() - for arg in args: - params[PARAM[_generate(arg)]] - return METHODRESPONSE[params] - - -if __name__ == '__main__': - print parse("""<?xml version="1.0"?> <methodCall> <methodName>examples.getStateName</methodName> <params> <param> <value><i4>41</i4></value> </param> </params> </methodCall> -""") - - - - - - - - - diff --git a/indra/lib/python/indra/util/fastest_elementtree.py b/indra/lib/python/indra/util/fastest_elementtree.py deleted file mode 100755 index 4fcf662dd9..0000000000 --- a/indra/lib/python/indra/util/fastest_elementtree.py +++ /dev/null @@ -1,64 +0,0 @@ -"""\ -@file fastest_elementtree.py -@brief Concealing some gnarly import logic in here. This should export the interface of elementtree. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -# The parsing exception raised by the underlying library depends -# on the ElementTree implementation we're using, so we provide an -# alias here. -# -# Use ElementTreeError as the exception type for catching parsing -# errors. - - -# Using cElementTree might cause some unforeseen problems, so here's a -# convenient off switch. -use_celementree = True - -try: - if not use_celementree: - raise ImportError() - # Python 2.3 and 2.4. - from cElementTree import * - ElementTreeError = SyntaxError -except ImportError: - try: - if not use_celementree: - raise ImportError() - # Python 2.5 and above. - from xml.etree.cElementTree import * - ElementTreeError = SyntaxError - except ImportError: - # Pure Python code. - try: - # Python 2.3 and 2.4. - from elementtree.ElementTree import * - except ImportError: - # Python 2.5 and above. - from xml.etree.ElementTree import * - - # The pure Python ElementTree module uses Expat for parsing. - from xml.parsers.expat import ExpatError as ElementTreeError diff --git a/indra/lib/python/indra/util/helpformatter.py b/indra/lib/python/indra/util/helpformatter.py deleted file mode 100755 index ba5c9b67d1..0000000000 --- a/indra/lib/python/indra/util/helpformatter.py +++ /dev/null @@ -1,52 +0,0 @@ -"""\ -@file helpformatter.py -@author Phoenix -@brief Class for formatting optparse descriptions. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import optparse -import textwrap - -class Formatter(optparse.IndentedHelpFormatter): - def __init__( - self, - p_indentIncrement = 2, - p_maxHelpPosition = 24, - p_width = 79, - p_shortFirst = 1) : - optparse.HelpFormatter.__init__( - self, - p_indentIncrement, - p_maxHelpPosition, - p_width, - p_shortFirst) - def format_description(self, p_description): - t_descWidth = self.width - self.current_indent - t_indent = " " * (self.current_indent + 2) - return "\n".join( - [textwrap.fill(descr, t_descWidth, initial_indent = t_indent, - subsequent_indent = t_indent) - for descr in p_description.split("\n")] ) diff --git a/indra/lib/python/indra/util/iterators.py b/indra/lib/python/indra/util/iterators.py deleted file mode 100755 index 9013fa6303..0000000000 --- a/indra/lib/python/indra/util/iterators.py +++ /dev/null @@ -1,63 +0,0 @@ -"""\ -@file iterators.py -@brief Useful general-purpose iterators. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -from __future__ import nested_scopes - -def iter_chunks(rows, aggregate_size=100): - """ - Given an iterable set of items (@p rows), produces lists of up to @p - aggregate_size items at a time, for example: - - iter_chunks([1,2,3,4,5,6,7,8,9,10], 3) - - Values for @p aggregate_size < 1 will raise ValueError. - - Will return a generator that produces, in the following order: - - [1, 2, 3] - - [4, 5, 6] - - [7, 8, 9] - - [10] - """ - if aggregate_size < 1: - raise ValueError() - - def iter_chunks_inner(): - row_iter = iter(rows) - done = False - agg = [] - while not done: - try: - row = row_iter.next() - agg.append(row) - except StopIteration: - done = True - if agg and (len(agg) >= aggregate_size or done): - yield agg - agg = [] - - return iter_chunks_inner() diff --git a/indra/lib/python/indra/util/iterators_test.py b/indra/lib/python/indra/util/iterators_test.py deleted file mode 100755 index 66928c8e7d..0000000000 --- a/indra/lib/python/indra/util/iterators_test.py +++ /dev/null @@ -1,72 +0,0 @@ -"""\ -@file iterators_test.py -@brief Test cases for iterators module. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import unittest - -from indra.util.iterators import iter_chunks - -class TestIterChunks(unittest.TestCase): - """Unittests for iter_chunks""" - def test_bad_agg_size(self): - rows = [1,2,3,4] - self.assertRaises(ValueError, iter_chunks, rows, 0) - self.assertRaises(ValueError, iter_chunks, rows, -1) - - try: - for i in iter_chunks(rows, 0): - pass - except ValueError: - pass - else: - self.fail() - - try: - result = list(iter_chunks(rows, 0)) - except ValueError: - pass - else: - self.fail() - def test_empty(self): - rows = [] - result = list(iter_chunks(rows)) - self.assertEqual(result, []) - def test_small(self): - rows = [[1]] - result = list(iter_chunks(rows, 2)) - self.assertEqual(result, [[[1]]]) - def test_size(self): - rows = [[1],[2]] - result = list(iter_chunks(rows, 2)) - self.assertEqual(result, [[[1],[2]]]) - def test_multi_agg(self): - rows = [[1],[2],[3],[4],[5]] - result = list(iter_chunks(rows, 2)) - self.assertEqual(result, [[[1],[2]],[[3],[4]],[[5]]]) - -if __name__ == "__main__": - unittest.main() diff --git a/indra/lib/python/indra/util/llperformance.py b/indra/lib/python/indra/util/llperformance.py deleted file mode 100755 index 57dd64de3f..0000000000 --- a/indra/lib/python/indra/util/llperformance.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python -"""\ -@file llperformance.py - -$LicenseInfo:firstyear=2010&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2010-2011, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -$/LicenseInfo$ -""" - -# ------------------------------------------------ -# Sim metrics utility functions. - -import glob, os, time, sys, stat, exceptions - -from indra.base import llsd - -gBlockMap = {} #Map of performance metric data with function hierarchy information. -gCurrentStatPath = "" - -gIsLoggingEnabled=False - -class LLPerfStat: - def __init__(self,key): - self.mTotalTime = 0 - self.mNumRuns = 0 - self.mName=key - self.mTimeStamp = int(time.time()*1000) - self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) - - def __str__(self): - return "%f" % self.mTotalTime - - def start(self): - self.mStartTime = int(time.time() * 1000000) - self.mNumRuns += 1 - - def stop(self): - execution_time = int(time.time() * 1000000) - self.mStartTime - self.mTotalTime += execution_time - - def get_map(self): - results={} - results['name']=self.mName - results['utc_time']=self.mUTCTime - results['timestamp']=self.mTimeStamp - results['us']=self.mTotalTime - results['count']=self.mNumRuns - return results - -class PerfError(exceptions.Exception): - def __init__(self): - return - - def __Str__(self): - print "","Unfinished LLPerfBlock" - -class LLPerfBlock: - def __init__( self, key ): - global gBlockMap - global gCurrentStatPath - global gIsLoggingEnabled - - #Check to see if we're running metrics right now. - if gIsLoggingEnabled: - self.mRunning = True #Mark myself as running. - - self.mPreviousStatPath = gCurrentStatPath - gCurrentStatPath += "/" + key - if gCurrentStatPath not in gBlockMap: - gBlockMap[gCurrentStatPath] = LLPerfStat(key) - - self.mStat = gBlockMap[gCurrentStatPath] - self.mStat.start() - - def finish( self ): - global gBlockMap - global gIsLoggingEnabled - - if gIsLoggingEnabled: - self.mStat.stop() - self.mRunning = False - gCurrentStatPath = self.mPreviousStatPath - -# def __del__( self ): -# if self.mRunning: -# #SPATTERS FIXME -# raise PerfError - -class LLPerformance: - #-------------------------------------------------- - # Determine whether or not we want to log statistics - - def __init__( self, process_name = "python" ): - self.process_name = process_name - self.init_testing() - self.mTimeStamp = int(time.time()*1000) - self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) - - def init_testing( self ): - global gIsLoggingEnabled - - host_performance_file = "/dev/shm/simperf/simperf_proc_config.llsd" - - #If file exists, open - if os.path.exists(host_performance_file): - file = open (host_performance_file,'r') - - #Read serialized LLSD from file. - body = llsd.parse(file.read()) - - #Calculate time since file last modified. - stats = os.stat(host_performance_file) - now = time.time() - mod = stats[stat.ST_MTIME] - age = now - mod - - if age < ( body['duration'] ): - gIsLoggingEnabled = True - - - def get ( self ): - global gIsLoggingEnabled - return gIsLoggingEnabled - - #def output(self,ptr,path): - # if 'stats' in ptr: - # stats = ptr['stats'] - # self.mOutputPtr[path] = stats.get_map() - - # if 'children' in ptr: - # children=ptr['children'] - - # curptr = self.mOutputPtr - # curchildren={} - # curptr['children'] = curchildren - - # for key in children: - # curchildren[key]={} - # self.mOutputPtr = curchildren[key] - # self.output(children[key],path + '/' + key) - - def done(self): - global gBlockMap - - if not self.get(): - return - - output_name = "/dev/shm/simperf/%s_proc.%d.llsd" % (self.process_name, os.getpid()) - output_file = open(output_name, 'w') - process_info = { - "name" : self.process_name, - "pid" : os.getpid(), - "ppid" : os.getppid(), - "timestamp" : self.mTimeStamp, - "utc_time" : self.mUTCTime, - } - output_file.write(llsd.format_notation(process_info)) - output_file.write('\n') - - for key in gBlockMap.keys(): - gBlockMap[key] = gBlockMap[key].get_map() - output_file.write(llsd.format_notation(gBlockMap)) - output_file.write('\n') - output_file.close() - diff --git a/indra/lib/python/indra/util/llsubprocess.py b/indra/lib/python/indra/util/llsubprocess.py deleted file mode 100755 index 7e0e115d14..0000000000 --- a/indra/lib/python/indra/util/llsubprocess.py +++ /dev/null @@ -1,117 +0,0 @@ -"""\ -@file llsubprocess.py -@author Phoenix -@date 2008-01-18 -@brief The simplest possible wrapper for a common sub-process paradigm. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import os -import popen2 -import time -import select - -class Timeout(RuntimeError): - "Exception raised when a subprocess times out." - pass - -def run(command, args=None, data=None, timeout=None): - """\ -@brief Run command with arguments - -This is it. This is the function I want to run all the time when doing -subprocces, but end up copying the code everywhere. none of the -standard commands are secure and provide a way to specify input, get -all the output, and get the result. -@param command A string specifying a process to launch. -@param args Arguments to be passed to command. Must be list, tuple or None. -@param data input to feed to the command. -@param timeout Maximum number of many seconds to run. -@return Returns (result, stdout, stderr) from process. -""" - cmd = [command] - if args: - cmd.extend([str(arg) for arg in args]) - #print "cmd: ","' '".join(cmd) - child = popen2.Popen3(cmd, True) - #print child.pid - out = [] - err = [] - result = -1 - time_left = timeout - tochild = [child.tochild.fileno()] - while True: - time_start = time.time() - #print "time:",time_left - p_in, p_out, p_err = select.select( - [child.fromchild.fileno(), child.childerr.fileno()], - tochild, - [], - time_left) - if p_in: - new_line = os.read(child.fromchild.fileno(), 32 * 1024) - if new_line: - #print "line:",new_line - out.append(new_line) - new_line = os.read(child.childerr.fileno(), 32 * 1024) - if new_line: - #print "error:", new_line - err.append(new_line) - if p_out: - if data: - #print "p_out" - bytes = os.write(child.tochild.fileno(), data) - data = data[bytes:] - if len(data) == 0: - data = None - tochild = [] - child.tochild.close() - result = child.poll() - if result != -1: - # At this point, the child process has exited and result - # is the return value from the process. Between the time - # we called select() and poll() the process may have - # exited so read all the data left on the child process - # stdout and stderr. - last = child.fromchild.read() - if last: - out.append(last) - last = child.childerr.read() - if last: - err.append(last) - child.tochild.close() - child.fromchild.close() - child.childerr.close() - break - if time_left is not None: - time_left -= (time.time() - time_start) - if time_left < 0: - raise Timeout - #print "result:",result - out = ''.join(out) - #print "stdout:", out - err = ''.join(err) - #print "stderr:", err - return result, out, err diff --git a/indra/lib/python/indra/util/named_query.py b/indra/lib/python/indra/util/named_query.py deleted file mode 100755 index 6bf956107d..0000000000 --- a/indra/lib/python/indra/util/named_query.py +++ /dev/null @@ -1,592 +0,0 @@ -"""\ -@file named_query.py -@author Ryan Williams, Phoenix -@date 2007-07-31 -@brief An API for running named queries. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import errno -import MySQLdb -import MySQLdb.cursors -import os -import os.path -import re -import time - -from indra.base import llsd -from indra.base import config - -DEBUG = False -NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq') -NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX) - -_g_named_manager = None - -def _init_g_named_manager(sql_dir = None): - """Initializes a global NamedManager object to point at a - specified named queries hierarchy. - - This function is intended entirely for testing purposes, - because it's tricky to control the config from inside a test.""" - global NQ_FILE_SUFFIX - NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq') - global NQ_FILE_SUFFIX_LEN - NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX) - - if sql_dir is None: - sql_dir = config.get('named-query-base-dir') - - # extra fallback directory in case config doesn't return what we want - if sql_dir is None: - sql_dir = os.path.abspath( - os.path.join( - os.path.realpath(os.path.dirname(__file__)), "..", "..", "..", "..", "web", "dataservice", "sql")) - - global _g_named_manager - _g_named_manager = NamedQueryManager( - os.path.abspath(os.path.realpath(sql_dir))) - -def get(name, schema = None): - "Get the named query object to be used to perform queries" - if _g_named_manager is None: - _init_g_named_manager() - return _g_named_manager.get(name).for_schema(schema) - -def sql(connection, name, params): - # use module-global NamedQuery object to perform default substitution - return get(name).sql(connection, params) - -def run(connection, name, params, expect_rows = None): - """\ -@brief given a connection, run a named query with the params - -Note that this function will fetch ALL rows. -@param connection The connection to use -@param name The name of the query to run -@param params The parameters passed into the query -@param expect_rows The number of rows expected. Set to 1 if return_as_map is true. Raises ExpectationFailed if the number of returned rows doesn't exactly match. Kind of a hack. -@return Returns the result set as a list of dicts. -""" - return get(name).run(connection, params, expect_rows) - -class ExpectationFailed(Exception): - """ Exception that is raised when an expectation for an sql query - is not met.""" - def __init__(self, message): - Exception.__init__(self, message) - self.message = message - -class NamedQuery(object): - def __init__(self, name, filename): - """ Construct a NamedQuery object. The name argument is an - arbitrary name as a handle for the query, and the filename is - a path to a file or a file-like object containing an llsd named - query document.""" - self._stat_interval_seconds = 5 # 5 seconds - self._name = name - if (filename is not None and isinstance(filename, (str, unicode)) - and NQ_FILE_SUFFIX != filename[-NQ_FILE_SUFFIX_LEN:]): - filename = filename + NQ_FILE_SUFFIX - self._location = filename - self._alternative = dict() - self._last_mod_time = 0 - self._last_check_time = 0 - self.deleted = False - self.load_contents() - - def name(self): - """ The name of the query. """ - return self._name - - def get_modtime(self): - """ Returns the mtime (last modified time) of the named query - filename. For file-like objects, expect a modtime of 0""" - if self._location and isinstance(self._location, (str, unicode)): - return os.path.getmtime(self._location) - return 0 - - def load_contents(self): - """ Loads and parses the named query file into self. Does - nothing if self.location is nonexistant.""" - if self._location: - if isinstance(self._location, (str, unicode)): - contents = llsd.parse(open(self._location).read()) - else: - # we probably have a file-like object. Godspeed! - contents = llsd.parse(self._location.read()) - self._reference_contents(contents) - # Check for alternative implementations - try: - for name, alt in self._contents['alternative'].items(): - nq = NamedQuery(name, None) - nq._reference_contents(alt) - self._alternative[name] = nq - except KeyError, e: - pass - self._last_mod_time = self.get_modtime() - self._last_check_time = time.time() - - def _reference_contents(self, contents): - "Helper method which builds internal structure from parsed contents" - self._contents = contents - self._ttl = int(self._contents.get('ttl', 0)) - self._return_as_map = bool(self._contents.get('return_as_map', False)) - self._legacy_dbname = self._contents.get('legacy_dbname', None) - - # reset these before doing the sql conversion because we will - # read them there. reset these while loading so we pick up - # changes. - self._around = set() - self._append = set() - self._integer = set() - self._options = self._contents.get('dynamic_where', {}) - for key in self._options: - if isinstance(self._options[key], basestring): - self._options[key] = self._convert_sql(self._options[key]) - elif isinstance(self._options[key], list): - lines = [] - for line in self._options[key]: - lines.append(self._convert_sql(line)) - self._options[key] = lines - else: - moreopt = {} - for kk in self._options[key]: - moreopt[kk] = self._convert_sql(self._options[key][kk]) - self._options[key] = moreopt - self._base_query = self._convert_sql(self._contents['base_query']) - self._query_suffix = self._convert_sql( - self._contents.get('query_suffix', '')) - - def _convert_sql(self, sql): - """convert the parsed sql into a useful internal structure. - - This function has to turn the named query format into a pyformat - style. It also has to look for %:name% and :name% and - ready them for use in LIKE statements""" - if sql: - # This first sub is to properly escape any % signs that - # are meant to be literally passed through to mysql in the - # query. It leaves any %'s that are used for - # like-expressions. - expr = re.compile("(?<=[^a-zA-Z0-9_-])%(?=[^:])") - sql = expr.sub('%%', sql) - - # This should tackle the rest of the %'s in the query, by - # converting them to LIKE clauses. - expr = re.compile("(%?):([a-zA-Z][a-zA-Z0-9_-]*)%") - sql = expr.sub(self._prepare_like, sql) - expr = re.compile("#:([a-zA-Z][a-zA-Z0-9_-]*)") - sql = expr.sub(self._prepare_integer, sql) - expr = re.compile(":([a-zA-Z][a-zA-Z0-9_-]*)") - sql = expr.sub("%(\\1)s", sql) - return sql - - def _prepare_like(self, match): - """This function changes LIKE statement replace behavior - - It works by turning %:name% to %(_name_around)s and :name% to - %(_name_append)s. Since a leading '_' is not a valid keyname - input (enforced via unit tests), it will never clash with - existing keys. Then, when building the statement, the query - runner will generate corrected strings.""" - if match.group(1) == '%': - # there is a leading % so this is treated as prefix/suffix - self._around.add(match.group(2)) - return "%(" + self._build_around_key(match.group(2)) + ")s" - else: - # there is no leading %, so this is suffix only - self._append.add(match.group(2)) - return "%(" + self._build_append_key(match.group(2)) + ")s" - - def _build_around_key(self, key): - return "_" + key + "_around" - - def _build_append_key(self, key): - return "_" + key + "_append" - - def _prepare_integer(self, match): - """This function adjusts the sql for #:name replacements - - It works by turning #:name to %(_name_as_integer)s. Since a - leading '_' is not a valid keyname input (enforced via unit - tests), it will never clash with existing keys. Then, when - building the statement, the query runner will generate - corrected strings.""" - self._integer.add(match.group(1)) - return "%(" + self._build_integer_key(match.group(1)) + ")s" - - def _build_integer_key(self, key): - return "_" + key + "_as_integer" - - def _strip_wildcards_to_list(self, value): - """Take string, and strip out the LIKE special characters. - - Technically, this is database dependant, but postgresql and - mysql use the same wildcards, and I am not aware of a general - way to handle this. I think you need a sql statement of the - form: - - LIKE_STRING( [ANY,ONE,str]... ) - - which would treat ANY as their any string, and ONE as their - single glyph, and str as something that needs database - specific encoding to not allow any % or _ to affect the query. - - As it stands, I believe it's impossible to write a named query - style interface which uses like to search the entire space of - text available. Imagine the query: - - % of brain used by average linden - - In order to search for %, it must be escaped, so once you have - escaped the string to not do wildcard searches, and be escaped - for the database, and then prepended the wildcard you come - back with one of: - - 1) %\% of brain used by average linden - 2) %%% of brain used by average linden - - Then, when passed to the database to be escaped to be database - safe, you get back: - - 1) %\\% of brain used by average linden - : which means search for any character sequence, followed by a - backslash, followed by any sequence, followed by ' of - brain...' - 2) %%% of brain used by average linden - : which (I believe) means search for a % followed by any - character sequence followed by 'of brain...' - - Neither of which is what we want! - - So, we need a vendor (or extention) for LIKE_STRING. Anyone - want to write it?""" - if isinstance(value, unicode): - utf8_value = value - else: - utf8_value = unicode(value, "utf-8") - esc_list = [] - remove_chars = set(u"%_") - for glyph in utf8_value: - if glyph in remove_chars: - continue - esc_list.append(glyph.encode("utf-8")) - return esc_list - - def delete(self): - """ Makes this query unusable by deleting all the members and - setting the deleted member. This is desired when the on-disk - query has been deleted but the in-memory copy remains.""" - # blow away all members except _name, _location, and deleted - name, location = self._name, self._location - for key in self.__dict__.keys(): - del self.__dict__[key] - self.deleted = True - self._name, self._location = name, location - - def ttl(self): - """ Estimated time to live of this query. Used for web - services to set the Expires header.""" - return self._ttl - - def legacy_dbname(self): - return self._legacy_dbname - - def return_as_map(self): - """ Returns true if this query is configured to return its - results as a single map (as opposed to a list of maps, the - normal behavior).""" - - return self._return_as_map - - def for_schema(self, db_name): - "Look trough the alternates and return the correct query" - if db_name is None: - return self - try: - return self._alternative[db_name] - except KeyError, e: - pass - return self - - def run(self, connection, params, expect_rows = None, use_dictcursor = True): - """given a connection, run a named query with the params - - Note that this function will fetch ALL rows. We do this because it - opens and closes the cursor to generate the values, and this - isn't a generator so the cursor has no life beyond the method call. - - @param cursor The connection to use (this generates its own cursor for the query) - @param name The name of the query to run - @param params The parameters passed into the query - @param expect_rows The number of rows expected. Set to 1 if return_as_map is true. Raises ExpectationFailed if the number of returned rows doesn't exactly match. Kind of a hack. - @param use_dictcursor Set to false to use a normal cursor and manually convert the rows to dicts. - @return Returns the result set as a list of dicts, or, if the named query has return_as_map set to true, returns a single dict. - """ - if use_dictcursor: - cursor = connection.cursor(MySQLdb.cursors.DictCursor) - else: - cursor = connection.cursor() - - full_query, params = self._construct_sql(params) - if DEBUG: - print "SQL:", self.sql(connection, params) - rows = cursor.execute(full_query, params) - - # *NOTE: the expect_rows argument is a very cheesy way to get some - # validation on the result set. If you want to add more expectation - # logic, do something more object-oriented and flexible. Or use an ORM. - if(self._return_as_map): - expect_rows = 1 - if expect_rows is not None and rows != expect_rows: - cursor.close() - raise ExpectationFailed("Statement expected %s rows, got %s. Sql: '%s' %s" % ( - expect_rows, rows, full_query, params)) - - # convert to dicts manually if we're not using a dictcursor - if use_dictcursor: - result_set = cursor.fetchall() - else: - if cursor.description is None: - # an insert or something - x = cursor.fetchall() - cursor.close() - return x - - names = [x[0] for x in cursor.description] - - result_set = [] - for row in cursor.fetchall(): - converted_row = {} - for idx, col_name in enumerate(names): - converted_row[col_name] = row[idx] - result_set.append(converted_row) - - cursor.close() - if self._return_as_map: - return result_set[0] - return result_set - - def _construct_sql(self, params): - """ Returns a query string and a dictionary of parameters, - suitable for directly passing to the execute() method.""" - self.refresh() - - # build the query from the options available and the params - base_query = [] - base_query.append(self._base_query) - for opt, extra_where in self._options.items(): - if type(extra_where) in (dict, list, tuple): - if opt in params: - base_query.append(extra_where[params[opt]]) - else: - if opt in params and params[opt]: - base_query.append(extra_where) - if self._query_suffix: - base_query.append(self._query_suffix) - full_query = '\n'.join(base_query) - - # Go through the query and rewrite all of the ones with the - # @:name syntax. - rewrite = _RewriteQueryForArray(params) - expr = re.compile("@%\(([a-zA-Z][a-zA-Z0-9_-]*)\)s") - full_query = expr.sub(rewrite.operate, full_query) - params.update(rewrite.new_params) - - # build out the params for like. We only have to do this - # parameters which were detected to have ued the where syntax - # during load. - # - # * treat the incoming string as utf-8 - # * strip wildcards - # * append or prepend % as appropriate - new_params = {} - for key in params: - if key in self._around: - new_value = ['%'] - new_value.extend(self._strip_wildcards_to_list(params[key])) - new_value.append('%') - new_params[self._build_around_key(key)] = ''.join(new_value) - if key in self._append: - new_value = self._strip_wildcards_to_list(params[key]) - new_value.append('%') - new_params[self._build_append_key(key)] = ''.join(new_value) - if key in self._integer: - new_params[self._build_integer_key(key)] = int(params[key]) - params.update(new_params) - - return full_query, params - - def sql(self, connection, params): - """ Generates an SQL statement from the named query document - and a dictionary of parameters. - - *NOTE: Only use for debugging, because it uses the - non-standard MySQLdb 'literal' method. - """ - if not DEBUG: - import warnings - warnings.warn("Don't use named_query.sql() when not debugging. Used on %s" % self._location) - # do substitution using the mysql (non-standard) 'literal' - # function to do the escaping. - full_query, params = self._construct_sql(params) - return full_query % connection.literal(params) - - - def refresh(self): - """ Refresh self from the file on the filesystem. - - This is optimized to be callable as frequently as you wish, - without adding too much load. It does so by only stat-ing the - file every N seconds, where N defaults to 5 and is - configurable through the member _stat_interval_seconds. If the stat - reveals that the file has changed, refresh will re-parse the - contents of the file and use them to update the named query - instance. If the stat reveals that the file has been deleted, - refresh will call self.delete to make the in-memory - representation unusable.""" - now = time.time() - if(now - self._last_check_time > self._stat_interval_seconds): - self._last_check_time = now - try: - modtime = self.get_modtime() - if(modtime > self._last_mod_time): - self.load_contents() - except OSError, e: - if e.errno == errno.ENOENT: # file not found - self.delete() # clean up self - raise # pass the exception along to the caller so they know that this query disappeared - -class NamedQueryManager(object): - """ Manages the lifespan of NamedQuery objects, drawing from a - directory hierarchy of named query documents. - - In practice this amounts to a memory cache of NamedQuery objects.""" - - def __init__(self, named_queries_dir): - """ Initializes a manager to look for named queries in a - directory.""" - self._dir = os.path.abspath(os.path.realpath(named_queries_dir)) - self._cached_queries = {} - - def sql(self, connection, name, params): - nq = self.get(name) - return nq.sql(connection, params) - - def get(self, name): - """ Returns a NamedQuery instance based on the name, either - from memory cache, or by parsing from disk. - - The name is simply a relative path to the directory associated - with the manager object. Before returning the instance, the - NamedQuery object is cached in memory, so that subsequent - accesses don't have to read from disk or do any parsing. This - means that NamedQuery objects returned by this method are - shared across all users of the manager object. - NamedQuery.refresh is used to bring the NamedQuery objects in - sync with the actual files on disk.""" - nq = self._cached_queries.get(name) - if nq is None: - nq = NamedQuery(name, os.path.join(self._dir, name)) - self._cached_queries[name] = nq - else: - try: - nq.refresh() - except OSError, e: - if e.errno == errno.ENOENT: # file not found - del self._cached_queries[name] - raise # pass exception along to caller so they know that the query disappeared - - return nq - -class _RewriteQueryForArray(object): - "Helper class for rewriting queries with the @:name syntax" - def __init__(self, params): - self.params = params - self.new_params = dict() - - def operate(self, match): - "Given a match, return the string that should be in use" - key = match.group(1) - value = self.params[key] - if type(value) in (list,tuple): - rv = [] - for idx in range(len(value)): - # if the value@idx is array-like, we are - # probably dealing with a VALUES - new_key = "_%s_%s"%(key, str(idx)) - val_item = value[idx] - if type(val_item) in (list, tuple, dict): - if type(val_item) is dict: - # this is because in Python, the order of - # key, value retrieval from the dict is not - # guaranteed to match what the input intended - # and for VALUES, order is important. - # TODO: Implemented ordered dict in LLSD parser? - raise ExpectationFailed('Only lists/tuples allowed,\ - received dict') - values_keys = [] - for value_idx, item in enumerate(val_item): - # we want a key of the format : - # key_#replacement_#value_row_#value_col - # ugh... so if we are replacing 10 rows in user_note, - # the first values clause would read (for @:user_notes) :- - # ( :_user_notes_0_1_1, :_user_notes_0_1_2, :_user_notes_0_1_3 ) - # the input LLSD for VALUES will look like: - # <llsd>... - # <map> - # <key>user_notes</key> - # <array> - # <array> <!-- row 1 for VALUES --> - # <string>...</string> - # <string>...</string> - # <string>...</string> - # </array> - # ... - # </array> - # </map> - # ... </llsd> - values_key = "%s_%s"%(new_key, value_idx) - self.new_params[values_key] = item - values_keys.append("%%(%s)s"%values_key) - # now collapse all these new place holders enclosed in () - # from [':_key_0_1_1', ':_key_0_1_2', ':_key_0_1_3,...] - # rv will have [ '(:_key_0_1_1, :_key_0_1_2, :_key_0_1_3)', ] - # which is flattened a few lines below join(rv) - rv.append('(%s)' % ','.join(values_keys)) - else: - self.new_params[new_key] = val_item - rv.append("%%(%s)s"%new_key) - return ','.join(rv) - else: - # not something that can be expanded, so just drop the - # leading @ in the front of the match. This will mean that - # the single value we have, be it a string, int, whatever - # (other than dict) will correctly show up, eg: - # - # where foo in (@:foobar) -- foobar is a string, so we get - # where foo in (:foobar) - return match.group(0)[1:] diff --git a/indra/lib/python/indra/util/shutil2.py b/indra/lib/python/indra/util/shutil2.py deleted file mode 100755 index 9e2e7a6ded..0000000000 --- a/indra/lib/python/indra/util/shutil2.py +++ /dev/null @@ -1,84 +0,0 @@ -''' -@file shutil2.py -@brief a better shutil.copytree replacement - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -''' - -# -# shutil2.py -# Taken from http://www.scons.org/wiki/AccumulateBuilder -# the stock copytree sucks because it insists that the -# target dir not exist -# - -import os.path -import shutil - -def copytree(src, dest, symlinks=False): - """My own copyTree which does not fail if the directory exists. - - Recursively copy a directory tree using copy2(). - - If the optional symlinks flag is true, symbolic links in the - source tree result in symbolic links in the destination tree; if - it is false, the contents of the files pointed to by symbolic - links are copied. - - Behavior is meant to be identical to GNU 'cp -R'. - """ - def copyItems(src, dest, symlinks=False): - """Function that does all the work. - - It is necessary to handle the two 'cp' cases: - - destination does exist - - destination does not exist - - See 'cp -R' documentation for more details - """ - for item in os.listdir(src): - srcPath = os.path.join(src, item) - if os.path.isdir(srcPath): - srcBasename = os.path.basename(srcPath) - destDirPath = os.path.join(dest, srcBasename) - if not os.path.exists(destDirPath): - os.makedirs(destDirPath) - copyItems(srcPath, destDirPath) - elif os.path.islink(item) and symlinks: - linkto = os.readlink(item) - os.symlink(linkto, dest) - else: - shutil.copy2(srcPath, dest) - - # case 'cp -R src/ dest/' where dest/ already exists - if os.path.exists(dest): - destPath = os.path.join(dest, os.path.basename(src)) - if not os.path.exists(destPath): - os.makedirs(destPath) - # case 'cp -R src/ dest/' where dest/ does not exist - else: - os.makedirs(dest) - destPath = dest - # actually copy the files - copyItems(src, destPath) diff --git a/indra/lib/python/indra/util/simperf_host_xml_parser.py b/indra/lib/python/indra/util/simperf_host_xml_parser.py deleted file mode 100755 index 672c1050c2..0000000000 --- a/indra/lib/python/indra/util/simperf_host_xml_parser.py +++ /dev/null @@ -1,338 +0,0 @@ -#!/usr/bin/env python -"""\ -@file simperf_host_xml_parser.py -@brief Digest collector's XML dump and convert to simple dict/list structure - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys, os, getopt, time -import simplejson -from xml import sax - - -def usage(): - print "Usage:" - print sys.argv[0] + " [options]" - print " Convert RRD's XML dump to JSON. Script to convert the simperf_host_collector-" - print " generated RRD dump into JSON. Steps include converting selected named" - print " fields from GAUGE type to COUNTER type by computing delta with preceding" - print " values. Top-level named fields are:" - print - print " lastupdate Time (javascript timestamp) of last data sample" - print " step Time in seconds between samples" - print " ds Data specification (name/type) for each column" - print " database Table of data samples, one time step per row" - print - print "Options:" - print " -i, --in Input settings filename. (Default: stdin)" - print " -o, --out Output settings filename. (Default: stdout)" - print " -h, --help Print this message and exit." - print - print "Example: %s -i rrddump.xml -o rrddump.json" % sys.argv[0] - print - print "Interfaces:" - print " class SimPerfHostXMLParser() # SAX content handler" - print " def simperf_host_xml_fixup(parser) # post-parse value fixup" - -class SimPerfHostXMLParser(sax.handler.ContentHandler): - - def __init__(self): - pass - - def startDocument(self): - self.rrd_last_update = 0 # public - self.rrd_step = 0 # public - self.rrd_ds = [] # public - self.rrd_records = [] # public - self._rrd_level = 0 - self._rrd_parse_state = 0 - self._rrd_chars = "" - self._rrd_capture = False - self._rrd_ds_val = {} - self._rrd_data_row = [] - self._rrd_data_row_has_nan = False - - def endDocument(self): - pass - - # Nasty little ad-hoc state machine to extract the elements that are - # necessary from the 'rrdtool dump' XML output. The same element - # name '<ds>' is used for two different data sets so we need to pay - # some attention to the actual structure to get the ones we want - # and ignore the ones we don't. - - def startElement(self, name, attrs): - self._rrd_level = self._rrd_level + 1 - self._rrd_capture = False - if self._rrd_level == 1: - if name == "rrd" and self._rrd_parse_state == 0: - self._rrd_parse_state = 1 # In <rrd> - self._rrd_capture = True - self._rrd_chars = "" - elif self._rrd_level == 2: - if self._rrd_parse_state == 1: - if name == "lastupdate": - self._rrd_parse_state = 2 # In <rrd><lastupdate> - self._rrd_capture = True - self._rrd_chars = "" - elif name == "step": - self._rrd_parse_state = 3 # In <rrd><step> - self._rrd_capture = True - self._rrd_chars = "" - elif name == "ds": - self._rrd_parse_state = 4 # In <rrd><ds> - self._rrd_ds_val = {} - self._rrd_chars = "" - elif name == "rra": - self._rrd_parse_state = 5 # In <rrd><rra> - elif self._rrd_level == 3: - if self._rrd_parse_state == 4: - if name == "name": - self._rrd_parse_state = 6 # In <rrd><ds><name> - self._rrd_capture = True - self._rrd_chars = "" - elif name == "type": - self._rrd_parse_state = 7 # In <rrd><ds><type> - self._rrd_capture = True - self._rrd_chars = "" - elif self._rrd_parse_state == 5: - if name == "database": - self._rrd_parse_state = 8 # In <rrd><rra><database> - elif self._rrd_level == 4: - if self._rrd_parse_state == 8: - if name == "row": - self._rrd_parse_state = 9 # In <rrd><rra><database><row> - self._rrd_data_row = [] - self._rrd_data_row_has_nan = False - elif self._rrd_level == 5: - if self._rrd_parse_state == 9: - if name == "v": - self._rrd_parse_state = 10 # In <rrd><rra><database><row><v> - self._rrd_capture = True - self._rrd_chars = "" - - def endElement(self, name): - self._rrd_capture = False - if self._rrd_parse_state == 10: - self._rrd_capture = self._rrd_level == 6 - if self._rrd_level == 5: - if self._rrd_chars == "NaN": - self._rrd_data_row_has_nan = True - else: - self._rrd_data_row.append(self._rrd_chars) - self._rrd_parse_state = 9 # In <rrd><rra><database><row> - elif self._rrd_parse_state == 9: - if self._rrd_level == 4: - if not self._rrd_data_row_has_nan: - self.rrd_records.append(self._rrd_data_row) - self._rrd_parse_state = 8 # In <rrd><rra><database> - elif self._rrd_parse_state == 8: - if self._rrd_level == 3: - self._rrd_parse_state = 5 # In <rrd><rra> - elif self._rrd_parse_state == 7: - if self._rrd_level == 3: - self._rrd_ds_val["type"] = self._rrd_chars - self._rrd_parse_state = 4 # In <rrd><ds> - elif self._rrd_parse_state == 6: - if self._rrd_level == 3: - self._rrd_ds_val["name"] = self._rrd_chars - self._rrd_parse_state = 4 # In <rrd><ds> - elif self._rrd_parse_state == 5: - if self._rrd_level == 2: - self._rrd_parse_state = 1 # In <rrd> - elif self._rrd_parse_state == 4: - if self._rrd_level == 2: - self.rrd_ds.append(self._rrd_ds_val) - self._rrd_parse_state = 1 # In <rrd> - elif self._rrd_parse_state == 3: - if self._rrd_level == 2: - self.rrd_step = long(self._rrd_chars) - self._rrd_parse_state = 1 # In <rrd> - elif self._rrd_parse_state == 2: - if self._rrd_level == 2: - self.rrd_last_update = long(self._rrd_chars) - self._rrd_parse_state = 1 # In <rrd> - elif self._rrd_parse_state == 1: - if self._rrd_level == 1: - self._rrd_parse_state = 0 # At top - - if self._rrd_level: - self._rrd_level = self._rrd_level - 1 - - def characters(self, content): - if self._rrd_capture: - self._rrd_chars = self._rrd_chars + content.strip() - -def _make_numeric(value): - try: - value = float(value) - except: - value = "" - return value - -def simperf_host_xml_fixup(parser, filter_start_time = None, filter_end_time = None): - # Fixup for GAUGE fields that are really COUNTS. They - # were forced to GAUGE to try to disable rrdtool's - # data interpolation/extrapolation for non-uniform time - # samples. - fixup_tags = [ "cpu_user", - "cpu_nice", - "cpu_sys", - "cpu_idle", - "cpu_waitio", - "cpu_intr", - # "file_active", - # "file_free", - # "inode_active", - # "inode_free", - "netif_in_kb", - "netif_in_pkts", - "netif_in_errs", - "netif_in_drop", - "netif_out_kb", - "netif_out_pkts", - "netif_out_errs", - "netif_out_drop", - "vm_page_in", - "vm_page_out", - "vm_swap_in", - "vm_swap_out", - #"vm_mem_total", - #"vm_mem_used", - #"vm_mem_active", - #"vm_mem_inactive", - #"vm_mem_free", - #"vm_mem_buffer", - #"vm_swap_cache", - #"vm_swap_total", - #"vm_swap_used", - #"vm_swap_free", - "cpu_interrupts", - "cpu_switches", - "cpu_forks" ] - - col_count = len(parser.rrd_ds) - row_count = len(parser.rrd_records) - - # Process the last row separately, just to make all values numeric. - for j in range(col_count): - parser.rrd_records[row_count - 1][j] = _make_numeric(parser.rrd_records[row_count - 1][j]) - - # Process all other row/columns. - last_different_row = row_count - 1 - current_row = row_count - 2 - while current_row >= 0: - # Check for a different value than the previous row. If everything is the same - # then this is probably just a filler/bogus entry. - is_different = False - for j in range(col_count): - parser.rrd_records[current_row][j] = _make_numeric(parser.rrd_records[current_row][j]) - if parser.rrd_records[current_row][j] != parser.rrd_records[last_different_row][j]: - # We're good. This is a different row. - is_different = True - - if not is_different: - # This is a filler/bogus entry. Just ignore it. - for j in range(col_count): - parser.rrd_records[current_row][j] = float('nan') - else: - # Some tags need to be converted into deltas. - for j in range(col_count): - if parser.rrd_ds[j]["name"] in fixup_tags: - parser.rrd_records[last_different_row][j] = \ - parser.rrd_records[last_different_row][j] - parser.rrd_records[current_row][j] - last_different_row = current_row - - current_row -= 1 - - # Set fixup_tags in the first row to 'nan' since they aren't useful anymore. - for j in range(col_count): - if parser.rrd_ds[j]["name"] in fixup_tags: - parser.rrd_records[0][j] = float('nan') - - # Add a timestamp to each row and to the catalog. Format and name - # chosen to match other simulator logging (hopefully). - start_time = parser.rrd_last_update - (parser.rrd_step * (row_count - 1)) - # Build a filtered list of rrd_records if we are limited to a time range. - filter_records = False - if filter_start_time is not None or filter_end_time is not None: - filter_records = True - filtered_rrd_records = [] - if filter_start_time is None: - filter_start_time = start_time * 1000 - if filter_end_time is None: - filter_end_time = parser.rrd_last_update * 1000 - - for i in range(row_count): - record_timestamp = (start_time + (i * parser.rrd_step)) * 1000 - parser.rrd_records[i].insert(0, record_timestamp) - if filter_records: - if filter_start_time <= record_timestamp and record_timestamp <= filter_end_time: - filtered_rrd_records.append(parser.rrd_records[i]) - - if filter_records: - parser.rrd_records = filtered_rrd_records - - parser.rrd_ds.insert(0, {"type": "GAUGE", "name": "javascript_timestamp"}) - - -def main(argv=None): - opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"]) - input_file = sys.stdin - output_file = sys.stdout - for o, a in opts: - if o in ("-i", "--in"): - input_file = open(a, 'r') - if o in ("-o", "--out"): - output_file = open(a, 'w') - if o in ("-h", "--help"): - usage() - sys.exit(0) - - # Using the SAX parser as it is at least 4X faster and far, far - # smaller on this dataset than the DOM-based interface in xml.dom.minidom. - # With SAX and a 5.4MB xml file, this requires about seven seconds of - # wall-clock time and 32MB VSZ. With the DOM interface, about 22 seconds - # and over 270MB VSZ. - - handler = SimPerfHostXMLParser() - sax.parse(input_file, handler) - if input_file != sys.stdin: - input_file.close() - - # Various format fixups: string-to-num, gauge-to-counts, add - # a time stamp, etc. - simperf_host_xml_fixup(handler) - - # Create JSONable dict with interesting data and format/print it - print >>output_file, simplejson.dumps({ "step" : handler.rrd_step, - "lastupdate": handler.rrd_last_update * 1000, - "ds" : handler.rrd_ds, - "database" : handler.rrd_records }) - - return 0 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/indra/lib/python/indra/util/simperf_oprof_interface.py b/indra/lib/python/indra/util/simperf_oprof_interface.py deleted file mode 100755 index 547d2f9980..0000000000 --- a/indra/lib/python/indra/util/simperf_oprof_interface.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env python -"""\ -@file simperf_oprof_interface.py -@brief Manage OProfile data collection on a host - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys, os, getopt -import simplejson - - -def usage(): - print "Usage:" - print sys.argv[0] + " [options]" - print " Digest the OProfile report forms that come out of the" - print " simperf_oprof_ctl program's -r/--report command. The result" - print " is an array of dictionaires with the following keys:" - print - print " symbol Name of sampled, calling, or called procedure" - print " file Executable or library where symbol resides" - print " percentage Percentage contribution to profile, calls or called" - print " samples Sample count" - print " calls Methods called by the method in question (full only)" - print " called_by Methods calling the method (full only)" - print - print " For 'full' reports the two keys 'calls' and 'called_by' are" - print " themselves arrays of dictionaries based on the first four keys." - print - print "Return Codes:" - print " None. Aggressively digests everything. Will likely mung results" - print " if a program or library has whitespace in its name." - print - print "Options:" - print " -i, --in Input settings filename. (Default: stdin)" - print " -o, --out Output settings filename. (Default: stdout)" - print " -h, --help Print this message and exit." - print - print "Interfaces:" - print " class SimPerfOProfileInterface()" - -class SimPerfOProfileInterface: - def __init__(self): - self.isBrief = True # public - self.isValid = False # public - self.result = [] # public - - def parse(self, input): - in_samples = False - for line in input: - if in_samples: - if line[0:6] == "------": - self.isBrief = False - self._parseFull(input) - else: - self._parseBrief(input, line) - self.isValid = True - return - try: - hd1, remain = line.split(None, 1) - if hd1 == "samples": - in_samples = True - except ValueError: - pass - - def _parseBrief(self, input, line1): - try: - fld1, fld2, fld3, fld4 = line1.split(None, 3) - self.result.append({"samples" : fld1, - "percentage" : fld2, - "file" : fld3, - "symbol" : fld4.strip("\n")}) - except ValueError: - pass - for line in input: - try: - fld1, fld2, fld3, fld4 = line.split(None, 3) - self.result.append({"samples" : fld1, - "percentage" : fld2, - "file" : fld3, - "symbol" : fld4.strip("\n")}) - except ValueError: - pass - - def _parseFull(self, input): - state = 0 # In 'called_by' section - calls = [] - called_by = [] - current = {} - for line in input: - if line[0:6] == "------": - if len(current): - current["calls"] = calls - current["called_by"] = called_by - self.result.append(current) - state = 0 - calls = [] - called_by = [] - current = {} - else: - try: - fld1, fld2, fld3, fld4 = line.split(None, 3) - tmp = {"samples" : fld1, - "percentage" : fld2, - "file" : fld3, - "symbol" : fld4.strip("\n")} - except ValueError: - continue - if line[0] != " ": - current = tmp - state = 1 # In 'calls' section - elif state == 0: - called_by.append(tmp) - else: - calls.append(tmp) - if len(current): - current["calls"] = calls - current["called_by"] = called_by - self.result.append(current) - - -def main(argv=None): - opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"]) - input_file = sys.stdin - output_file = sys.stdout - for o, a in opts: - if o in ("-i", "--in"): - input_file = open(a, 'r') - if o in ("-o", "--out"): - output_file = open(a, 'w') - if o in ("-h", "--help"): - usage() - sys.exit(0) - - oprof = SimPerfOProfileInterface() - oprof.parse(input_file) - if input_file != sys.stdin: - input_file.close() - - # Create JSONable dict with interesting data and format/print it - print >>output_file, simplejson.dumps(oprof.result) - - return 0 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/indra/lib/python/indra/util/simperf_proc_interface.py b/indra/lib/python/indra/util/simperf_proc_interface.py deleted file mode 100755 index de061f68cc..0000000000 --- a/indra/lib/python/indra/util/simperf_proc_interface.py +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/env python -"""\ -@file simperf_proc_interface.py -@brief Utility to extract log messages from *.<pid>.llsd files containing performance statistics. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -# ---------------------------------------------------- -# Utility to extract log messages from *.<pid>.llsd -# files that contain performance statistics. - -# ---------------------------------------------------- -import sys, os - -if os.path.exists("setup-path.py"): - execfile("setup-path.py") - -from indra.base import llsd - -DEFAULT_PATH="/dev/shm/simperf/" - - -# ---------------------------------------------------- -# Pull out the stats and return a single document -def parse_logfile(filename, target_column=None, verbose=False): - full_doc = [] - # Open source temp log file. Let exceptions percolate up. - sourcefile = open( filename,'r') - - if verbose: - print "Reading " + filename - - # Parse and output all lines from the temp file - for line in sourcefile.xreadlines(): - partial_doc = llsd.parse(line) - if partial_doc is not None: - if target_column is None: - full_doc.append(partial_doc) - else: - trim_doc = { target_column: partial_doc[target_column] } - if target_column != "fps": - trim_doc[ 'fps' ] = partial_doc[ 'fps' ] - trim_doc[ '/total_time' ] = partial_doc[ '/total_time' ] - trim_doc[ 'utc_time' ] = partial_doc[ 'utc_time' ] - full_doc.append(trim_doc) - - sourcefile.close() - return full_doc - -# Extract just the meta info line, and the timestamp of the first/last frame entry. -def parse_logfile_info(filename, verbose=False): - # Open source temp log file. Let exceptions percolate up. - sourcefile = open(filename, 'rU') # U is to open with Universal newline support - - if verbose: - print "Reading " + filename - - # The first line is the meta info line. - info_line = sourcefile.readline() - if not info_line: - sourcefile.close() - return None - - # The rest of the lines are frames. Read the first and last to get the time range. - info = llsd.parse( info_line ) - info['start_time'] = None - info['end_time'] = None - first_frame = sourcefile.readline() - if first_frame: - try: - info['start_time'] = int(llsd.parse(first_frame)['timestamp']) - except: - pass - - # Read the file backwards to find the last two lines. - sourcefile.seek(0, 2) - file_size = sourcefile.tell() - offset = 1024 - num_attempts = 0 - end_time = None - if file_size < offset: - offset = file_size - while 1: - sourcefile.seek(-1*offset, 2) - read_str = sourcefile.read(offset) - # Remove newline at the end - if read_str[offset - 1] == '\n': - read_str = read_str[0:-1] - lines = read_str.split('\n') - full_line = None - if len(lines) > 2: # Got two line - try: - end_time = llsd.parse(lines[-1])['timestamp'] - except: - # We couldn't parse this line. Try once more. - try: - end_time = llsd.parse(lines[-2])['timestamp'] - except: - # Nope. Just move on. - pass - break - if len(read_str) == file_size: # Reached the beginning - break - offset += 1024 - - info['end_time'] = int(end_time) - - sourcefile.close() - return info - - -def parse_proc_filename(filename): - try: - name_as_list = filename.split(".") - cur_stat_type = name_as_list[0].split("_")[0] - cur_pid = name_as_list[1] - except IndexError, ValueError: - return (None, None) - return (cur_pid, cur_stat_type) - -# ---------------------------------------------------- -def get_simstats_list(path=None): - """ Return stats (pid, type) listed in <type>_proc.<pid>.llsd """ - if path is None: - path = DEFAULT_PATH - simstats_list = [] - for file_name in os.listdir(path): - if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": - simstats_info = parse_logfile_info(path + file_name) - if simstats_info is not None: - simstats_list.append(simstats_info) - return simstats_list - -def get_log_info_list(pid=None, stat_type=None, path=None, target_column=None, verbose=False): - """ Return data from all llsd files matching the pid and stat type """ - if path is None: - path = DEFAULT_PATH - log_info_list = {} - for file_name in os.listdir ( path ): - if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": - (cur_pid, cur_stat_type) = parse_proc_filename(file_name) - if cur_pid is None: - continue - if pid is not None and pid != cur_pid: - continue - if stat_type is not None and stat_type != cur_stat_type: - continue - log_info_list[cur_pid] = parse_logfile(path + file_name, target_column, verbose) - return log_info_list - -def delete_simstats_files(pid=None, stat_type=None, path=None): - """ Delete *.<pid>.llsd files """ - if path is None: - path = DEFAULT_PATH - del_list = [] - for file_name in os.listdir(path): - if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": - (cur_pid, cur_stat_type) = parse_proc_filename(file_name) - if cur_pid is None: - continue - if pid is not None and pid != cur_pid: - continue - if stat_type is not None and stat_type != cur_stat_type: - continue - del_list.append(cur_pid) - # Allow delete related exceptions to percolate up if this fails. - os.unlink(os.path.join(DEFAULT_PATH, file_name)) - return del_list - diff --git a/indra/lib/python/indra/util/term.py b/indra/lib/python/indra/util/term.py deleted file mode 100755 index 8c316a1f12..0000000000 --- a/indra/lib/python/indra/util/term.py +++ /dev/null @@ -1,222 +0,0 @@ -''' -@file term.py -@brief a better shutil.copytree replacement - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -''' - -#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116 - -import sys, re - -class TerminalController: - """ - A class that can be used to portably generate formatted output to - a terminal. - - `TerminalController` defines a set of instance variables whose - values are initialized to the control sequence necessary to - perform a given action. These can be simply included in normal - output to the terminal: - - >>> term = TerminalController() - >>> print 'This is '+term.GREEN+'green'+term.NORMAL - - Alternatively, the `render()` method can used, which replaces - '${action}' with the string required to perform 'action': - - >>> term = TerminalController() - >>> print term.render('This is ${GREEN}green${NORMAL}') - - If the terminal doesn't support a given action, then the value of - the corresponding instance variable will be set to ''. As a - result, the above code will still work on terminals that do not - support color, except that their output will not be colored. - Also, this means that you can test whether the terminal supports a - given action by simply testing the truth value of the - corresponding instance variable: - - >>> term = TerminalController() - >>> if term.CLEAR_SCREEN: - ... print 'This terminal supports clearning the screen.' - - Finally, if the width and height of the terminal are known, then - they will be stored in the `COLS` and `LINES` attributes. - """ - # Cursor movement: - BOL = '' #: Move the cursor to the beginning of the line - UP = '' #: Move the cursor up one line - DOWN = '' #: Move the cursor down one line - LEFT = '' #: Move the cursor left one char - RIGHT = '' #: Move the cursor right one char - - # Deletion: - CLEAR_SCREEN = '' #: Clear the screen and move to home position - CLEAR_EOL = '' #: Clear to the end of the line. - CLEAR_BOL = '' #: Clear to the beginning of the line. - CLEAR_EOS = '' #: Clear to the end of the screen - - # Output modes: - BOLD = '' #: Turn on bold mode - BLINK = '' #: Turn on blink mode - DIM = '' #: Turn on half-bright mode - REVERSE = '' #: Turn on reverse-video mode - NORMAL = '' #: Turn off all modes - - # Cursor display: - HIDE_CURSOR = '' #: Make the cursor invisible - SHOW_CURSOR = '' #: Make the cursor visible - - # Terminal size: - COLS = None #: Width of the terminal (None for unknown) - LINES = None #: Height of the terminal (None for unknown) - - # Foreground colors: - BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = '' - - # Background colors: - BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = '' - BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = '' - - _STRING_CAPABILITIES = """ - BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1 - CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold - BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0 - HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split() - _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split() - _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split() - - def __init__(self, term_stream=sys.stdout): - """ - Create a `TerminalController` and initialize its attributes - with appropriate values for the current terminal. - `term_stream` is the stream that will be used for terminal - output; if this stream is not a tty, then the terminal is - assumed to be a dumb terminal (i.e., have no capabilities). - """ - # Curses isn't available on all platforms - try: import curses - except: return - - # If the stream isn't a tty, then assume it has no capabilities. - if not term_stream.isatty(): return - - # Check the terminal type. If we fail, then assume that the - # terminal has no capabilities. - try: curses.setupterm() - except: return - - # Look up numeric capabilities. - self.COLS = curses.tigetnum('cols') - self.LINES = curses.tigetnum('lines') - - # Look up string capabilities. - for capability in self._STRING_CAPABILITIES: - (attrib, cap_name) = capability.split('=') - setattr(self, attrib, self._tigetstr(cap_name) or '') - - # Colors - set_fg = self._tigetstr('setf') - if set_fg: - for i,color in zip(range(len(self._COLORS)), self._COLORS): - setattr(self, color, curses.tparm(set_fg, i) or '') - set_fg_ansi = self._tigetstr('setaf') - if set_fg_ansi: - for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): - setattr(self, color, curses.tparm(set_fg_ansi, i) or '') - set_bg = self._tigetstr('setb') - if set_bg: - for i,color in zip(range(len(self._COLORS)), self._COLORS): - setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '') - set_bg_ansi = self._tigetstr('setab') - if set_bg_ansi: - for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): - setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '') - - def _tigetstr(self, cap_name): - # String capabilities can include "delays" of the form "$<2>". - # For any modern terminal, we should be able to just ignore - # these, so strip them out. - import curses - cap = curses.tigetstr(cap_name) or '' - return re.sub(r'\$<\d+>[/*]?', '', cap) - - def render(self, template): - """ - Replace each $-substitutions in the given template string with - the corresponding terminal control string (if it's defined) or - '' (if it's not). - """ - return re.sub(r'\$\$|\${\w+}', self._render_sub, template) - - def _render_sub(self, match): - s = match.group() - if s == '$$': return s - else: return getattr(self, s[2:-1]) - -####################################################################### -# Example use case: progress bar -####################################################################### - -class ProgressBar: - """ - A 3-line progress bar, which looks like:: - - Header - 20% [===========----------------------------------] - progress message - - The progress bar is colored, if the terminal supports color - output; and adjusts to the width of the terminal. - """ - BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n' - HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n' - - def __init__(self, term, header): - self.term = term - if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL): - raise ValueError("Terminal isn't capable enough -- you " - "should use a simpler progress dispaly.") - self.width = self.term.COLS or 75 - self.bar = term.render(self.BAR) - self.header = self.term.render(self.HEADER % header.center(self.width)) - self.cleared = 1 #: true if we haven't drawn the bar yet. - self.update(0, '') - - def update(self, percent, message): - if self.cleared: - sys.stdout.write(self.header) - self.cleared = 0 - n = int((self.width-10)*percent) - sys.stdout.write( - self.term.BOL + self.term.UP + self.term.CLEAR_EOL + - (self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) + - self.term.CLEAR_EOL + message.center(self.width)) - - def clear(self): - if not self.cleared: - sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL + - self.term.UP + self.term.CLEAR_EOL + - self.term.UP + self.term.CLEAR_EOL) - self.cleared = 1 diff --git a/indra/lib/python/uuid.py b/indra/lib/python/uuid.py deleted file mode 100755 index e956383cca..0000000000 --- a/indra/lib/python/uuid.py +++ /dev/null @@ -1,508 +0,0 @@ -#!/usr/bin/python -## $LicenseInfo:firstyear=2011&license=viewerlgpl$ -## Second Life Viewer Source Code -## Copyright (C) 2011, Linden Research, Inc. -## -## This library is free software; you can redistribute it and/or -## modify it under the terms of the GNU Lesser General Public -## License as published by the Free Software Foundation; -## version 2.1 of the License only. -## -## This library is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## Lesser General Public License for more details. -## -## You should have received a copy of the GNU Lesser General Public -## License along with this library; if not, write to the Free Software -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -## -## Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -## $/LicenseInfo$ -r"""UUID objects (universally unique identifiers) according to RFC 4122. - -This module provides immutable UUID objects (class UUID) and the functions -uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5 -UUIDs as specified in RFC 4122. - -If all you want is a unique ID, you should probably call uuid1() or uuid4(). -Note that uuid1() may compromise privacy since it creates a UUID containing -the computer's network address. uuid4() creates a random UUID. - -Typical usage: - - >>> import uuid - - # make a UUID based on the host ID and current time - >>> uuid.uuid1() - UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') - - # make a UUID using an MD5 hash of a namespace UUID and a name - >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') - UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') - - # make a random UUID - >>> uuid.uuid4() - UUID('16fd2706-8baf-433b-82eb-8c7fada847da') - - # make a UUID using a SHA-1 hash of a namespace UUID and a name - >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') - UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') - - # make a UUID from a string of hex digits (braces and hyphens ignored) - >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') - - # convert a UUID to a string of hex digits in standard form - >>> str(x) - '00010203-0405-0607-0809-0a0b0c0d0e0f' - - # get the raw 16 bytes of the UUID - >>> x.bytes - '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' - - # make a UUID from a 16-byte string - >>> uuid.UUID(bytes=x.bytes) - UUID('00010203-0405-0607-0809-0a0b0c0d0e0f') - -This module works with Python 2.3 or higher.""" - -__author__ = 'Ka-Ping Yee <ping@zesty.ca>' -__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-') -__version__ = '$Revision: 1.30 $'.split()[1] - -RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ - 'reserved for NCS compatibility', 'specified in RFC 4122', - 'reserved for Microsoft compatibility', 'reserved for future definition'] - -class UUID(object): - """Instances of the UUID class represent UUIDs as specified in RFC 4122. - UUID objects are immutable, hashable, and usable as dictionary keys. - Converting a UUID to a string with str() yields something in the form - '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts - four possible forms: a similar string of hexadecimal digits, or a - string of 16 raw bytes as an argument named 'bytes', or a tuple of - six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and - 48-bit values respectively) as an argument named 'fields', or a single - 128-bit integer as an argument named 'int'. - - UUIDs have these read-only attributes: - - bytes the UUID as a 16-byte string - - fields a tuple of the six integer fields of the UUID, - which are also available as six individual attributes - and two derived attributes: - - time_low the first 32 bits of the UUID - time_mid the next 16 bits of the UUID - time_hi_version the next 16 bits of the UUID - clock_seq_hi_variant the next 8 bits of the UUID - clock_seq_low the next 8 bits of the UUID - node the last 48 bits of the UUID - - time the 60-bit timestamp - clock_seq the 14-bit sequence number - - hex the UUID as a 32-character hexadecimal string - - int the UUID as a 128-bit integer - - urn the UUID as a URN as specified in RFC 4122 - - variant the UUID variant (one of the constants RESERVED_NCS, - RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE) - - version the UUID version number (1 through 5, meaningful only - when the variant is RFC_4122) - """ - - def __init__(self, hex=None, bytes=None, fields=None, int=None, - version=None): - r"""Create a UUID from either a string of 32 hexadecimal digits, - a string of 16 bytes as the 'bytes' argument, a tuple of six - integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version, - 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as - the 'fields' argument, or a single 128-bit integer as the 'int' - argument. When a string of hex digits is given, curly braces, - hyphens, and a URN prefix are all optional. For example, these - expressions all yield the same UUID: - - UUID('{12345678-1234-5678-1234-567812345678}') - UUID('12345678123456781234567812345678') - UUID('urn:uuid:12345678-1234-5678-1234-567812345678') - UUID(bytes='\x12\x34\x56\x78'*4) - UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678)) - UUID(int=0x12345678123456781234567812345678) - - Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given. - The 'version' argument is optional; if given, the resulting UUID - will have its variant and version number set according to RFC 4122, - overriding bits in the given 'hex', 'bytes', 'fields', or 'int'. - """ - - if [hex, bytes, fields, int].count(None) != 3: - raise TypeError('need just one of hex, bytes, fields, or int') - if hex is not None: - hex = hex.replace('urn:', '').replace('uuid:', '') - hex = hex.strip('{}').replace('-', '') - if len(hex) != 32: - raise ValueError('badly formed hexadecimal UUID string') - int = long(hex, 16) - if bytes is not None: - if len(bytes) != 16: - raise ValueError('bytes is not a 16-char string') - int = long(('%02x'*16) % tuple(map(ord, bytes)), 16) - if fields is not None: - if len(fields) != 6: - raise ValueError('fields is not a 6-tuple') - (time_low, time_mid, time_hi_version, - clock_seq_hi_variant, clock_seq_low, node) = fields - if not 0 <= time_low < 1<<32L: - raise ValueError('field 1 out of range (need a 32-bit value)') - if not 0 <= time_mid < 1<<16L: - raise ValueError('field 2 out of range (need a 16-bit value)') - if not 0 <= time_hi_version < 1<<16L: - raise ValueError('field 3 out of range (need a 16-bit value)') - if not 0 <= clock_seq_hi_variant < 1<<8L: - raise ValueError('field 4 out of range (need an 8-bit value)') - if not 0 <= clock_seq_low < 1<<8L: - raise ValueError('field 5 out of range (need an 8-bit value)') - if not 0 <= node < 1<<48L: - raise ValueError('field 6 out of range (need a 48-bit value)') - clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low - int = ((time_low << 96L) | (time_mid << 80L) | - (time_hi_version << 64L) | (clock_seq << 48L) | node) - if int is not None: - if not 0 <= int < 1<<128L: - raise ValueError('int is out of range (need a 128-bit value)') - if version is not None: - if not 1 <= version <= 5: - raise ValueError('illegal version number') - # Set the variant to RFC 4122. - int &= ~(0xc000 << 48L) - int |= 0x8000 << 48L - # Set the version number. - int &= ~(0xf000 << 64L) - int |= version << 76L - self.__dict__['int'] = int - - def __cmp__(self, other): - if isinstance(other, UUID): - return cmp(self.int, other.int) - return NotImplemented - - def __hash__(self): - return hash(self.int) - - def __int__(self): - return self.int - - def __repr__(self): - return 'UUID(%r)' % str(self) - - def __setattr__(self, name, value): - raise TypeError('UUID objects are immutable') - - def __str__(self): - hex = '%032x' % self.int - return '%s-%s-%s-%s-%s' % ( - hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:]) - - def get_bytes(self): - bytes = '' - for shift in range(0, 128, 8): - bytes = chr((self.int >> shift) & 0xff) + bytes - return bytes - - bytes = property(get_bytes) - - def get_fields(self): - return (self.time_low, self.time_mid, self.time_hi_version, - self.clock_seq_hi_variant, self.clock_seq_low, self.node) - - fields = property(get_fields) - - def get_time_low(self): - return self.int >> 96L - - time_low = property(get_time_low) - - def get_time_mid(self): - return (self.int >> 80L) & 0xffff - - time_mid = property(get_time_mid) - - def get_time_hi_version(self): - return (self.int >> 64L) & 0xffff - - time_hi_version = property(get_time_hi_version) - - def get_clock_seq_hi_variant(self): - return (self.int >> 56L) & 0xff - - clock_seq_hi_variant = property(get_clock_seq_hi_variant) - - def get_clock_seq_low(self): - return (self.int >> 48L) & 0xff - - clock_seq_low = property(get_clock_seq_low) - - def get_time(self): - return (((self.time_hi_version & 0x0fffL) << 48L) | - (self.time_mid << 32L) | self.time_low) - - time = property(get_time) - - def get_clock_seq(self): - return (((self.clock_seq_hi_variant & 0x3fL) << 8L) | - self.clock_seq_low) - - clock_seq = property(get_clock_seq) - - def get_node(self): - return self.int & 0xffffffffffff - - node = property(get_node) - - def get_hex(self): - return '%032x' % self.int - - hex = property(get_hex) - - def get_urn(self): - return 'urn:uuid:' + str(self) - - urn = property(get_urn) - - def get_variant(self): - if not self.int & (0x8000 << 48L): - return RESERVED_NCS - elif not self.int & (0x4000 << 48L): - return RFC_4122 - elif not self.int & (0x2000 << 48L): - return RESERVED_MICROSOFT - else: - return RESERVED_FUTURE - - variant = property(get_variant) - - def get_version(self): - # The version bits are only meaningful for RFC 4122 UUIDs. - if self.variant == RFC_4122: - return int((self.int >> 76L) & 0xf) - - version = property(get_version) - -def _ifconfig_getnode(): - """Get the hardware address on Unix by running ifconfig.""" - import os - for dir in ['', '/sbin/', '/usr/sbin']: - try: - path = os.path.join(dir, 'ifconfig') - if os.path.exists(path): - pipe = os.popen(path) - else: - continue - except IOError: - continue - for line in pipe: - words = line.lower().split() - for i in range(len(words)): - if words[i] in ['hwaddr', 'ether']: - return int(words[i + 1].replace(':', ''), 16) - -def _ipconfig_getnode(): - """Get the hardware address on Windows by running ipconfig.exe.""" - import os, re - dirs = ['', r'c:\windows\system32', r'c:\winnt\system32'] - try: - import ctypes - buffer = ctypes.create_string_buffer(300) - ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300) - dirs.insert(0, buffer.value.decode('mbcs')) - except: - pass - for dir in dirs: - try: - pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all') - except IOError: - continue - for line in pipe: - value = line.split(':')[-1].strip().lower() - if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value): - return int(value.replace('-', ''), 16) - -def _netbios_getnode(): - """Get the hardware address on Windows using NetBIOS calls. - See http://support.microsoft.com/kb/118623 for details.""" - import win32wnet, netbios - ncb = netbios.NCB() - ncb.Command = netbios.NCBENUM - ncb.Buffer = adapters = netbios.LANA_ENUM() - adapters._pack() - if win32wnet.Netbios(ncb) != 0: - return - adapters._unpack() - for i in range(adapters.length): - ncb.Reset() - ncb.Command = netbios.NCBRESET - ncb.Lana_num = ord(adapters.lana[i]) - if win32wnet.Netbios(ncb) != 0: - continue - ncb.Reset() - ncb.Command = netbios.NCBASTAT - ncb.Lana_num = ord(adapters.lana[i]) - ncb.Callname = '*'.ljust(16) - ncb.Buffer = status = netbios.ADAPTER_STATUS() - if win32wnet.Netbios(ncb) != 0: - continue - status._unpack() - bytes = map(ord, status.adapter_address) - return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) + - (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5]) - -# Thanks to Thomas Heller for ctypes and for his help with its use here. - -# If ctypes is available, use it to find system routines for UUID generation. -_uuid_generate_random = _uuid_generate_time = _UuidCreate = None -try: - import ctypes, ctypes.util - _buffer = ctypes.create_string_buffer(16) - - # The uuid_generate_* routines are provided by libuuid on at least - # Linux and FreeBSD, and provided by libc on Mac OS X. - for libname in ['uuid', 'c']: - try: - lib = ctypes.CDLL(ctypes.util.find_library(libname)) - except: - continue - if hasattr(lib, 'uuid_generate_random'): - _uuid_generate_random = lib.uuid_generate_random - if hasattr(lib, 'uuid_generate_time'): - _uuid_generate_time = lib.uuid_generate_time - - # On Windows prior to 2000, UuidCreate gives a UUID containing the - # hardware address. On Windows 2000 and later, UuidCreate makes a - # random UUID and UuidCreateSequential gives a UUID containing the - # hardware address. These routines are provided by the RPC runtime. - try: - lib = ctypes.windll.rpcrt4 - except: - lib = None - _UuidCreate = getattr(lib, 'UuidCreateSequential', - getattr(lib, 'UuidCreate', None)) -except: - pass - -def _unixdll_getnode(): - """Get the hardware address on Unix using ctypes.""" - _uuid_generate_time(_buffer) - return UUID(bytes=_buffer.raw).node - -def _windll_getnode(): - """Get the hardware address on Windows using ctypes.""" - if _UuidCreate(_buffer) == 0: - return UUID(bytes=_buffer.raw).node - -def _random_getnode(): - """Get a random node ID, with eighth bit set as suggested by RFC 4122.""" - import random - return random.randrange(0, 1<<48L) | 0x010000000000L - -_node = None - -def getnode(): - """Get the hardware address as a 48-bit integer. The first time this - runs, it may launch a separate program, which could be quite slow. If - all attempts to obtain the hardware address fail, we choose a random - 48-bit number with its eighth bit set to 1 as recommended in RFC 4122.""" - - global _node - if _node is not None: - return _node - - import sys - if sys.platform == 'win32': - getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] - else: - getters = [_unixdll_getnode, _ifconfig_getnode] - - for getter in getters + [_random_getnode]: - try: - _node = getter() - except: - continue - if _node is not None: - return _node - -def uuid1(node=None, clock_seq=None): - """Generate a UUID from a host ID, sequence number, and the current time. - If 'node' is not given, getnode() is used to obtain the hardware - address. If 'clock_seq' is given, it is used as the sequence number; - otherwise a random 14-bit sequence number is chosen.""" - - # When the system provides a version-1 UUID generator, use it (but don't - # use UuidCreate here because its UUIDs don't conform to RFC 4122). - if _uuid_generate_time and node is clock_seq is None: - _uuid_generate_time(_buffer) - return UUID(bytes=_buffer.raw) - - import time - nanoseconds = int(time.time() * 1e9) - # 0x01b21dd213814000 is the number of 100-ns intervals between the - # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. - timestamp = int(nanoseconds/100) + 0x01b21dd213814000L - if clock_seq is None: - import random - clock_seq = random.randrange(1<<14L) # instead of stable storage - time_low = timestamp & 0xffffffffL - time_mid = (timestamp >> 32L) & 0xffffL - time_hi_version = (timestamp >> 48L) & 0x0fffL - clock_seq_low = clock_seq & 0xffL - clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL - if node is None: - node = getnode() - return UUID(fields=(time_low, time_mid, time_hi_version, - clock_seq_hi_variant, clock_seq_low, node), version=1) - -def uuid3(namespace, name): - """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" - try: - # Python 2.6 - from hashlib import md5 - except ImportError: - # Python 2.5 and earlier - from md5 import new as md5 - - hash = md5(namespace.bytes + name).digest() - return UUID(bytes=hash[:16], version=3) - -def uuid4(): - """Generate a random UUID.""" - - # When the system provides a version-4 UUID generator, use it. - if _uuid_generate_random: - _uuid_generate_random(_buffer) - return UUID(bytes=_buffer.raw) - - # Otherwise, get randomness from urandom or the 'random' module. - try: - import os - return UUID(bytes=os.urandom(16), version=4) - except: - import random - bytes = [chr(random.randrange(256)) for i in range(16)] - return UUID(bytes=bytes, version=4) - -def uuid5(namespace, name): - """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" - import sha - hash = sha.sha(namespace.bytes + name).digest() - return UUID(bytes=hash[:16], version=5) - -# The following standard UUIDs are for use with uuid3() or uuid5(). - -NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') -NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8') -NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') -NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index d1eb389013..94c431feb4 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -44,6 +44,7 @@ #include "lltexglobalcolor.h" #include "llwearabledata.h" #include "boost/bind.hpp" +#include "boost/tokenizer.hpp" #if LL_MSVC @@ -87,8 +88,11 @@ public: private: std::string mName; + std::string mSupport; + std::string mAliases; BOOL mIsJoint; LLVector3 mPos; + LLVector3 mEnd; LLVector3 mRot; LLVector3 mScale; LLVector3 mPivot; @@ -118,6 +122,7 @@ public: private: S32 mNumBones; S32 mNumCollisionVolumes; + LLAvatarAppearance::joint_alias_map_t mJointAliasMap; typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t; bone_info_list_t mBoneInfoList; }; @@ -181,7 +186,11 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mPelvisToFoot(0.f), mHeadOffset(), mRoot(NULL), - mWearableData(wearable_data) + mWearableData(wearable_data), + mNumBones(0), + mNumCollisionVolumes(0), + mCollisionVolumes(NULL), + mIsBuilt(FALSE) { llassert_always(mWearableData); mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES); @@ -194,11 +203,6 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mBakedTextureDatas[i].mMaskTexName = 0; mBakedTextureDatas[i].mTextureIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i); } - - mIsBuilt = FALSE; - - mNumCollisionVolumes = 0; - mCollisionVolumes = NULL; } // virtual @@ -323,36 +327,49 @@ LLAvatarAppearance::~LLAvatarAppearance() //static void LLAvatarAppearance::initClass() { - std::string xmlFile; + initClass("",""); +} - xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml"; - BOOL success = sXMLTree.parseFile( xmlFile, FALSE ); +//static +void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, const std::string& skeleton_file_name_arg) +{ + std::string avatar_file_name; + + if (!avatar_file_name_arg.empty()) + { + avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,avatar_file_name_arg); + } + else + { + avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR + "_lad.xml"); + } + BOOL success = sXMLTree.parseFile( avatar_file_name, FALSE ); if (!success) { - LL_ERRS() << "Problem reading avatar configuration file:" << xmlFile << LL_ENDL; + LL_ERRS() << "Problem reading avatar configuration file:" << avatar_file_name << LL_ENDL; } // now sanity check xml file LLXmlTreeNode* root = sXMLTree.getRoot(); if (!root) { - LL_ERRS() << "No root node found in avatar configuration file: " << xmlFile << LL_ENDL; + LL_ERRS() << "No root node found in avatar configuration file: " << avatar_file_name << LL_ENDL; return; } //------------------------------------------------------------------------- - // <linden_avatar version="1.0"> (root) + // <linden_avatar version="2.0"> (root) //------------------------------------------------------------------------- if( !root->hasName( "linden_avatar" ) ) { - LL_ERRS() << "Invalid avatar file header: " << xmlFile << LL_ENDL; + LL_ERRS() << "Invalid avatar file header: " << avatar_file_name << LL_ENDL; } std::string version; static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); - if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) + if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0"))) { - LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << xmlFile << LL_ENDL; + LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << avatar_file_name << LL_ENDL; } S32 wearable_def_version = 1; @@ -365,16 +382,19 @@ void LLAvatarAppearance::initClass() LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" ); if (!skeleton_node) { - LL_ERRS() << "No skeleton in avatar configuration file: " << xmlFile << LL_ENDL; + LL_ERRS() << "No skeleton in avatar configuration file: " << avatar_file_name << LL_ENDL; return; } - - std::string skeleton_file_name; - static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); - if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name)) - { - LL_ERRS() << "No file name in skeleton node in avatar config file: " << xmlFile << LL_ENDL; - } + + std::string skeleton_file_name = skeleton_file_name_arg; + if (skeleton_file_name.empty()) + { + static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); + if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name)) + { + LL_ERRS() << "No file name in skeleton node in avatar config file: " << avatar_file_name << LL_ENDL; + } + } std::string skeleton_path; skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name); @@ -437,11 +457,56 @@ void LLAvatarAppearance::cleanupClass() using namespace LLAvatarAppearanceDefines; +void LLAvatarAppearance::compareJointStateMaps(joint_state_map_t& last_state, + joint_state_map_t& curr_state) +{ + if (!last_state.empty() && (last_state != curr_state)) + { + S32 diff_count = 0; + joint_state_map_t::iterator it; + for (it=last_state.begin(); it != last_state.end(); ++it) + { + const std::string& key = it->first; + if (last_state[key] != curr_state[key]) + { + LL_DEBUGS("AvatarBodySize") << "BodySize change " << key << " " << last_state[key] << "->" << curr_state[key] << LL_ENDL; + diff_count++; + } + } + if (diff_count > 0) + { + LL_DEBUGS("AvatarBodySize") << "Total of BodySize changes " << diff_count << LL_ENDL; + } + + } +} + //------------------------------------------------------------------------ // The viewer can only suggest a good size for the agent, // the simulator will keep it inside a reasonable range. void LLAvatarAppearance::computeBodySize() { + mLastBodySizeState = mCurrBodySizeState; + + mCurrBodySizeState["mPelvis scale"] = mPelvisp->getScale(); + mCurrBodySizeState["mSkull pos"] = mSkullp->getPosition(); + mCurrBodySizeState["mSkull scale"] = mSkullp->getScale(); + mCurrBodySizeState["mNeck pos"] = mNeckp->getPosition(); + mCurrBodySizeState["mNeck scale"] = mNeckp->getScale(); + mCurrBodySizeState["mChest pos"] = mChestp->getPosition(); + mCurrBodySizeState["mChest scale"] = mChestp->getScale(); + mCurrBodySizeState["mHead pos"] = mHeadp->getPosition(); + mCurrBodySizeState["mHead scale"] = mHeadp->getScale(); + mCurrBodySizeState["mTorso pos"] = mTorsop->getPosition(); + mCurrBodySizeState["mTorso scale"] = mTorsop->getScale(); + mCurrBodySizeState["mHipLeft pos"] = mHipLeftp->getPosition(); + mCurrBodySizeState["mHipLeft scale"] = mHipLeftp->getScale(); + mCurrBodySizeState["mKneeLeft pos"] = mKneeLeftp->getPosition(); + mCurrBodySizeState["mKneeLeft scale"] = mKneeLeftp->getScale(); + mCurrBodySizeState["mAnkleLeft pos"] = mAnkleLeftp->getPosition(); + mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale(); + mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition(); + LLVector3 pelvis_scale = mPelvisp->getScale(); // some of the joints have not been cached @@ -501,6 +566,8 @@ void LLAvatarAppearance::computeBodySize() if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ]) { mBodySize = new_body_size; + + compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState); } } @@ -536,7 +603,7 @@ BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename) std::string version; static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); - if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) + if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0"))) { LL_ERRS() << "Invalid avatar skeleton file version: " << version << " in file: " << filename << LL_ENDL; return FALSE; @@ -552,6 +619,12 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent { LLJoint* joint = NULL; + LL_DEBUGS("BVH") << "bone info: name " << info->mName + << " isJoint " << info->mIsJoint + << " volume_num " << volume_num + << " joint_num " << joint_num + << LL_ENDL; + if (info->mIsJoint) { joint = getCharacterJoint(joint_num); @@ -566,7 +639,7 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent { if (volume_num >= (S32)mNumCollisionVolumes) { - LL_WARNS() << "Too many bones" << LL_ENDL; + LL_WARNS() << "Too many collision volumes" << LL_ENDL; return FALSE; } joint = (&mCollisionVolumes[volume_num]); @@ -574,26 +647,34 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent } // add to parent - if (parent) + if (parent && (joint->getParent()!=parent)) { parent->addChild( joint ); } + // SL-315 joint->setPosition(info->mPos); + joint->setDefaultPosition(info->mPos); joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY], info->mRot.mV[VZ], LLQuaternion::XYZ)); joint->setScale(info->mScale); + joint->setDefaultScale(info->mScale); + joint->setSupport(info->mSupport); + joint->setEnd(info->mEnd); if (info->mIsJoint) { joint->setSkinOffset( info->mPivot ); + joint->setJointNum(joint_num); joint_num++; } else // collision volume { + joint->setJointNum(mNumBones+volume_num); volume_num++; } + // setup children LLAvatarBoneInfo::child_list_t::const_iterator iter; for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter) @@ -613,12 +694,12 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent //----------------------------------------------------------------------------- BOOL LLAvatarAppearance::allocateCharacterJoints( U32 num ) { - clearSkeleton(); - - for(S32 joint_num = 0; joint_num < (S32)num; joint_num++) - { - mSkeleton.push_back(createAvatarJoint(joint_num)); - } + if (mSkeleton.size() != num) + { + clearSkeleton(); + mSkeleton = avatar_joint_list_t(num,NULL); + mNumBones = num; + } return TRUE; } @@ -629,18 +710,16 @@ BOOL LLAvatarAppearance::allocateCharacterJoints( U32 num ) //----------------------------------------------------------------------------- BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) { - //------------------------------------------------------------------------- + LL_DEBUGS("BVH") << "numBones " << info->mNumBones << " numCollisionVolumes " << info->mNumCollisionVolumes << LL_ENDL; + // allocate joints - //------------------------------------------------------------------------- if (!allocateCharacterJoints(info->mNumBones)) { LL_ERRS() << "Can't allocate " << info->mNumBones << " joints" << LL_ENDL; return FALSE; } - //------------------------------------------------------------------------- // allocate volumes - //------------------------------------------------------------------------- if (info->mNumCollisionVolumes) { if (!allocateCollisionVolumes(info->mNumCollisionVolumes)) @@ -655,8 +734,8 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter) { - LLAvatarBoneInfo *info = *iter; - if (!setupBone(info, NULL, current_volume_num, current_joint_num)) + LLAvatarBoneInfo *bone_info = *iter; + if (!setupBone(bone_info, NULL, current_volume_num, current_joint_num)) { LL_ERRS() << "Error parsing bone in skeleton file" << LL_ENDL; return FALSE; @@ -820,6 +899,7 @@ void LLAvatarAppearance::buildCharacter() //------------------------------------------------------------------------- // initialize the pelvis //------------------------------------------------------------------------- + // SL-315 mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) ); mIsBuilt = TRUE; @@ -834,21 +914,21 @@ BOOL LLAvatarAppearance::loadAvatar() // avatar_skeleton.xml if( !buildSkeleton(sAvatarSkeletonInfo) ) { - LL_WARNS() << "avatar file: buildSkeleton() failed" << LL_ENDL; + LL_ERRS() << "avatar file: buildSkeleton() failed" << LL_ENDL; return FALSE; } // avatar_lad.xml : <skeleton> if( !loadSkeletonNode() ) { - LL_WARNS() << "avatar file: loadNodeSkeleton() failed" << LL_ENDL; + LL_ERRS() << "avatar file: loadNodeSkeleton() failed" << LL_ENDL; return FALSE; } // avatar_lad.xml : <mesh> if( !loadMeshNodes() ) { - LL_WARNS() << "avatar file: loadNodeMesh() failed" << LL_ENDL; + LL_ERRS() << "avatar file: loadNodeMesh() failed" << LL_ENDL; return FALSE; } @@ -858,13 +938,13 @@ BOOL LLAvatarAppearance::loadAvatar() mTexSkinColor = new LLTexGlobalColor( this ); if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) ) { - LL_WARNS() << "avatar file: mTexSkinColor->setInfo() failed" << LL_ENDL; + LL_ERRS() << "avatar file: mTexSkinColor->setInfo() failed" << LL_ENDL; return FALSE; } } else { - LL_WARNS() << "<global_color> name=\"skin_color\" not found" << LL_ENDL; + LL_ERRS() << "<global_color> name=\"skin_color\" not found" << LL_ENDL; return FALSE; } if( sAvatarXmlInfo->mTexHairColorInfo ) @@ -872,13 +952,13 @@ BOOL LLAvatarAppearance::loadAvatar() mTexHairColor = new LLTexGlobalColor( this ); if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) ) { - LL_WARNS() << "avatar file: mTexHairColor->setInfo() failed" << LL_ENDL; + LL_ERRS() << "avatar file: mTexHairColor->setInfo() failed" << LL_ENDL; return FALSE; } } else { - LL_WARNS() << "<global_color> name=\"hair_color\" not found" << LL_ENDL; + LL_ERRS() << "<global_color> name=\"hair_color\" not found" << LL_ENDL; return FALSE; } if( sAvatarXmlInfo->mTexEyeColorInfo ) @@ -886,26 +966,26 @@ BOOL LLAvatarAppearance::loadAvatar() mTexEyeColor = new LLTexGlobalColor( this ); if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) ) { - LL_WARNS() << "avatar file: mTexEyeColor->setInfo() failed" << LL_ENDL; + LL_ERRS() << "avatar file: mTexEyeColor->setInfo() failed" << LL_ENDL; return FALSE; } } else { - LL_WARNS() << "<global_color> name=\"eye_color\" not found" << LL_ENDL; + LL_ERRS() << "<global_color> name=\"eye_color\" not found" << LL_ENDL; return FALSE; } // avatar_lad.xml : <layer_set> if (sAvatarXmlInfo->mLayerInfoList.empty()) { - LL_WARNS() << "avatar file: missing <layer_set> node" << LL_ENDL; + LL_ERRS() << "avatar file: missing <layer_set> node" << LL_ENDL; return FALSE; } if (sAvatarXmlInfo->mMorphMaskInfoList.empty()) { - LL_WARNS() << "avatar file: missing <morph_masks> node" << LL_ENDL; + LL_ERRS() << "avatar file: missing <morph_masks> node" << LL_ENDL; return FALSE; } @@ -1104,6 +1184,7 @@ BOOL LLAvatarAppearance::loadMeshNodes() { // This should never happen LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL; + return FALSE; } } else @@ -1240,6 +1321,10 @@ LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num ) { return NULL; } + if (!mSkeleton[num]) + { + mSkeleton[num] = createAvatarJoint(); + } return mSkeleton[num]; } @@ -1476,16 +1561,19 @@ LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_in //----------------------------------------------------------------------------- BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num ) { - delete_and_clear_array(mCollisionVolumes); - mNumCollisionVolumes = 0; - - mCollisionVolumes = new LLAvatarJointCollisionVolume[num]; - if (!mCollisionVolumes) - { - return FALSE; - } - - mNumCollisionVolumes = num; + if (mNumCollisionVolumes !=num) + { + delete_and_clear_array(mCollisionVolumes); + mNumCollisionVolumes = 0; + + mCollisionVolumes = new LLAvatarJointCollisionVolume[num]; + if (!mCollisionVolumes) + { + return FALSE; + } + + mNumCollisionVolumes = num; + } return TRUE; } @@ -1503,6 +1591,9 @@ BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node) LL_WARNS() << "Bone without name" << LL_ENDL; return FALSE; } + + static LLStdStringHandle aliases_string = LLXmlTree::addAttributeString("aliases"); + node->getFastAttributeString(aliases_string, mAliases ); //Aliases are not required. } else if (node->hasName("collision_volume")) { @@ -1540,6 +1631,20 @@ BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node) return FALSE; } + static LLStdStringHandle end_string = LLXmlTree::addAttributeString("end"); + if (!node->getFastAttributeVector3(end_string, mEnd)) + { + LL_WARNS() << "Bone without end " << mName << LL_ENDL; + mEnd = LLVector3(0.0f, 0.0f, 0.0f); + } + + static LLStdStringHandle support_string = LLXmlTree::addAttributeString("support"); + if (!node->getFastAttributeString(support_string,mSupport)) + { + LL_WARNS() << "Bone without support " << mName << LL_ENDL; + mSupport = "base"; + } + if (mIsJoint) { static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot"); @@ -1595,6 +1700,54 @@ BOOL LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) return TRUE; } +//Make aliases for joint and push to map. +void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info) +{ + if (! bone_info->mIsJoint ) + { + return; + } + + std::string bone_name = bone_info->mName; + mJointAliasMap[bone_name] = bone_name; //Actual name is a valid alias. + + std::string aliases = bone_info->mAliases; + + boost::char_separator<char> sep(" "); + boost::tokenizer<boost::char_separator<char> > tok(aliases, sep); + for(boost::tokenizer<boost::char_separator<char> >::iterator i = tok.begin(); i != tok.end(); ++i) + { + if ( mJointAliasMap.find(*i) != mJointAliasMap.end() ) + { + LL_WARNS() << "avatar skeleton: Joint alias \"" << *i << "\" remapped from " << mJointAliasMap[*i] << " to " << bone_name << LL_ENDL; + } + mJointAliasMap[*i] = bone_name; + } + + LLAvatarBoneInfo::child_list_t::const_iterator iter; + for (iter = bone_info->mChildList.begin(); iter != bone_info->mChildList.end(); ++iter) + { + makeJointAliases( *iter ); + } +} + +const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases () +{ + LLAvatarAppearance::joint_alias_map_t alias_map; + if (mJointAliasMap.empty()) + { + + LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; + for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin(); iter != sAvatarSkeletonInfo->mBoneInfoList.end(); ++iter) + { + //LLAvatarBoneInfo *bone_info = *iter; + makeJointAliases( *iter ); + } + } + + return mJointAliasMap; +} + //----------------------------------------------------------------------------- // parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree @@ -1625,7 +1778,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro { LL_WARNS() << "Unknown param type." << LL_ENDL; } - continue; + return FALSE; } LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo; @@ -1650,7 +1803,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro { LL_WARNS() << "No name supplied for attachment point." << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint"); @@ -1658,7 +1811,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro { LL_WARNS() << "No bone declared in attachment point " << info->mName << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position"); @@ -1684,7 +1837,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro { LL_WARNS() << "No id supplied for attachment point " << info->mName << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice"); @@ -1770,7 +1923,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) { LL_WARNS() << "Unknown param type." << LL_ENDL; } - continue; + return FALSE; } LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo(); @@ -1931,7 +2084,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root { LL_WARNS() << "No name supplied for morph mask." << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region"); @@ -1939,7 +2092,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root { LL_WARNS() << "No region supplied for morph mask." << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer"); @@ -1947,7 +2100,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root { LL_WARNS() << "No layer supplied for morph mask." << LL_ENDL; delete info; - continue; + return FALSE; } // optional parameter. don't throw a warning if not present. diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index a0ef49b7cb..ccd6323ed8 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -66,7 +66,8 @@ public: LLAvatarAppearance(LLWearableData* wearable_data); virtual ~LLAvatarAppearance(); - static void initClass(); // initializes static members + static void initClass(const std::string& avatar_file_name, const std::string& skeleton_file_name); // initializes static members + static void initClass(); static void cleanupClass(); // Cleanup data that's only init'd once per class. virtual void initInstance(); // Called after construction to initialize the instance. virtual BOOL loadSkeletonNode(); @@ -124,8 +125,11 @@ public: protected: virtual LLAvatarJoint* createAvatarJoint() = 0; - virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 0; + virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 0; virtual LLAvatarJointMesh* createAvatarJointMesh() = 0; + void makeJointAliases(LLAvatarBoneInfo *bone_info); + + public: F32 getPelvisToFoot() const { return mPelvisToFoot; } /*virtual*/ LLJoint* getRootJoint() { return mRoot; } @@ -135,9 +139,20 @@ public: typedef std::map<std::string, LLJoint*> joint_map_t; joint_map_t mJointMap; - + + typedef std::map<std::string, LLVector3> joint_state_map_t; + joint_state_map_t mLastBodySizeState; + joint_state_map_t mCurrBodySizeState; + void compareJointStateMaps(joint_state_map_t& last_state, + joint_state_map_t& curr_state); void computeBodySize(); +public: + typedef std::vector<LLAvatarJoint*> avatar_joint_list_t; + const avatar_joint_list_t& getSkeleton() { return mSkeleton; } + typedef std::map<std::string, std::string> joint_alias_map_t; + const joint_alias_map_t& getJointAliases(); + protected: static BOOL parseSkeletonFile(const std::string& filename); @@ -147,12 +162,12 @@ protected: BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); BOOL allocateCharacterJoints(U32 num); BOOL buildSkeleton(const LLAvatarSkeletonInfo *info); -protected: + void clearSkeleton(); BOOL mIsBuilt; // state of deferred character building - typedef std::vector<LLAvatarJoint*> avatar_joint_list_t; avatar_joint_list_t mSkeleton; - LLPosOverrideMap mPelvisFixups; + LLVector3OverrideMap mPelvisFixups; + joint_alias_map_t mJointAliasMap; //-------------------------------------------------------------------- // Pelvis height adjustment members. @@ -335,6 +350,7 @@ protected: // Collision volumes //-------------------------------------------------------------------- public: + S32 mNumBones; S32 mNumCollisionVolumes; LLAvatarJointCollisionVolume* mCollisionVolumes; protected: diff --git a/indra/llappearance/llavatarjoint.cpp b/indra/llappearance/llavatarjoint.cpp index 2ee3c65a01..29642be099 100644 --- a/indra/llappearance/llavatarjoint.cpp +++ b/indra/llappearance/llavatarjoint.cpp @@ -52,19 +52,18 @@ LLAvatarJoint::LLAvatarJoint() : init(); } -LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) : - LLJoint(name, parent) +LLAvatarJoint::LLAvatarJoint(S32 joint_num) : + LLJoint(joint_num) { - init(); + init(); } - -LLAvatarJoint::LLAvatarJoint(S32 joint_num) : - LLJoint(joint_num) + +LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) : + LLJoint(name, parent) { init(); } - void LLAvatarJoint::init() { mValid = FALSE; diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp index 520ad775db..7ca0928171 100644 --- a/indra/llappearance/llavatarjointmesh.cpp +++ b/indra/llappearance/llavatarjointmesh.cpp @@ -33,22 +33,7 @@ #include "llavatarjointmesh.h" #include "llavatarappearance.h" -//#include "llapr.h" -//#include "llbox.h" -//#include "lldrawable.h" -//#include "lldrawpoolavatar.h" -//#include "lldrawpoolbump.h" -//#include "lldynamictexture.h" -//#include "llface.h" -//#include "llgldbg.h" -//#include "llglheaders.h" #include "lltexlayer.h" -//#include "llviewercamera.h" -//#include "llviewercontrol.h" -//#include "llviewertexturelist.h" -//#include "llsky.h" -//#include "pipeline.h" -//#include "llviewershadermgr.h" #include "llmath.h" #include "v4math.h" #include "m3math.h" @@ -56,6 +41,41 @@ #include "llmatrix4a.h" +// Utility functions added with Bento to simplify handling of extra +// spine joints, or other new joints internal to the original +// skeleton, and unknown to the system avatar. + +//----------------------------------------------------------------------------- +// getBaseSkeletonAncestor() +//----------------------------------------------------------------------------- +LLAvatarJoint *getBaseSkeletonAncestor(LLAvatarJoint* joint) +{ + LLJoint *ancestor = joint->getParent(); + while (ancestor->getParent() && (ancestor->getSupport() != LLJoint::SUPPORT_BASE)) + { + LL_DEBUGS("Avatar") << "skipping non-base ancestor " << ancestor->getName() << LL_ENDL; + ancestor = ancestor->getParent(); + } + return (LLAvatarJoint*) ancestor; +} + +//----------------------------------------------------------------------------- +// totalSkinOffset() +//----------------------------------------------------------------------------- +LLVector3 totalSkinOffset(LLAvatarJoint *joint) +{ + LLVector3 totalOffset; + while (joint) + { + if (joint->getSupport() == LLJoint::SUPPORT_BASE) + { + totalOffset += joint->getSkinOffset(); + } + joint = (LLAvatarJoint*)joint->getParent(); + } + return totalOffset; +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // LLAvatarJointMesh::LLSkinJoint @@ -92,18 +112,12 @@ BOOL LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint) } // compute the inverse root skin matrix - mRootToJointSkinOffset.clearVec(); - - LLVector3 rootSkinOffset; - while (joint) - { - rootSkinOffset += joint->getSkinOffset(); - joint = (LLAvatarJoint*)joint->getParent(); - } + mRootToJointSkinOffset = totalSkinOffset(joint); + mRootToJointSkinOffset = -mRootToJointSkinOffset; - mRootToJointSkinOffset = -rootSkinOffset; - mRootToParentJointSkinOffset = mRootToJointSkinOffset; - mRootToParentJointSkinOffset += mJoint->getSkinOffset(); + //mRootToParentJointSkinOffset = totalSkinOffset((LLAvatarJoint*)joint->getParent()); + mRootToParentJointSkinOffset = totalSkinOffset(getBaseSkeletonAncestor(joint)); + mRootToParentJointSkinOffset = -mRootToParentJointSkinOffset; return TRUE; } @@ -289,6 +303,7 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh ) } // acquire the transform from the mesh object + // SL-315 setPosition( mMesh->getPosition() ); setRotation( mMesh->getRotation() ); setScale( mMesh->getScale() ); @@ -314,9 +329,9 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh ) if (!mMesh->isLOD()) { setupJoint((LLAvatarJoint*)getRoot()); + LL_DEBUGS("Avatar") << getName() << " joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL; } - LL_DEBUGS() << "joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL; } //----------------------------------------------------------------------------- @@ -324,9 +339,6 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh ) //----------------------------------------------------------------------------- void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint) { - LL_DEBUGS() << "Mesh: " << getName() << LL_ENDL; - - S32 joint_count = 0; U32 sj; for (sj=0; sj<mNumSkinJoints; sj++) @@ -339,22 +351,30 @@ void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint) } // we've found a skinjoint for this joint.. + LL_DEBUGS("Avatar") << "Mesh: " << getName() << " joint " << current_joint->getName() << " matches skinjoint " << sj << LL_ENDL; // is the last joint in the array our parent? - if(mMesh->mJointRenderData.size() && mMesh->mJointRenderData[mMesh->mJointRenderData.size() - 1]->mWorldMatrix == ¤t_joint->getParent()->getWorldMatrix()) + + std::vector<LLJointRenderData*> &jrd = mMesh->mJointRenderData; + + // SL-287 - need to update this so the results are the same if + // additional extended-skeleton joints lie between this joint + // and the original parent. + LLJoint *ancestor = getBaseSkeletonAncestor(current_joint); + if(jrd.size() && jrd.back()->mWorldMatrix == &ancestor->getWorldMatrix()) { // ...then just add ourselves LLAvatarJoint* jointp = js.mJoint; - mMesh->mJointRenderData.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js)); - LL_DEBUGS() << "joint " << joint_count++ << js.mJoint->getName() << LL_ENDL; + jrd.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js)); + LL_DEBUGS("Avatar") << "add joint[" << (jrd.size()-1) << "] = " << js.mJoint->getName() << LL_ENDL; } - // otherwise add our parent and ourselves + // otherwise add our ancestor and ourselves else { - mMesh->mJointRenderData.push_back(new LLJointRenderData(¤t_joint->getParent()->getWorldMatrix(), NULL)); - LL_DEBUGS() << "joint " << joint_count++ << current_joint->getParent()->getName() << LL_ENDL; - mMesh->mJointRenderData.push_back(new LLJointRenderData(¤t_joint->getWorldMatrix(), &js)); - LL_DEBUGS() << "joint " << joint_count++ << current_joint->getName() << LL_ENDL; + jrd.push_back(new LLJointRenderData(&ancestor->getWorldMatrix(), NULL)); + LL_DEBUGS("Avatar") << "add2 ancestor joint[" << (jrd.size()-1) << "] = " << ancestor->getName() << LL_ENDL; + jrd.push_back(new LLJointRenderData(¤t_joint->getWorldMatrix(), &js)); + LL_DEBUGS("Avatar") << "add2 joint[" << (jrd.size()-1) << "] = " << current_joint->getName() << LL_ENDL; } } diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index e630c1118b..e5e502b158 100644 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -110,6 +110,14 @@ void LLDriverParamInfo::toStream(std::ostream &out) out << std::endl; + // FIXME - this mDriverParam backlink makes no sense, because the + // LLDriverParamInfos are static objects - there's only one copy + // for each param type, so the backlink will just reference the + // corresponding param in the most recently created + // avatar. Apparently these toStream() methods are not currently + // used anywhere, so it's not an urgent problem. + LL_WARNS_ONCE() << "Invalid usage of mDriverParam." << LL_ENDL; + if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() && mDriverParam->getAvatarAppearance()->isValid()) { diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h index f71c930e5e..f278dcc2e2 100644 --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -128,6 +128,10 @@ public: S32 getDrivenParamsCount() const; const LLViewerVisualParam* getDrivenParam(S32 index) const; + typedef std::vector<LLDrivenEntry> entry_list_t; + entry_list_t& getDrivenList() { return mDriven; } + void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; } + protected: LLDriverParam(const LLDriverParam& pOther); F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); @@ -135,7 +139,6 @@ protected: LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder - typedef std::vector<LLDrivenEntry> entry_list_t; entry_list_t mDriven; LLViewerVisualParam* mCurrentDistortionParam; // Backlink only; don't make this an LLPointer. diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index e3992a080e..2cb4c65d7c 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -369,7 +369,8 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) { if (avatarp->mCollisionVolumes[i].getName() == volume_info->mName) { - mVolumeMorphs.push_back(LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i], + mVolumeMorphs.push_back( + LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i], volume_info->mScale, volume_info->mPos)); break; @@ -647,6 +648,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) LLVector3 pos_delta = volume_morph->mPos * delta_weight; volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); + // SL-315 volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); } } @@ -730,6 +732,20 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3 apply(mLastSex); } +void LLPolyMorphTarget::applyVolumeChanges(F32 delta_weight) +{ + // now apply volume changes + for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ ) + { + LLPolyVolumeMorph* volume_morph = &(*iter); + LLVector3 scale_delta = volume_morph->mScale * delta_weight; + LLVector3 pos_delta = volume_morph->mPos * delta_weight; + + volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); + // SL-315 + volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); + } +} //----------------------------------------------------------------------------- // LLPolyVertexMask() diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h index 3c2c68079c..c6133cd831 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -182,6 +182,8 @@ public: void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); void addPendingMorphMask() { mNumMorphMasksPending++; } + void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton() + void* operator new(size_t size) { return ll_aligned_malloc_16(size); diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp index fbc312c426..5b77a7433a 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -34,6 +34,7 @@ #include "llpolymorph.h" #include "llwearable.h" #include "llfasttimer.h" +#include "llcallstack.h" #include "llpolyskeletaldistortion.h" @@ -134,55 +135,49 @@ LLPolySkeletalDistortion::~LLPolySkeletalDistortion() BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) { - llassert(mInfo == NULL); - if (info->mID < 0) - return FALSE; - mInfo = info; - mID = info->mID; - setWeight(getDefaultWeight()); - - LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; - for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) + if (info->mID < 0) + { + return FALSE; + } + mInfo = info; + mID = info->mID; + setWeight(getDefaultWeight()); + + LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; + for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) + { + LLPolySkeletalBoneInfo *bone_info = &(*iter); + LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); + if (!joint) { - LLPolySkeletalBoneInfo *bone_info = &(*iter); - LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); - if (!joint) - { - LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL; - continue; - } - - if (mJointScales.find(joint) != mJointScales.end()) - { - LL_WARNS() << "Scale deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; - } + // There's no point continuing after this error - means + // that either the skeleton or lad file is broken. + LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL; + return FALSE; + } - // store it - mJointScales[joint] = bone_info->mScaleDeformation; + // store it + mJointScales[joint] = bone_info->mScaleDeformation; - // apply to children that need to inherit it - for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); - iter != joint->mChildren.end(); ++iter) - { - LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); - if (child_joint->inheritScale()) - { - LLVector3 childDeformation = LLVector3(child_joint->getScale()); - childDeformation.scaleVec(bone_info->mScaleDeformation); - mJointScales[child_joint] = childDeformation; - } - } + // apply to children that need to inherit it + for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); + iter != joint->mChildren.end(); ++iter) + { + LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); + if (child_joint->inheritScale()) + { + LLVector3 childDeformation = LLVector3(child_joint->getScale()); + childDeformation.scaleVec(bone_info->mScaleDeformation); + mJointScales[child_joint] = childDeformation; + } + } - if (bone_info->mHasPositionDeformation) - { - if (mJointOffsets.find(joint) != mJointOffsets.end()) - { - LL_WARNS() << "Offset deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; - } - mJointOffsets[joint] = bone_info->mPositionDeformation; - } + if (bone_info->mHasPositionDeformation) + { + mJointOffsets[joint] = bone_info->mPositionDeformation; } - return TRUE; + } + return TRUE; } /*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const @@ -197,42 +192,52 @@ static LLTrace::BlockTimerStatHandle FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { - LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY); - - F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); - - LLJoint* joint; - joint_vec_map_t::iterator iter; - - for (iter = mJointScales.begin(); - iter != mJointScales.end(); - iter++) - { - joint = iter->first; - LLVector3 newScale = joint->getScale(); - LLVector3 scaleDelta = iter->second; - newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); - //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached - // needed? // joint->storeScaleForReset( newScale ); - joint->setScale(newScale); - } - - for (iter = mJointOffsets.begin(); - iter != mJointOffsets.end(); - iter++) - { - joint = iter->first; - LLVector3 newPosition = joint->getPosition(); - LLVector3 positionDelta = iter->second; - newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); - joint->setPosition(newPosition); - } - - if (mLastWeight != mCurWeight && !mIsAnimating) - { - mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); - } - mLastWeight = mCurWeight; + LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY); + + F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); + + LLJoint* joint; + joint_vec_map_t::iterator iter; + + for (iter = mJointScales.begin(); + iter != mJointScales.end(); + iter++) + { + joint = iter->first; + LLVector3 newScale = joint->getScale(); + LLVector3 scaleDelta = iter->second; + LLVector3 offset = (effective_weight - mLastWeight) * scaleDelta; + newScale = newScale + offset; + //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached + // needed? + // joint->storeScaleForReset( newScale ); + + // BENTO for detailed stack tracing of params. + std::stringstream ostr; + ostr << "LLPolySkeletalDistortion::apply, id " << getID() << " " << getName() << " effective wt " << effective_weight << " last wt " << mLastWeight << " scaleDelta " << scaleDelta << " offset " << offset; + LLScopedContextString str(ostr.str()); + + joint->setScale(newScale, true); + } + + for (iter = mJointOffsets.begin(); + iter != mJointOffsets.end(); + iter++) + { + joint = iter->first; + LLVector3 newPosition = joint->getPosition(); + LLVector3 positionDelta = iter->second; + newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); + // SL-315 + bool allow_attachment_pos_overrides = true; + joint->setPosition(newPosition, allow_attachment_pos_overrides); + } + + if (mLastWeight != effective_weight && !mIsAnimating) + { + mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); + } + mLastWeight = effective_weight; } diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 5ca9f55ac8..63069adcc8 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -173,7 +173,7 @@ void LLWearable::createVisualParams(LLAvatarAppearance *avatarp) { if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true)) { - LL_WARNS() << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL; + LL_DEBUGS("Avatar") << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL; continue; } } diff --git a/indra/llcharacter/CMakeLists.txt b/indra/llcharacter/CMakeLists.txt index 2573417b26..a17a5b0aa6 100644 --- a/indra/llcharacter/CMakeLists.txt +++ b/indra/llcharacter/CMakeLists.txt @@ -91,12 +91,12 @@ target_link_libraries( # Add tests -if (LL_TESTS) - include(LLAddBuildTest) - # UNIT TESTS - SET(llcharacter_TEST_SOURCE_FILES - lljoint.cpp - ) - LL_ADD_PROJECT_UNIT_TESTS(llcharacter "${llcharacter_TEST_SOURCE_FILES}") -endif (LL_TESTS) +#if (LL_TESTS) +# include(LLAddBuildTest) +# # UNIT TESTS +# SET(llcharacter_TEST_SOURCE_FILES +# lljoint.cpp +# ) +# LL_ADD_PROJECT_UNIT_TESTS(llcharacter "${llcharacter_TEST_SOURCE_FILES}") +#endif (LL_TESTS) diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index 0d558aeaa2..e906d81ce1 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -11,7 +11,7 @@ * 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, + * This library is distributed in the hope that it will be useful,7 * 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. @@ -29,6 +29,7 @@ #include "llbvhloader.h" #include <boost/tokenizer.hpp> +#include <boost/lexical_cast.hpp> #include "lldatapacker.h" #include "lldir.h" @@ -36,6 +37,7 @@ #include "llquantize.h" #include "llstl.h" #include "llapr.h" +#include "llsdserialize.h" using namespace std; @@ -121,52 +123,16 @@ LLQuaternion::Order bvhStringToOrder( char *str ) // LLBVHLoader() //----------------------------------------------------------------------------- -/* - LLBVHLoader::LLBVHLoader(const char* buffer) -{ - reset(); - - mStatus = loadTranslationTable("anim.ini"); - - if (mStatus == LLBVHLoader::ST_NO_XLT_FILE) - { - LL_WARNS() << "NOTE: No translation table found." << LL_ENDL; - return; - } - else - { - if (mStatus != LLBVHLoader::ST_OK) - { - LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; - return; - } - } - - char error_text[128]; // Flawfinder: ignore - S32 error_line; - mStatus = loadBVHFile(buffer, error_text, error_line); - if (mStatus != LLBVHLoader::ST_OK) - { - LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; - return; - } - - applyTranslations(); - optimize(); - - mInitialized = TRUE; -} -*/ -LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine) +LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map<std::string, std::string>& joint_alias_map ) { reset(); errorLine = 0; mStatus = loadTranslationTable("anim.ini"); loadStatus = mStatus; - LL_INFOS()<<"Load Status 00 : "<< loadStatus << LL_ENDL; + LL_INFOS("BVH") << "Load Status 00 : " << loadStatus << LL_ENDL; if (mStatus == E_ST_NO_XLT_FILE) { - //LL_WARNS() << "NOTE: No translation table found." << LL_ENDL; + LL_WARNS("BVH") << "NOTE: No translation table found." << LL_ENDL; loadStatus = mStatus; return; } @@ -174,28 +140,43 @@ LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &error { if (mStatus != E_ST_OK) { - //LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; + LL_WARNS("BVH") << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; errorLine = getLineNumber(); loadStatus = mStatus; return; } } + + // Recognize all names we've been told are legal. + std::map<std::string, std::string>::iterator iter; + for (iter = joint_alias_map.begin(); iter != joint_alias_map.end(); iter++) + { + makeTranslation( iter->first , iter->second ); + } char error_text[128]; /* Flawfinder: ignore */ S32 error_line; - mStatus = loadBVHFile(buffer, error_text, error_line); + mStatus = loadBVHFile(buffer, error_text, error_line); //Reads all joints in BVH file. + + LL_DEBUGS("BVH") << "============================================================" << LL_ENDL; + LL_DEBUGS("BVH") << "Raw data from file" << LL_ENDL; + dumpBVHInfo(); if (mStatus != E_ST_OK) { - //LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; + LL_WARNS("BVH") << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; loadStatus = mStatus; errorLine = getLineNumber(); return; } - applyTranslations(); + applyTranslations(); //Maps between joints found in file and the aliased names. optimize(); + LL_DEBUGS("BVH") << "============================================================" << LL_ENDL; + LL_DEBUGS("BVH") << "After translations and optimize" << LL_ENDL; + dumpBVHInfo(); + mInitialized = TRUE; } @@ -211,10 +192,6 @@ LLBVHLoader::~LLBVHLoader() //------------------------------------------------------------------------ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) { - mLineNumber = 0; - mTranslations.clear(); - mConstraints.clear(); - //-------------------------------------------------------------------- // open file //-------------------------------------------------------------------- @@ -226,7 +203,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) if (!fp) return E_ST_NO_XLT_FILE; - LL_INFOS() << "NOTE: Loading translation table: " << fileName << LL_ENDL; + LL_INFOS("BVH") << "NOTE: Loading translation table: " << fileName << LL_ENDL; //-------------------------------------------------------------------- // register file to be closed on function exit @@ -244,7 +221,6 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) // load data one line at a time //-------------------------------------------------------------------- BOOL loadingGlobals = FALSE; - Translation *trans = NULL; while ( getLine(fp) ) { //---------------------------------------------------------------- @@ -271,13 +247,6 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) loadingGlobals = TRUE; continue; } - else - { - loadingGlobals = FALSE; - Translation &newTrans = mTranslations[ name ]; - trans = &newTrans; - continue; - } } //---------------------------------------------------------------- @@ -499,174 +468,102 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) mConstraints.push_back(constraint); continue; } + } + infile.close() ; + return E_ST_OK; +} +void LLBVHLoader::makeTranslation(std::string alias_name, std::string joint_name) +{ + //Translation &newTrans = (foomap.insert(value_type(alias_name, Translation()))).first(); + Translation &newTrans = mTranslations[ alias_name ]; //Uses []'s implicit call to ctor. + + newTrans.mOutName = joint_name; + LLMatrix3 fm; + LLVector3 vect1(0, 1, 0); + LLVector3 vect2(0, 0, 1); + LLVector3 vect3(1, 0, 0); + fm.setRows(vect1, vect2, vect3); + + newTrans.mFrameMatrix = fm; + +if (joint_name == "mPelvis") + { + newTrans.mRelativePositionKey = TRUE; + newTrans.mRelativeRotationKey = TRUE; + } - //---------------------------------------------------------------- - // at this point there must be a valid trans pointer - //---------------------------------------------------------------- - if ( ! trans ) - return E_ST_NO_XLT_NAME; - - //---------------------------------------------------------------- - // check for ignore flag - //---------------------------------------------------------------- - if ( LLStringUtil::compareInsensitive(token, "ignore")==0 ) - { - char trueFalse[128]; /* Flawfinder: ignore */ - if ( sscanf(mLine, " %*s = %127s", trueFalse) != 1 ) /* Flawfinder: ignore */ - return E_ST_NO_XLT_IGNORE; - - trans->mIgnore = (LLStringUtil::compareInsensitive(trueFalse, "true")==0); - continue; - } - - //---------------------------------------------------------------- - // check for relativepos flag - //---------------------------------------------------------------- - if ( LLStringUtil::compareInsensitive(token, "relativepos")==0 ) - { - F32 x, y, z; - char relpos[128]; /* Flawfinder: ignore */ - if ( sscanf(mLine, " %*s = %f %f %f", &x, &y, &z) == 3 ) - { - trans->mRelativePosition.setVec( x, y, z ); - } - else if ( sscanf(mLine, " %*s = %127s", relpos) == 1 ) /* Flawfinder: ignore */ - { - if ( LLStringUtil::compareInsensitive(relpos, "firstkey")==0 ) - { - trans->mRelativePositionKey = TRUE; - } - else - { - return E_ST_NO_XLT_RELATIVE; - } - } - else - { - return E_ST_NO_XLT_RELATIVE; - } - - continue; - } - - //---------------------------------------------------------------- - // check for relativerot flag - //---------------------------------------------------------------- - if ( LLStringUtil::compareInsensitive(token, "relativerot")==0 ) - { - //F32 x, y, z; - char relpos[128]; /* Flawfinder: ignore */ - if ( sscanf(mLine, " %*s = %127s", relpos) == 1 ) /* Flawfinder: ignore */ - { - if ( LLStringUtil::compareInsensitive(relpos, "firstkey")==0 ) - { - trans->mRelativeRotationKey = TRUE; - } - else - { - return E_ST_NO_XLT_RELATIVE; - } - } - else - { - return E_ST_NO_XLT_RELATIVE; - } - - continue; - } - - //---------------------------------------------------------------- - // check for outname value - //---------------------------------------------------------------- - if ( LLStringUtil::compareInsensitive(token, "outname")==0 ) - { - char outName[128]; /* Flawfinder: ignore */ - if ( sscanf(mLine, " %*s = %127s", outName) != 1 ) /* Flawfinder: ignore */ - return E_ST_NO_XLT_OUTNAME; - - trans->mOutName = outName; - continue; - } - - //---------------------------------------------------------------- - // check for frame matrix value - //---------------------------------------------------------------- - if ( LLStringUtil::compareInsensitive(token, "frame")==0 ) - { - LLMatrix3 fm; - if ( sscanf(mLine, " %*s = %f %f %f, %f %f %f, %f %f %f", - &fm.mMatrix[0][0], &fm.mMatrix[0][1], &fm.mMatrix[0][2], - &fm.mMatrix[1][0], &fm.mMatrix[1][1], &fm.mMatrix[1][2], - &fm.mMatrix[2][0], &fm.mMatrix[2][1], &fm.mMatrix[2][2] ) != 9 ) - return E_ST_NO_XLT_MATRIX; - - trans->mFrameMatrix = fm; - continue; - } - - //---------------------------------------------------------------- - // check for offset matrix value - //---------------------------------------------------------------- - if ( LLStringUtil::compareInsensitive(token, "offset")==0 ) - { - LLMatrix3 om; - if ( sscanf(mLine, " %*s = %f %f %f, %f %f %f, %f %f %f", - &om.mMatrix[0][0], &om.mMatrix[0][1], &om.mMatrix[0][2], - &om.mMatrix[1][0], &om.mMatrix[1][1], &om.mMatrix[1][2], - &om.mMatrix[2][0], &om.mMatrix[2][1], &om.mMatrix[2][2] ) != 9 ) - return E_ST_NO_XLT_MATRIX; - - trans->mOffsetMatrix = om; - continue; - } - - //---------------------------------------------------------------- - // check for mergeparent value - //---------------------------------------------------------------- - if ( LLStringUtil::compareInsensitive(token, "mergeparent")==0 ) - { - char mergeParentName[128]; /* Flawfinder: ignore */ - if ( sscanf(mLine, " %*s = %127s", mergeParentName) != 1 ) /* Flawfinder: ignore */ - return E_ST_NO_XLT_MERGEPARENT; - - trans->mMergeParentName = mergeParentName; - continue; - } - - //---------------------------------------------------------------- - // check for mergechild value - //---------------------------------------------------------------- - if ( LLStringUtil::compareInsensitive(token, "mergechild")==0 ) - { - char mergeChildName[128]; /* Flawfinder: ignore */ - if ( sscanf(mLine, " %*s = %127s", mergeChildName) != 1 ) /* Flawfinder: ignore */ - return E_ST_NO_XLT_MERGECHILD; +} - trans->mMergeChildName = mergeChildName; - continue; - } +ELoadStatus LLBVHLoader::loadAliases(const char * filename) +{ + LLSD aliases_sd; + + std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,filename); + + llifstream input_stream; + input_stream.open(fullpath.c_str(), std::ios::in | std::ios::binary); + + if(input_stream.is_open()) + { + if ( LLSDSerialize::fromXML(aliases_sd, input_stream) ) + { + for(LLSD::map_iterator alias_iter = aliases_sd.beginMap(); + alias_iter != aliases_sd.endMap(); + ++alias_iter) + { + LLSD::String alias_name = alias_iter->first; + LLSD::String joint_name = alias_iter->second; + makeTranslation(alias_name, joint_name); + + } + } + else + { + return E_ST_NO_XLT_HEADER; + } + input_stream.close(); + } + else + { + LL_WARNS("BVH") << "Can't open joint alias file " << fullpath << LL_ENDL; + return E_ST_NO_XLT_FILE; + } + + return E_ST_OK; +} - //---------------------------------------------------------------- - // check for per-joint priority - //---------------------------------------------------------------- - if ( LLStringUtil::compareInsensitive(token, "priority")==0 ) +void LLBVHLoader::dumpBVHInfo() +{ + for (U32 j=0; j<mJoints.size(); j++) + { + Joint *joint = mJoints[j]; + LL_DEBUGS("BVH") << joint->mName << LL_ENDL; + for (S32 i=0; i<mNumFrames; i++) { - S32 priority; - if ( sscanf(mLine, " %*s = %d", &priority) != 1 ) - return E_ST_NO_XLT_PRIORITY; - - trans->mPriorityModifier = priority; - continue; + if (i<joint->mKeys.size()) // Check this in case file load failed. + { + Key &prevkey = joint->mKeys[llmax(i-1,0)]; + Key &key = joint->mKeys[i]; + if ((i==0) || + (key.mPos[0] != prevkey.mPos[0]) || + (key.mPos[1] != prevkey.mPos[1]) || + (key.mPos[2] != prevkey.mPos[2]) || + (key.mRot[0] != prevkey.mRot[0]) || + (key.mRot[1] != prevkey.mRot[1]) || + (key.mRot[2] != prevkey.mRot[2]) + ) + { + LL_DEBUGS("BVH") << "FRAME " << i + << " POS " << key.mPos[0] << "," << key.mPos[1] << "," << key.mPos[2] + << " ROT " << key.mRot[0] << "," << key.mRot[1] << "," << key.mRot[2] << LL_ENDL; + } + } } - } - infile.close() ; - return E_ST_OK; } - //------------------------------------------------------------------------ // LLBVHLoader::loadBVHFile() //------------------------------------------------------------------------ @@ -746,6 +643,7 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 & { iter++; // { iter++; // OFFSET + iter++; // } S32 depth = 0; for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--) { @@ -777,12 +675,19 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 & //--------------------------------------------------------------- // we require the root joint be "hip" - DEV-26188 //--------------------------------------------------------------- - const char* FORCED_ROOT_NAME = "hip"; - if ( (mJoints.size() == 0 ) && ( !strstr(jointName, FORCED_ROOT_NAME) ) ) - { - strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */ - return E_ST_BAD_ROOT; - } + if (mJoints.size() == 0 ) + { + //The root joint of the BVH file must be hip (mPelvis) or an alias of mPelvis. + const char* FORCED_ROOT_NAME = "hip"; + + TranslationMap::iterator hip_joint = mTranslations.find( FORCED_ROOT_NAME ); + TranslationMap::iterator root_joint = mTranslations.find( jointName ); + if ( hip_joint == mTranslations.end() || root_joint == mTranslations.end() || root_joint->second.mOutName != hip_joint->second.mOutName ) + { + strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */ + return E_ST_BAD_ROOT; + } + } //---------------------------------------------------------------- @@ -790,11 +695,14 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 & //---------------------------------------------------------------- mJoints.push_back( new Joint( jointName ) ); Joint *joint = mJoints.back(); + LL_DEBUGS("BVH") << "Created joint " << jointName << LL_ENDL; + LL_DEBUGS("BVH") << "- index " << mJoints.size()-1 << LL_ENDL; S32 depth = 1; for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--) { Joint *pjoint = mJoints[parent_joints[j]]; + LL_DEBUGS("BVH") << "- ancestor " << pjoint->mName << LL_ENDL; if (depth > pjoint->mChildTreeMaxDepth) { pjoint->mChildTreeMaxDepth = depth; @@ -863,6 +771,21 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 & return E_ST_NO_CHANNELS; } + // Animating position (via mNumChannels = 6) is only supported for mPelvis. + int res = sscanf(line.c_str(), " CHANNELS %d", &joint->mNumChannels); + if ( res != 1 ) + { + // Assume default if not otherwise specified. + if (mJoints.size()==1) + { + joint->mNumChannels = 6; + } + else + { + joint->mNumChannels = 3; + } + } + //---------------------------------------------------------------- // get rotation order //---------------------------------------------------------------- @@ -961,57 +884,49 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 & line = (*(iter++)); err_line++; - // read and store values - const char *p = line.c_str(); + // Split line into a collection of floats. + std::deque<F32> floats; + boost::char_separator<char> whitespace_sep("\t "); + tokenizer float_tokens(line, whitespace_sep); + tokenizer::iterator float_token_iter = float_tokens.begin(); + while (float_token_iter != float_tokens.end()) + { + try + { + F32 val = boost::lexical_cast<float>(*float_token_iter); + floats.push_back(val); + } + catch (const boost::bad_lexical_cast&) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_POS; + } + float_token_iter++; + } + LL_DEBUGS("BVH") << "Got " << floats.size() << " floats " << LL_ENDL; for (U32 j=0; j<mJoints.size(); j++) { Joint *joint = mJoints[j]; joint->mKeys.push_back( Key() ); Key &key = joint->mKeys.back(); - // get 3 pos values for root joint only - if (j==0) + if (floats.size() < joint->mNumChannels) { - if ( sscanf(p, "%f %f %f", key.mPos, key.mPos+1, key.mPos+2) != 3 ) - { - strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return E_ST_NO_POS; - } + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_POS; } - // skip to next 3 values in the line - p = find_next_whitespace(p); - if (!p) + // assume either numChannels == 6, in which case we have pos + rot, + // or numChannels == 3, in which case we have only rot. + if (joint->mNumChannels == 6) { - strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return E_ST_NO_ROT; + key.mPos[0] = floats.front(); floats.pop_front(); + key.mPos[1] = floats.front(); floats.pop_front(); + key.mPos[2] = floats.front(); floats.pop_front(); } - p = find_next_whitespace(++p); - if (!p) - { - strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return E_ST_NO_ROT; - } - p = find_next_whitespace(++p); - if (!p) - { - strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return E_ST_NO_ROT; - } - - // get 3 rot values for joint - F32 rot[3]; - if ( sscanf(p, " %f %f %f", rot, rot+1, rot+2) != 3 ) - { - strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return E_ST_NO_ROT; - } - - p++; - - key.mRot[ joint->mOrder[0]-'X' ] = rot[0]; - key.mRot[ joint->mOrder[1]-'X' ] = rot[1]; - key.mRot[ joint->mOrder[2]-'X' ] = rot[2]; + key.mRot[ joint->mOrder[0]-'X' ] = floats.front(); floats.pop_front(); + key.mRot[ joint->mOrder[1]-'X' ] = floats.front(); floats.pop_front(); + key.mRot[ joint->mOrder[2]-'X' ] = floats.front(); floats.pop_front(); } } @@ -1045,7 +960,7 @@ void LLBVHLoader::applyTranslations() //---------------------------------------------------------------- if ( trans.mIgnore ) { - //LL_INFOS() << "NOTE: Ignoring " << joint->mName.c_str() << LL_ENDL; + //LL_INFOS() << "NOTE: Ignoring " << joint->mName.c_str() << LL_ENDL; joint->mIgnore = TRUE; continue; } @@ -1059,13 +974,12 @@ void LLBVHLoader::applyTranslations() joint->mOutName = trans.mOutName; } - //---------------------------------------------------------------- - // Set the ignorepos flag if necessary - //---------------------------------------------------------------- - if ( joint->mOutName == std::string("mPelvis") ) - { - joint->mIgnorePositions = FALSE; - } + //Allow joint position changes as of SL-318 + joint->mIgnorePositions = FALSE; + if (joint->mNumChannels == 3) + { + joint->mIgnorePositions = TRUE; + } //---------------------------------------------------------------- // Set the relativepos flags if necessary @@ -1334,6 +1248,9 @@ void LLBVHLoader::reset() mInitialized = FALSE; mEmoteName = ""; + mLineNumber = 0; + mTranslations.clear(); + mConstraints.clear(); } //------------------------------------------------------------------------ @@ -1508,8 +1425,8 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp) frame++; } - // output position keys (only for 1st joint) - if ( ji == mJoints.begin() && !joint->mIgnorePositions ) + // output position keys if joint has motion. + if ( !joint->mIgnorePositions ) { dp.packS32(joint->mNumPosKeys, "num_pos_keys"); @@ -1539,6 +1456,7 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp) outPos *= INCHES_TO_METERS; + //SL-318 Pelvis position can only move 5m. Limiting all joint position offsets to this dist. outPos -= relPos; outPos.clamp(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); @@ -1586,5 +1504,6 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp) dp.packF32(constraint_it->mEaseOutStop, "ease_out_stop"); } + return TRUE; } diff --git a/indra/llcharacter/llbvhloader.h b/indra/llcharacter/llbvhloader.h index f816b76277..47fe409047 100644 --- a/indra/llcharacter/llbvhloader.h +++ b/indra/llcharacter/llbvhloader.h @@ -102,6 +102,7 @@ struct Joint mNumRotKeys = 0; mChildTreeMaxDepth = 0; mPriority = 0; + mNumChannels = 3; } // Include aligned members first @@ -123,6 +124,7 @@ struct Joint S32 mNumRotKeys; S32 mChildTreeMaxDepth; S32 mPriority; + S32 mNumChannels; }; @@ -225,8 +227,7 @@ class LLBVHLoader friend class LLKeyframeMotion; public: // Constructor -// LLBVHLoader(const char* buffer); - LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine); + LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map<std::string, std::string>& joint_alias_map ); ~LLBVHLoader(); /* @@ -265,13 +266,22 @@ public: static const char *ST_NO_XLT_EMOTE; static const char *ST_BAD_ROOT; */ + // Loads the specified translation table. ELoadStatus loadTranslationTable(const char *fileName); + //Create a new joint alias + void makeTranslation(std::string key, std::string value); + + // Loads joint aliases from XML file. + ELoadStatus loadAliases(const char * filename); + // Load the specified BVH file. // Returns status code. ELoadStatus loadBVHFile(const char *buffer, char *error_text, S32 &error_line); + void dumpBVHInfo(); + // Applies translations to BVH data loaded. void applyTranslations(); diff --git a/indra/llcharacter/lleditingmotion.cpp b/indra/llcharacter/lleditingmotion.cpp index f4a37a139a..ddf89f30f2 100644 --- a/indra/llcharacter/lleditingmotion.cpp +++ b/indra/llcharacter/lleditingmotion.cpp @@ -117,6 +117,7 @@ LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *characte addJointState( mWristState ); // propagate joint positions to kinematic chain + // SL-315 mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() ); mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() ); mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() ); @@ -143,6 +144,7 @@ LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *characte BOOL LLEditingMotion::onActivate() { // propagate joint positions to kinematic chain + // SL-315 mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() ); mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() ); mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() ); @@ -181,6 +183,7 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) focus_pt += mCharacter->getCharacterPosition(); // propagate joint positions to kinematic chain + // SL-315 mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() ); mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() ); mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() ); @@ -217,7 +220,8 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) " and focus point " << focus_pt << LL_ENDL; target.setVec(1.f, 1.f, 1.f); } - + + // SL-315 mTarget.setPosition( target + mParentJoint.getPosition()); // LL_INFOS() << "Point At: " << mTarget.getPosition() << LL_ENDL; diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp index 812c4201af..e91de7a11d 100644 --- a/indra/llcharacter/llheadrotmotion.cpp +++ b/indra/llcharacter/llheadrotmotion.cpp @@ -285,7 +285,10 @@ LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id) mName = "eye_rot"; mLeftEyeState = new LLJointState; + mAltLeftEyeState = new LLJointState; + mRightEyeState = new LLJointState; + mAltRightEyeState = new LLJointState; } @@ -318,18 +321,38 @@ LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character) return STATUS_FAILURE; } + mAltLeftEyeState->setJoint( character->getJoint("mFaceEyeAltLeft") ); + if ( ! mAltLeftEyeState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get alt left eyeball joint." << LL_ENDL; + return STATUS_FAILURE; + } + mRightEyeState->setJoint( character->getJoint("mEyeRight") ); if ( ! mRightEyeState->getJoint() ) { - LL_INFOS() << getName() << ": Can't get Right eyeball joint." << LL_ENDL; + LL_INFOS() << getName() << ": Can't get right eyeball joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mAltRightEyeState->setJoint( character->getJoint("mFaceEyeAltRight") ); + if ( ! mAltRightEyeState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get alt right eyeball joint." << LL_ENDL; return STATUS_FAILURE; } mLeftEyeState->setUsage(LLJointState::ROT); + mAltLeftEyeState->setUsage(LLJointState::ROT); + mRightEyeState->setUsage(LLJointState::ROT); + mAltRightEyeState->setUsage(LLJointState::ROT); addJointState( mLeftEyeState ); + addJointState( mAltLeftEyeState ); + addJointState( mRightEyeState ); + addJointState( mAltRightEyeState ); return STATUS_SUCCESS; } @@ -343,17 +366,98 @@ BOOL LLEyeMotion::onActivate() return TRUE; } - //----------------------------------------------------------------------------- -// LLEyeMotion::onUpdate() +// LLEyeMotion::adjustEyeTarget() //----------------------------------------------------------------------------- -BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask) +void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state) { // Compute eye rotation. + BOOL has_eye_target = FALSE; LLQuaternion target_eye_rot; LLVector3 eye_look_at; F32 vergence; + if (targetPos) + { + LLVector3 skyward(0.f, 0.f, 1.f); + LLVector3 left; + LLVector3 up; + + eye_look_at = *targetPos; + has_eye_target = TRUE; + F32 lookAtDistance = eye_look_at.normVec(); + + left.setVec(skyward % eye_look_at); + up.setVec(eye_look_at % left); + + target_eye_rot = LLQuaternion(eye_look_at, left, up); + // convert target rotation to head-local coordinates + target_eye_rot *= ~mHeadJoint->getWorldRotation(); + // eliminate any Euler roll - we're lucky that roll is applied last. + F32 roll, pitch, yaw; + target_eye_rot.getEulerAngles(&roll, &pitch, &yaw); + target_eye_rot.setQuat(0.0f, pitch, yaw); + // constrain target orientation to be in front of avatar's face + target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE); + + // calculate vergence + F32 interocular_dist = (left_eye_state.getJoint()->getWorldPosition() - right_eye_state.getJoint()->getWorldPosition()).magVec(); + vergence = -atan2((interocular_dist / 2.f), lookAtDistance); + llclamp(vergence, -F_PI_BY_TWO, 0.f); + } + else + { + target_eye_rot = LLQuaternion::DEFAULT; + vergence = 0.f; + } + + //RN: subtract 4 degrees to account for foveal angular offset relative to pupil + vergence += 4.f * DEG_TO_RAD; + + // calculate eye jitter + LLQuaternion eye_jitter_rot; + + // vergence not too high... + if (vergence > -0.05f) + { + //...go ahead and jitter + eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw); + } + else + { + //...or don't + eye_jitter_rot.loadIdentity(); + } + + // calculate vergence of eyes as an object gets closer to the avatar's head + LLQuaternion vergence_quat; + + if (has_eye_target) + { + vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f)); + } + else + { + vergence_quat.loadIdentity(); + } + + // calculate eye rotations + LLQuaternion left_eye_rot = target_eye_rot; + left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot; + + LLQuaternion right_eye_rot = target_eye_rot; + vergence_quat.transQuat(); + right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot; + + left_eye_state.setRotation( left_eye_rot ); + right_eye_state.setRotation( right_eye_rot ); +} + +//----------------------------------------------------------------------------- +// LLEyeMotion::onUpdate() +//----------------------------------------------------------------------------- +BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask) +{ //calculate jitter if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime) { @@ -426,83 +530,10 @@ BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask) } } - BOOL has_eye_target = FALSE; LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); - if (targetPos) - { - LLVector3 skyward(0.f, 0.f, 1.f); - LLVector3 left; - LLVector3 up; - - eye_look_at = *targetPos; - has_eye_target = TRUE; - F32 lookAtDistance = eye_look_at.normVec(); - - left.setVec(skyward % eye_look_at); - up.setVec(eye_look_at % left); - - target_eye_rot = LLQuaternion(eye_look_at, left, up); - // convert target rotation to head-local coordinates - target_eye_rot *= ~mHeadJoint->getWorldRotation(); - // eliminate any Euler roll - we're lucky that roll is applied last. - F32 roll, pitch, yaw; - target_eye_rot.getEulerAngles(&roll, &pitch, &yaw); - target_eye_rot.setQuat(0.0f, pitch, yaw); - // constrain target orientation to be in front of avatar's face - target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE); - - // calculate vergence - F32 interocular_dist = (mLeftEyeState->getJoint()->getWorldPosition() - mRightEyeState->getJoint()->getWorldPosition()).magVec(); - vergence = -atan2((interocular_dist / 2.f), lookAtDistance); - llclamp(vergence, -F_PI_BY_TWO, 0.f); - } - else - { - target_eye_rot = LLQuaternion::DEFAULT; - vergence = 0.f; - } - - //RN: subtract 4 degrees to account for foveal angular offset relative to pupil - vergence += 4.f * DEG_TO_RAD; - - // calculate eye jitter - LLQuaternion eye_jitter_rot; - - // vergence not too high... - if (vergence > -0.05f) - { - //...go ahead and jitter - eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw); - } - else - { - //...or don't - eye_jitter_rot.loadIdentity(); - } - - // calculate vergence of eyes as an object gets closer to the avatar's head - LLQuaternion vergence_quat; - - if (has_eye_target) - { - vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f)); - } - else - { - vergence_quat.loadIdentity(); - } - - // calculate eye rotations - LLQuaternion left_eye_rot = target_eye_rot; - left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot; - - LLQuaternion right_eye_rot = target_eye_rot; - vergence_quat.transQuat(); - right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot; - - mLeftEyeState->setRotation( left_eye_rot ); - mRightEyeState->setRotation( right_eye_rot ); + adjustEyeTarget(targetPos, *mLeftEyeState, *mRightEyeState); + adjustEyeTarget(targetPos, *mAltLeftEyeState, *mAltRightEyeState); return TRUE; } @@ -519,11 +550,23 @@ void LLEyeMotion::onDeactivate() joint->setRotation(LLQuaternion::DEFAULT); } + joint = mAltLeftEyeState->getJoint(); + if (joint) + { + joint->setRotation(LLQuaternion::DEFAULT); + } + joint = mRightEyeState->getJoint(); if (joint) { joint->setRotation(LLQuaternion::DEFAULT); } + + joint = mAltRightEyeState->getJoint(); + if (joint) + { + joint->setRotation(LLQuaternion::DEFAULT); + } } // End diff --git a/indra/llcharacter/llheadrotmotion.h b/indra/llcharacter/llheadrotmotion.h index 569dbef2dd..53ae1813bc 100644 --- a/indra/llcharacter/llheadrotmotion.h +++ b/indra/llcharacter/llheadrotmotion.h @@ -176,6 +176,8 @@ public: // it will be deactivated virtual BOOL onActivate(); + void adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state); + // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. @@ -193,6 +195,8 @@ public: LLJoint *mHeadJoint; LLPointer<LLJointState> mLeftEyeState; LLPointer<LLJointState> mRightEyeState; + LLPointer<LLJointState> mAltLeftEyeState; + LLPointer<LLJointState> mAltRightEyeState; LLFrameTimer mEyeJitterTimer; F32 mEyeJitterTime; diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index 8fa08a2a6c..a3d5679f65 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -32,6 +32,8 @@ #include "lljoint.h" #include "llmath.h" +#include "llcallstack.h" +#include <boost/algorithm/string.hpp> S32 LLJoint::sNumUpdates = 0; S32 LLJoint::sNumTouches = 0; @@ -42,7 +44,7 @@ bool attachment_map_iter_compare_key(const T& a, const T& b) return a.first < b.first; } -bool LLPosOverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const +bool LLVector3OverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const { pos = LLVector3(0,0,0); mesh_id = LLUUID(); @@ -60,7 +62,7 @@ bool LLPosOverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const return found; } -void LLPosOverrideMap::showJointPosOverrides( std::ostringstream& os ) const +void LLVector3OverrideMap::showJointVector3Overrides( std::ostringstream& os ) const { map_type::const_iterator max_it = std::max_element(m_map.begin(), m_map.end(), @@ -73,23 +75,23 @@ void LLPosOverrideMap::showJointPosOverrides( std::ostringstream& os ) const } } -U32 LLPosOverrideMap::count() const +U32 LLVector3OverrideMap::count() const { return m_map.size(); } -void LLPosOverrideMap::add(const LLUUID& mesh_id, const LLVector3& pos) +void LLVector3OverrideMap::add(const LLUUID& mesh_id, const LLVector3& pos) { m_map[mesh_id] = pos; } -bool LLPosOverrideMap::remove(const LLUUID& mesh_id) +bool LLVector3OverrideMap::remove(const LLUUID& mesh_id) { U32 remove_count = m_map.erase(mesh_id); return (remove_count > 0); } -void LLPosOverrideMap::clear() +void LLVector3OverrideMap::clear() { m_map.clear(); } @@ -108,6 +110,8 @@ void LLJoint::init() mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f)); mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY; mUpdateXform = TRUE; + mSupport = SUPPORT_BASE; + mEnd = LLVector3(0.0f, 0.0f, 0.0f); } LLJoint::LLJoint() : @@ -124,13 +128,12 @@ LLJoint::LLJoint(S32 joint_num) : touch(); } - //----------------------------------------------------------------------------- // LLJoint() // Class Constructor //----------------------------------------------------------------------------- LLJoint::LLJoint(const std::string &name, LLJoint *parent) : - mJointNum(0) + mJointNum(-2) { init(); mUpdateXform = FALSE; @@ -170,6 +173,27 @@ void LLJoint::setup(const std::string &name, LLJoint *parent) } //----------------------------------------------------------------------------- +// setSupport() +//----------------------------------------------------------------------------- +void LLJoint::setSupport(const std::string& support_name) +{ + if (support_name == "extended") + { + setSupport(SUPPORT_EXTENDED); + } + else if (support_name == "base") + { + setSupport(SUPPORT_BASE); + } + else + { + LL_WARNS() << "unknown support string " << support_name << LL_ENDL; + setSupport(SUPPORT_BASE); + } +} + + +//----------------------------------------------------------------------------- // touch() // Sets all dirty flags for all children, recursively. //----------------------------------------------------------------------------- @@ -195,6 +219,18 @@ void LLJoint::touch(U32 flags) } //----------------------------------------------------------------------------- +// setJointNum() +//----------------------------------------------------------------------------- +void LLJoint::setJointNum(S32 joint_num) +{ + mJointNum = joint_num; + if (mJointNum + 2 >= LL_CHARACTER_MAX_ANIMATED_JOINTS) + { + LL_INFOS() << "LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be increased" << LL_ENDL; + LL_ERRS() << "joint_num " << joint_num << " + 2 is too large for " << LL_CHARACTER_MAX_ANIMATED_JOINTS << LL_ENDL; + } +} +//----------------------------------------------------------------------------- // getRoot() //----------------------------------------------------------------------------- LLJoint *LLJoint::getRoot() @@ -290,43 +326,119 @@ const LLVector3& LLJoint::getPosition() bool do_debug_joint(const std::string& name) { - return false; + if (std::find(LLJoint::s_debugJointNames.begin(), LLJoint::s_debugJointNames.end(),name) != LLJoint::s_debugJointNames.end()) + { + return true; + } + return false; } //-------------------------------------------------------------------- // setPosition() //-------------------------------------------------------------------- -void LLJoint::setPosition( const LLVector3& pos ) +void LLJoint::setPosition( const LLVector3& requested_pos, bool apply_attachment_overrides ) { - if (pos != getPosition()) + LLVector3 pos(requested_pos); + + LLVector3 active_override; + LLUUID mesh_id; + if (apply_attachment_overrides && m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override)) + { + if (pos != active_override && do_debug_joint(getName())) + { + LLScopedContextString str("setPosition"); + LL_DEBUGS("Avatar") << " joint " << getName() << " requested_pos " << requested_pos + << " overriden by attachment " << active_override << LL_ENDL; + } + pos = active_override; + } + if ((pos != getPosition()) && do_debug_joint(getName())) { - if (do_debug_joint(getName())) - { - LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL; - } + LLScopedContextString str("setPosition"); + LLCallStack cs; + LLContextStatus con_status; + LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL; + LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << "====================" << LL_ENDL; + LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL; } - mXform.setPosition(pos); - touch(MATRIX_DIRTY | POSITION_DIRTY); + if (pos != getPosition()) + { + mXform.setPosition(pos); + touch(MATRIX_DIRTY | POSITION_DIRTY); + } +} + +void LLJoint::setDefaultPosition( const LLVector3& pos ) +{ + mDefaultPosition = pos; +} + +const LLVector3& LLJoint::getDefaultPosition() const +{ + return mDefaultPosition; +} + +void LLJoint::setDefaultScale( const LLVector3& scale ) +{ + mDefaultScale = scale; +} + +const LLVector3& LLJoint::getDefaultScale() const +{ + return mDefaultScale; } void showJointPosOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info ) { std::ostringstream os; os << joint.m_posBeforeOverrides; - joint.m_attachmentOverrides.showJointPosOverrides(os); + joint.m_attachmentPosOverrides.showJointVector3Overrides(os); + LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL; +} + +void showJointScaleOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info ) +{ + std::ostringstream os; + os << joint.m_scaleBeforeOverrides; + joint.m_attachmentScaleOverrides.showJointVector3Overrides(os); LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL; } +bool LLJoint::aboveJointPosThreshold(const LLVector3& pos) const +{ + LLVector3 diff = pos - getDefaultPosition(); + const F32 max_joint_pos_offset = 0.0001f; // 0.1 mm + return diff.lengthSquared() > max_joint_pos_offset * max_joint_pos_offset; +} + +bool LLJoint::aboveJointScaleThreshold(const LLVector3& scale) const +{ + LLVector3 diff = scale - getDefaultScale(); + const F32 max_joint_scale_offset = 0.0001f; // 0.1 mm + return diff.lengthSquared() > max_joint_scale_offset * max_joint_scale_offset; +} + //-------------------------------------------------------------------- // addAttachmentPosOverride() //-------------------------------------------------------------------- -void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info ) +void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ) { + active_override_changed = false; if (mesh_id.isNull()) { return; } - if (!m_attachmentOverrides.count()) + // BENTO + // Not clear pelvis overrides are meaningful/useful. + //if (mName == "mPelvis") + //{ + // return; + //} + + LLVector3 before_pos; + LLUUID before_mesh_id; + bool has_active_override_before = hasAttachmentPosOverride( before_pos, before_mesh_id ); + if (!m_attachmentPosOverrides.count()) { if (do_debug_joint(getName())) { @@ -334,32 +446,50 @@ void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh } m_posBeforeOverrides = getPosition(); } - m_attachmentOverrides.add(mesh_id,pos); - if (do_debug_joint(getName())) - { - LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << pos << LL_ENDL; - } - updatePos(av_info); + m_attachmentPosOverrides.add(mesh_id,pos); + LLVector3 after_pos; + LLUUID after_mesh_id; + hasAttachmentPosOverride(after_pos, after_mesh_id); + if (!has_active_override_before || (after_pos != before_pos)) + { + active_override_changed = true; + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << pos << LL_ENDL; + } + updatePos(av_info); + } } //-------------------------------------------------------------------- // removeAttachmentPosOverride() //-------------------------------------------------------------------- -void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info ) +void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ) { + active_override_changed = false; if (mesh_id.isNull()) { return; } - if (m_attachmentOverrides.remove(mesh_id)) + LLVector3 before_pos; + LLUUID before_mesh_id; + hasAttachmentPosOverride( before_pos, before_mesh_id ); + if (m_attachmentPosOverrides.remove(mesh_id)) { - if (do_debug_joint(getName())) - { - LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() - << " removeAttachmentPosOverride for " << mesh_id << LL_ENDL; - showJointPosOverrides(*this, "remove", av_info); - } - updatePos(av_info); + LLVector3 after_pos; + LLUUID after_mesh_id; + bool has_active_override_after = hasAttachmentPosOverride(after_pos, after_mesh_id); + if (!has_active_override_after || (after_pos != before_pos)) + { + active_override_changed = true; + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " removeAttachmentPosOverride for " << mesh_id << LL_ENDL; + showJointPosOverrides(*this, "remove", av_info); + } + updatePos(av_info); + } } } @@ -368,7 +498,7 @@ void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::str //-------------------------------------------------------------------- bool LLJoint::hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const { - return m_attachmentOverrides.findActiveOverride(mesh_id,pos); + return m_attachmentPosOverrides.findActiveOverride(mesh_id,pos); } //-------------------------------------------------------------------- @@ -376,11 +506,81 @@ bool LLJoint::hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const //-------------------------------------------------------------------- void LLJoint::clearAttachmentPosOverrides() { - if (m_attachmentOverrides.count()) + if (m_attachmentPosOverrides.count()) { - m_attachmentOverrides.clear(); + m_attachmentPosOverrides.clear(); setPosition(m_posBeforeOverrides); - setId( LLUUID::null ); + } +} + +//-------------------------------------------------------------------- +// getAllAttachmentPosOverrides() +//-------------------------------------------------------------------- +void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides, + std::set<LLVector3>& distinct_pos_overrides) +{ + num_pos_overrides = m_attachmentPosOverrides.count(); + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); + for (; it != m_attachmentPosOverrides.getMap().end(); ++it) + { + distinct_pos_overrides.insert(it->second); + } +} + +//-------------------------------------------------------------------- +// getAllAttachmentScaleOverrides() +//-------------------------------------------------------------------- +void LLJoint::getAllAttachmentScaleOverrides(S32& num_scale_overrides, + std::set<LLVector3>& distinct_scale_overrides) +{ + num_scale_overrides = m_attachmentScaleOverrides.count(); + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin(); + for (; it != m_attachmentScaleOverrides.getMap().end(); ++it) + { + distinct_scale_overrides.insert(it->second); + } +} + +//-------------------------------------------------------------------- +// showAttachmentPosOverrides() +//-------------------------------------------------------------------- +void LLJoint::showAttachmentPosOverrides(const std::string& av_info) const +{ + LLVector3 active_override; + bool has_active_override; + LLUUID mesh_id; + has_active_override = m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override); + U32 count = m_attachmentPosOverrides.count(); + if (count==1) + { + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); + std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : ""; + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " has single attachment pos override " << highlight << "" << it->second << " default " << mDefaultPosition << LL_ENDL; + } + else if (count>1) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment pos overrides" << LL_ENDL; + std::set<LLVector3> distinct_offsets; + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); + for (; it != m_attachmentPosOverrides.getMap().end(); ++it) + { + distinct_offsets.insert(it->second); + } + if (distinct_offsets.size()>1) + { + LL_DEBUGS("Avatar") << "CONFLICTS, " << distinct_offsets.size() << " different values" << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << "no conflicts" << LL_ENDL; + } + std::set<LLVector3>::iterator dit = distinct_offsets.begin(); + for ( ; dit != distinct_offsets.end(); ++dit) + { + std::string highlight = (has_active_override && *dit == active_override) ? "*" : ""; + LL_DEBUGS("Avatar") << " POS " << highlight << "" << (*dit) << " default " << mDefaultPosition << LL_ENDL; + } } } @@ -391,20 +591,178 @@ void LLJoint::updatePos(const std::string& av_info) { LLVector3 pos, found_pos; LLUUID mesh_id; - if (m_attachmentOverrides.findActiveOverride(mesh_id,found_pos)) + if (m_attachmentPosOverrides.findActiveOverride(mesh_id,found_pos)) { - LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner of " << m_attachmentOverrides.count() << " is mesh " << mesh_id << " pos " << found_pos << LL_ENDL; + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner of " << m_attachmentPosOverrides.count() << " is mesh " << mesh_id << " pos " << found_pos << LL_ENDL; + } pos = found_pos; } else { - LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner is posBeforeOverrides " << m_posBeforeOverrides << LL_ENDL; + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner is posBeforeOverrides " << m_posBeforeOverrides << LL_ENDL; + } pos = m_posBeforeOverrides; } setPosition(pos); } //-------------------------------------------------------------------- +// updateScale() +//-------------------------------------------------------------------- +void LLJoint::updateScale(const std::string& av_info) +{ + LLVector3 scale, found_scale; + LLUUID mesh_id; + if (m_attachmentScaleOverrides.findActiveOverride(mesh_id,found_scale)) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner of " << m_attachmentScaleOverrides.count() << " is mesh " << mesh_id << " scale " << found_scale << LL_ENDL; + } + scale = found_scale; + } + else + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner is scaleBeforeOverrides " << m_scaleBeforeOverrides << LL_ENDL; + } + scale = m_scaleBeforeOverrides; + } + setScale(scale); +} + +//-------------------------------------------------------------------- +// addAttachmentScaleOverride() +//-------------------------------------------------------------------- +void LLJoint::addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info ) +{ + if (mesh_id.isNull()) + { + return; + } + if (!m_attachmentScaleOverrides.count()) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " saving m_scaleBeforeOverrides " << getScale() << LL_ENDL; + } + m_scaleBeforeOverrides = getScale(); + } + m_attachmentScaleOverrides.add(mesh_id,scale); + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentScaleOverride for mesh " << mesh_id << " scale " << scale << LL_ENDL; + } + updateScale(av_info); +} + +//-------------------------------------------------------------------- +// removeAttachmentScaleOverride() +//-------------------------------------------------------------------- +void LLJoint::removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info ) +{ + if (mesh_id.isNull()) + { + return; + } + if (m_attachmentScaleOverrides.remove(mesh_id)) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " removeAttachmentScaleOverride for " << mesh_id << LL_ENDL; + showJointScaleOverrides(*this, "remove", av_info); + } + updateScale(av_info); + } +} + +//-------------------------------------------------------------------- + // hasAttachmentScaleOverride() + //-------------------------------------------------------------------- +bool LLJoint::hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const +{ + return m_attachmentScaleOverrides.findActiveOverride(mesh_id,scale); +} + +//-------------------------------------------------------------------- +// clearAttachmentScaleOverrides() +//-------------------------------------------------------------------- +void LLJoint::clearAttachmentScaleOverrides() +{ + if (m_attachmentScaleOverrides.count()) + { + m_attachmentScaleOverrides.clear(); + setScale(m_scaleBeforeOverrides); + } +} + +//-------------------------------------------------------------------- +// showAttachmentScaleOverrides() +//-------------------------------------------------------------------- +void LLJoint::showAttachmentScaleOverrides(const std::string& av_info) const +{ + LLVector3 active_override; + bool has_active_override; + LLUUID mesh_id; + has_active_override = m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override); + U32 count = m_attachmentScaleOverrides.count(); + if (count==1) + { + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin(); + std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : ""; + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " has single attachment scale override " << highlight << "" << it->second << " default " << mDefaultScale << LL_ENDL; + } + else if (count>1) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment scale overrides" << LL_ENDL; + std::set<LLVector3> distinct_offsets; + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin(); + for (; it != m_attachmentScaleOverrides.getMap().end(); ++it) + { + distinct_offsets.insert(it->second); + } + if (distinct_offsets.size()>1) + { + LL_DEBUGS("Avatar") << "CONFLICTS, " << distinct_offsets.size() << " different values" << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << "no conflicts" << LL_ENDL; + } + std::set<LLVector3>::iterator dit = distinct_offsets.begin(); + for ( ; dit != distinct_offsets.end(); ++dit) + { + std::string highlight = (has_active_override && *dit == active_override) ? "*" : ""; + LL_DEBUGS("Avatar") << " POS " << highlight << "" << (*dit) << " default " << mDefaultScale << LL_ENDL; + } + } +} + +// init static +LLJoint::debug_joint_name_t LLJoint::s_debugJointNames = debug_joint_name_t(); + +//-------------------------------------------------------------------- +// setDebugJointNames +//-------------------------------------------------------------------- +void LLJoint::setDebugJointNames(const debug_joint_name_t& names) +{ + s_debugJointNames = names; +} +void LLJoint::setDebugJointNames(const std::string& names_string) +{ + debug_joint_name_t names; + boost::split(names, names_string, boost::is_any_of(" :,")); + setDebugJointNames(names); +} + +//-------------------------------------------------------------------- // getWorldPosition() //-------------------------------------------------------------------- LLVector3 LLJoint::getWorldPosition() @@ -529,13 +887,32 @@ const LLVector3& LLJoint::getScale() //-------------------------------------------------------------------- // setScale() //-------------------------------------------------------------------- -void LLJoint::setScale( const LLVector3& scale ) +void LLJoint::setScale( const LLVector3& requested_scale, bool apply_attachment_overrides ) { -// if (mXform.getScale() != scale) + LLVector3 scale(requested_scale); + LLUUID mesh_id; + LLVector3 active_override; + if (apply_attachment_overrides && m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override)) + { + if (scale != active_override && do_debug_joint(getName())) + { + LLScopedContextString str("setScale"); + LL_DEBUGS("Avatar") << " joint " << getName() << " requested_scale " << requested_scale + << " overriden by attachment " << active_override << LL_ENDL; + } + scale = active_override; + } + if ((mXform.getScale() != scale) && do_debug_joint(getName())) { - mXform.setScale(scale); - touch(); + LLScopedContextString str("setScale"); + LLCallStack cs; + LLContextStatus con_status; + LL_DEBUGS("Avatar") << " joint " << getName() << " set scale " << scale << LL_ENDL; + LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << LL_ENDL; + LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL; } + mXform.setScale(scale); + touch(); } diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 2abe1d6db1..0c8fbfebb0 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -40,24 +40,33 @@ #include "xform.h" const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15; -const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 4! -const U32 LL_HAND_JOINT_NUM = 31; -const U32 LL_FACE_JOINT_NUM = 30; +// Need to set this to count of animate-able joints, +// currently = #bones + #collision_volumes + #attachments + 2, +// rounded to next multiple of 4. +const U32 LL_CHARACTER_MAX_ANIMATED_JOINTS = 216; // must be divisible by 4! +const U32 LL_MAX_JOINTS_PER_MESH_OBJECT = 110; + +// These should be higher than the joint_num of any +// other joint, to avoid conflicts in updateMotionsByType() +const U32 LL_HAND_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-1); +const U32 LL_FACE_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-2); const S32 LL_CHARACTER_MAX_PRIORITY = 7; const F32 LL_MAX_PELVIS_OFFSET = 5.f; -class LLPosOverrideMap +class LLVector3OverrideMap { public: - LLPosOverrideMap() {} + LLVector3OverrideMap() {} bool findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const; - void showJointPosOverrides(std::ostringstream& os) const; + void showJointVector3Overrides(std::ostringstream& os) const; U32 count() const; void add(const LLUUID& mesh_id, const LLVector3& pos); bool remove(const LLUUID& mesh_id); void clear(); -private: + typedef std::map<LLUUID,LLVector3> map_type; + const map_type& getMap() const { return m_map; } +private: map_type m_map; }; @@ -86,17 +95,26 @@ public: POSITION_DIRTY = 0x1 << 2, ALL_DIRTY = 0x7 }; +public: + enum SupportCategory + { + SUPPORT_BASE, + SUPPORT_EXTENDED + }; protected: std::string mName; + SupportCategory mSupport; + // parent joint LLJoint *mParent; // explicit transformation members LLXformMatrix mXform; - LLUUID mId; - + LLVector3 mDefaultPosition; + LLVector3 mDefaultScale; + public: U32 mDirtyFlags; BOOL mUpdateXform; @@ -104,6 +122,10 @@ public: // describes the skin binding pose LLVector3 mSkinOffset; + // Endpoint of the bone, if applicable. This is only relevant for + // external programs like Blender, and for diagnostic display. + LLVector3 mEnd; + S32 mJointNum; // child joints @@ -113,15 +135,40 @@ public: // debug statics static S32 sNumTouches; static S32 sNumUpdates; + typedef std::set<std::string> debug_joint_name_t; + static debug_joint_name_t s_debugJointNames; + static void setDebugJointNames(const debug_joint_name_t& names); + static void setDebugJointNames(const std::string& names_string); - LLPosOverrideMap m_attachmentOverrides; + // Position overrides + LLVector3OverrideMap m_attachmentPosOverrides; LLVector3 m_posBeforeOverrides; + // Scale overrides + LLVector3OverrideMap m_attachmentScaleOverrides; + LLVector3 m_scaleBeforeOverrides; + void updatePos(const std::string& av_info); + void updateScale(const std::string& av_info); public: LLJoint(); - LLJoint(S32 joint_num); + + // Note: these joint_num constructors are a bad idea because there + // are only a couple of places in the code where it is useful to + // have a joint num for a joint (for joints that are used in + // animations), and including them as part of the constructor then + // forces us to maintain an alternate path through the entire + // large-ish class hierarchy of joint types. The only reason they + // are still here now is to avoid breaking the baking service + // (appearanceutility) builds; these constructors are not used in + // the viewer. Once the appearance utility is updated to remove + // these joint num references, which it shouldn't ever need, from + // its own classes, we can also remove all the joint_num + // constructors from LLJoint, LLViewerJoint, LLAvatarJoint, and + // createAvatarJoint. + LLJoint(S32 joint_num); + // *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform* LLJoint( const std::string &name, LLJoint *parent=NULL ); virtual ~LLJoint(); @@ -139,6 +186,19 @@ public: const std::string& getName() const { return mName; } void setName( const std::string &name ) { mName = name; } + // joint num + S32 getJointNum() const { return mJointNum; } + void setJointNum(S32 joint_num); + + // get/set support + SupportCategory getSupport() const { return mSupport; } + void setSupport( const SupportCategory& support) { mSupport = support; } + void setSupport( const std::string& support_string); + + // get/set end point + void setEnd( const LLVector3& end) { mEnd = end; } + const LLVector3& getEnd() const { return mEnd; } + // getParent LLJoint *getParent() { return mParent; } @@ -155,10 +215,16 @@ public: // get/set local position const LLVector3& getPosition(); - void setPosition( const LLVector3& pos ); - + void setPosition( const LLVector3& pos, bool apply_attachment_overrides = false ); + + // Tracks the default position defined by the skeleton void setDefaultPosition( const LLVector3& pos ); - + const LLVector3& getDefaultPosition() const; + + // Tracks the default scale defined by the skeleton + void setDefaultScale( const LLVector3& scale ); + const LLVector3& getDefaultScale() const; + // get/set world position LLVector3 getWorldPosition(); LLVector3 getLastWorldPosition(); @@ -175,7 +241,7 @@ public: // get/set local scale const LLVector3& getScale(); - void setScale( const LLVector3& scale ); + void setScale( const LLVector3& scale, bool apply_attachment_overrides = false ); // get/set world matrix const LLMatrix4 &getWorldMatrix(); @@ -198,17 +264,26 @@ public: virtual BOOL isAnimatable() const { return TRUE; } - S32 getJointNum() const { return mJointNum; } - - void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info ); - void removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info ); + void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ); + void removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ); bool hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const; void clearAttachmentPosOverrides(); - - //Accessor for the joint id - LLUUID getId( void ) { return mId; } - //Setter for the joints id - void setId( const LLUUID& id ) { mId = id;} + void showAttachmentPosOverrides(const std::string& av_info) const; + + void addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info ); + void removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info ); + bool hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const; + void clearAttachmentScaleOverrides(); + void showAttachmentScaleOverrides(const std::string& av_info) const; + + void getAllAttachmentPosOverrides(S32& num_pos_overrides, + std::set<LLVector3>& distinct_pos_overrides); + void getAllAttachmentScaleOverrides(S32& num_scale_overrides, + std::set<LLVector3>& distinct_scale_overrides); + + // These are used in checks of whether a pos/scale override is considered significant. + bool aboveJointPosThreshold(const LLVector3& pos) const; + bool aboveJointScaleThreshold(const LLVector3& scale) const; }; #endif // LL_LLJOINT_H diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index cd201a65b4..89f34a92c8 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -498,6 +498,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact // request asset mAssetStatus = ASSET_FETCHED; + LL_DEBUGS("Animation") << "Requesting data fetch for: " << mID << LL_ENDL; character_id = new LLUUID(mCharacter->getID()); gAssetStorage->getAssetData(mID, LLAssetType::AT_ANIMATION, @@ -1380,7 +1381,7 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) LL_WARNS() << "no joints in animation" << LL_ENDL; return FALSE; } - else if (num_motions > LL_CHARACTER_MAX_JOINTS) + else if (num_motions > LL_CHARACTER_MAX_ANIMATED_JOINTS) { LL_WARNS() << "too many joints in animation" << LL_ENDL; return FALSE; @@ -1419,7 +1420,14 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) LLJoint *joint = mCharacter->getJoint( joint_name ); if (joint) { + S32 joint_num = joint->getJointNum(); // LL_INFOS() << " joint: " << joint_name << LL_ENDL; + if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0)) + { + LL_WARNS() << "Joint will be omitted from animation: joint_num " << joint_num << " is outside of legal range [0-" + << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << joint->getName() << LL_ENDL; + joint = NULL; + } } else { @@ -1603,6 +1611,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (old_version) { success = dp.unpackVector3(pos_key.mPosition, "pos"); + + //MAINT-6162 + pos_key.mPosition.mV[VX] = llclamp( pos_key.mPosition.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mPosition.mV[VY] = llclamp( pos_key.mPosition.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mPosition.mV[VZ] = llclamp( pos_key.mPosition.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + } else { @@ -1868,6 +1882,8 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const { BOOL success = TRUE; + LL_DEBUGS("BVH") << "serializing" << LL_ENDL; + success &= dp.packU16(KEYFRAME_MOTION_VERSION, "version"); success &= dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version"); success &= dp.packS32(mJointMotionList->mBasePriority, "base_priority"); @@ -1881,6 +1897,19 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const success &= dp.packU32(mJointMotionList->mHandPose, "hand_pose"); success &= dp.packU32(mJointMotionList->getNumJointMotions(), "num_joints"); + LL_DEBUGS("BVH") << "version " << KEYFRAME_MOTION_VERSION << LL_ENDL; + LL_DEBUGS("BVH") << "sub_version " << KEYFRAME_MOTION_SUBVERSION << LL_ENDL; + LL_DEBUGS("BVH") << "base_priority " << mJointMotionList->mBasePriority << LL_ENDL; + LL_DEBUGS("BVH") << "duration " << mJointMotionList->mDuration << LL_ENDL; + LL_DEBUGS("BVH") << "emote_name " << mJointMotionList->mEmoteName << LL_ENDL; + LL_DEBUGS("BVH") << "loop_in_point " << mJointMotionList->mLoopInPoint << LL_ENDL; + LL_DEBUGS("BVH") << "loop_out_point " << mJointMotionList->mLoopOutPoint << LL_ENDL; + LL_DEBUGS("BVH") << "loop " << mJointMotionList->mLoop << LL_ENDL; + LL_DEBUGS("BVH") << "ease_in_duration " << mJointMotionList->mEaseInDuration << LL_ENDL; + LL_DEBUGS("BVH") << "ease_out_duration " << mJointMotionList->mEaseOutDuration << LL_ENDL; + LL_DEBUGS("BVH") << "hand_pose " << mJointMotionList->mHandPose << LL_ENDL; + LL_DEBUGS("BVH") << "num_joints " << mJointMotionList->getNumJointMotions() << LL_ENDL; + for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++) { JointMotion* joint_motionp = mJointMotionList->getJointMotion(i); @@ -1888,6 +1917,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const success &= dp.packS32(joint_motionp->mPriority, "joint_priority"); success &= dp.packS32(joint_motionp->mRotationCurve.mNumKeys, "num_rot_keys"); + LL_DEBUGS("BVH") << "Joint " << joint_motionp->mJointName << LL_ENDL; for (RotationCurve::key_map_t::iterator iter = joint_motionp->mRotationCurve.mKeys.begin(); iter != joint_motionp->mRotationCurve.mKeys.end(); ++iter) { @@ -1905,6 +1935,8 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const success &= dp.packU16(x, "rot_angle_x"); success &= dp.packU16(y, "rot_angle_y"); success &= dp.packU16(z, "rot_angle_z"); + + LL_DEBUGS("BVH") << " rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL; } success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys"); @@ -1923,37 +1955,54 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const success &= dp.packU16(x, "pos_x"); success &= dp.packU16(y, "pos_y"); success &= dp.packU16(z, "pos_z"); + + LL_DEBUGS("BVH") << " pos: t " << pos_key.mTime << " pos " << pos_key.mPosition.mV[VX] <<","<< pos_key.mPosition.mV[VY] <<","<< pos_key.mPosition.mV[VZ] << LL_ENDL; } } success &= dp.packS32(mJointMotionList->mConstraints.size(), "num_constraints"); + LL_DEBUGS("BVH") << "num_constraints " << mJointMotionList->mConstraints.size() << LL_ENDL; for (JointMotionList::constraint_list_t::const_iterator iter = mJointMotionList->mConstraints.begin(); iter != mJointMotionList->mConstraints.end(); ++iter) { JointConstraintSharedData* shared_constraintp = *iter; success &= dp.packU8(shared_constraintp->mChainLength, "chain_length"); success &= dp.packU8(shared_constraintp->mConstraintType, "constraint_type"); - char volume_name[16]; /* Flawfinder: ignore */ - snprintf(volume_name, sizeof(volume_name), "%s", /* Flawfinder: ignore */ + char source_volume[16]; /* Flawfinder: ignore */ + snprintf(source_volume, sizeof(source_volume), "%s", /* Flawfinder: ignore */ mCharacter->findCollisionVolume(shared_constraintp->mSourceConstraintVolume)->getName().c_str()); - success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "source_volume"); + + success &= dp.packBinaryDataFixed((U8*)source_volume, 16, "source_volume"); success &= dp.packVector3(shared_constraintp->mSourceConstraintOffset, "source_offset"); + char target_volume[16]; /* Flawfinder: ignore */ if (shared_constraintp->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND) { - snprintf(volume_name,sizeof(volume_name), "%s", "GROUND"); /* Flawfinder: ignore */ + snprintf(target_volume,sizeof(target_volume), "%s", "GROUND"); /* Flawfinder: ignore */ } else { - snprintf(volume_name, sizeof(volume_name),"%s", /* Flawfinder: ignore */ + snprintf(target_volume, sizeof(target_volume),"%s", /* Flawfinder: ignore */ mCharacter->findCollisionVolume(shared_constraintp->mTargetConstraintVolume)->getName().c_str()); } - success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "target_volume"); + success &= dp.packBinaryDataFixed((U8*)target_volume, 16, "target_volume"); success &= dp.packVector3(shared_constraintp->mTargetConstraintOffset, "target_offset"); success &= dp.packVector3(shared_constraintp->mTargetConstraintDir, "target_dir"); success &= dp.packF32(shared_constraintp->mEaseInStartTime, "ease_in_start"); success &= dp.packF32(shared_constraintp->mEaseInStopTime, "ease_in_stop"); success &= dp.packF32(shared_constraintp->mEaseOutStartTime, "ease_out_start"); success &= dp.packF32(shared_constraintp->mEaseOutStopTime, "ease_out_stop"); + + LL_DEBUGS("BVH") << " chain_length " << shared_constraintp->mChainLength << LL_ENDL; + LL_DEBUGS("BVH") << " constraint_type " << (S32)shared_constraintp->mConstraintType << LL_ENDL; + LL_DEBUGS("BVH") << " source_volume " << source_volume << LL_ENDL; + LL_DEBUGS("BVH") << " source_offset " << shared_constraintp->mSourceConstraintOffset << LL_ENDL; + LL_DEBUGS("BVH") << " target_volume " << target_volume << LL_ENDL; + LL_DEBUGS("BVH") << " target_offset " << shared_constraintp->mTargetConstraintOffset << LL_ENDL; + LL_DEBUGS("BVH") << " target_dir " << shared_constraintp->mTargetConstraintDir << LL_ENDL; + LL_DEBUGS("BVH") << " ease_in_start " << shared_constraintp->mEaseInStartTime << LL_ENDL; + LL_DEBUGS("BVH") << " ease_in_stop " << shared_constraintp->mEaseInStopTime << LL_ENDL; + LL_DEBUGS("BVH") << " ease_out_start " << shared_constraintp->mEaseOutStartTime << LL_ENDL; + LL_DEBUGS("BVH") << " ease_out_stop " << shared_constraintp->mEaseOutStopTime << LL_ENDL; } return success; @@ -1972,6 +2021,51 @@ U32 LLKeyframeMotion::getFileSize() } //----------------------------------------------------------------------------- +// dumpToFile() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::dumpToFile(const std::string& name) +{ + if (isLoaded()) + { + std::string outfile_base; + if (!name.empty()) + { + outfile_base = name; + } + else if (!getName().empty()) + { + outfile_base = getName(); + } + else + { + const LLUUID& id = getID(); + outfile_base = id.asString(); + } + std::string outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base + ".anim"); + if (LLFile::isfile(outfilename)) + { + return; + } + + S32 file_size = getFileSize(); + U8* buffer = new U8[file_size]; + + LL_DEBUGS("BVH") << "Dumping " << outfilename << LL_ENDL; + LLDataPackerBinaryBuffer dp(buffer, file_size); + if (serialize(dp)) + { + LLAPRFile outfile; + outfile.open(outfilename, LL_APR_WPB); + if (outfile.getFileHandle()) + { + outfile.write(buffer, file_size); + } + } + delete [] buffer; + } +} + +//----------------------------------------------------------------------------- // getPelvisBBox() //----------------------------------------------------------------------------- const LLBBoxLocal &LLKeyframeMotion::getPelvisBBox() @@ -2149,7 +2243,7 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, LLCharacter* character = *char_iter; // look for an existing instance of this motion - LLKeyframeMotion* motionp = (LLKeyframeMotion*) character->findMotion(asset_uuid); + LLKeyframeMotion* motionp = dynamic_cast<LLKeyframeMotion*> (character->findMotion(asset_uuid)); if (motionp) { if (0 == status) @@ -2164,8 +2258,8 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, U8* buffer = new U8[size]; file.read((U8*)buffer, size); /*Flawfinder: ignore*/ - - LL_DEBUGS() << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL; + + LL_DEBUGS("Animation") << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL; LLDataPackerBinaryBuffer dp(buffer, size); if (motionp->deserialize(dp)) diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index b1422b2b90..f1fa56d731 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -153,6 +153,7 @@ public: BOOL serialize(LLDataPacker& dp) const; BOOL deserialize(LLDataPacker& dp); BOOL isLoaded() { return mJointMotionList != NULL; } + void dumpToFile(const std::string& name); // setters for modifying a keyframe animation diff --git a/indra/llcharacter/llkeyframestandmotion.cpp b/indra/llcharacter/llkeyframestandmotion.cpp index fdeddf55e1..02c1d3cdbd 100644 --- a/indra/llcharacter/llkeyframestandmotion.cpp +++ b/indra/llcharacter/llkeyframestandmotion.cpp @@ -201,10 +201,12 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask) //------------------------------------------------------------------------- // propagate joint positions to internal versions //------------------------------------------------------------------------- + // SL-315 mPelvisJoint.setPosition( root_world_pos + mPelvisState->getPosition() ); + // SL-315 mHipLeftJoint.setPosition( mHipLeftState->getJoint()->getPosition() ); mKneeLeftJoint.setPosition( mKneeLeftState->getJoint()->getPosition() ); mAnkleLeftJoint.setPosition( mAnkleLeftState->getJoint()->getPosition() ); @@ -213,6 +215,7 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask) mKneeLeftJoint.setScale( mKneeLeftState->getJoint()->getScale() ); mAnkleLeftJoint.setScale( mAnkleLeftState->getJoint()->getScale() ); + // SL-315 mHipRightJoint.setPosition( mHipRightState->getJoint()->getPosition() ); mKneeRightJoint.setPosition( mKneeRightState->getJoint()->getPosition() ); mAnkleRightJoint.setPosition( mAnkleRightState->getJoint()->getPosition() ); @@ -265,6 +268,7 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask) mCharacter->getGround( mAnkleLeftJoint.getWorldPosition(), mPositionLeft, mNormalLeft); mCharacter->getGround( mAnkleRightJoint.getWorldPosition(), mPositionRight, mNormalRight); + // SL-315 mTargetLeft.setPosition( mPositionLeft ); mTargetRight.setPosition( mPositionRight ); } diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp index 4803f855de..697efc8157 100644 --- a/indra/llcharacter/llmotion.cpp +++ b/indra/llcharacter/llmotion.cpp @@ -55,7 +55,7 @@ LLMotion::LLMotion( const LLUUID &id ) : mDeactivateCallbackUserData(NULL) { for (S32 i=0; i<3; ++i) - memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); + memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); } //----------------------------------------------------------------------------- @@ -111,9 +111,15 @@ void LLMotion::addJointState(const LLPointer<LLJointState>& jointState) U32 usage = jointState->getUsage(); // for now, usage is everything - mJointSignature[0][jointState->getJoint()->getJointNum()] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0; - mJointSignature[1][jointState->getJoint()->getJointNum()] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0; - mJointSignature[2][jointState->getJoint()->getJointNum()] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0; + S32 joint_num = jointState->getJoint()->getJointNum(); + if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0)) + { + LL_WARNS() << "joint_num " << joint_num << " is outside of legal range [0-" << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << jointState->getJoint()->getName() << LL_ENDL; + return; + } + mJointSignature[0][joint_num] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0; + mJointSignature[1][joint_num] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0; + mJointSignature[2][joint_num] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0; } void LLMotion::setDeactivateCallback( void (*cb)(void *), void* userdata ) diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h index 5e37f094b8..2dfc3afc7f 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -181,7 +181,7 @@ protected: F32 mSendStopTimestamp; // time when simulator should be told to stop this motion F32 mResidualWeight; // blend weight at beginning of stop motion phase F32 mFadeWeight; // for fading in and out based on LOD - U8 mJointSignature[3][LL_CHARACTER_MAX_JOINTS]; // signature of which joints are animated at what priority + U8 mJointSignature[3][LL_CHARACTER_MAX_ANIMATED_JOINTS]; // signature of which joints are animated at what priority void (*mDeactivateCallback)(void* data); void* mDeactivateCallbackUserData; }; diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index e02b139608..d8185aa693 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -37,7 +37,8 @@ #include "llanimationstates.h" #include "llstl.h" -const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_JOINTS / 4; +// This is why LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be a multiple of 4. +const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_ANIMATED_JOINTS / 4; const U32 MAX_MOTION_INSTANCES = 32; //----------------------------------------------------------------------------- @@ -488,8 +489,8 @@ void LLMotionController::updateAdditiveMotions() //----------------------------------------------------------------------------- void LLMotionController::resetJointSignatures() { - memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); - memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); + memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); + memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); } //----------------------------------------------------------------------------- @@ -553,9 +554,9 @@ static LLTrace::BlockTimerStatHandle FTM_MOTION_ON_UPDATE("Motion onUpdate"); void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type) { BOOL update_result = TRUE; - U8 last_joint_signature[LL_CHARACTER_MAX_JOINTS]; + U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS]; - memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); + memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); // iterate through active motions in chronological order for (motion_list_t::iterator iter = mActiveMotions.begin(); @@ -576,7 +577,6 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty } else { - // NUM_JOINT_SIGNATURE_STRIDES should be multiple of 4 for (S32 i = 0; i < NUM_JOINT_SIGNATURE_STRIDES; i++) { U32 *current_signature = (U32*)&(mJointSignature[0][i * 4]); diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 2bd5271c4f..72de331694 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -223,7 +223,7 @@ protected: S32 mTimeStepCount; F32 mLastInterp; - U8 mJointSignature[2][LL_CHARACTER_MAX_JOINTS]; + U8 mJointSignature[2][LL_CHARACTER_MAX_ANIMATED_JOINTS]; }; //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llpose.cpp b/indra/llcharacter/llpose.cpp index b1a7ebb159..fc95fafd61 100644 --- a/indra/llcharacter/llpose.cpp +++ b/indra/llcharacter/llpose.cpp @@ -386,6 +386,7 @@ void LLJointStateBlender::blendJointStates(BOOL apply_now) } // apply transforms + // SL-315 target_joint->setPosition(blended_pos + added_pos); target_joint->setScale(blended_scale + added_scale); target_joint->setRotation(added_rot * blended_rot); @@ -417,6 +418,7 @@ void LLJointStateBlender::interpolate(F32 u) return; } + // SL-315 target_joint->setPosition(lerp(target_joint->getPosition(), mJointCache.getPosition(), u)); target_joint->setScale(lerp(target_joint->getScale(), mJointCache.getScale(), u)); target_joint->setRotation(nlerp(u, target_joint->getRotation(), mJointCache.getRotation())); @@ -444,6 +446,7 @@ void LLJointStateBlender::resetCachedJoint() return; } LLJoint* source_joint = mJointStates[0]->getJoint(); + // SL-315 mJointCache.setPosition(source_joint->getPosition()); mJointCache.setScale(source_joint->getScale()); mJointCache.setRotation(source_joint->getRotation()); diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h index c6b97d7e8b..0ad063fd1e 100644 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -150,6 +150,7 @@ public: F32 getWeight() const { return mIsAnimating ? mTargetWeight : mCurWeight; } F32 getCurrentWeight() const { return mCurWeight; } F32 getLastWeight() const { return mLastWeight; } + void setLastWeight(F32 val) { mLastWeight = val; } BOOL isAnimating() const { return mIsAnimating; } BOOL isTweakable() const { return (getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) || (getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT); } diff --git a/indra/llcharacter/tests/lljoint_test.cpp b/indra/llcharacter/tests/lljoint_test.cpp index da151808f2..617f31b0e4 100644 --- a/indra/llcharacter/tests/lljoint_test.cpp +++ b/indra/llcharacter/tests/lljoint_test.cpp @@ -88,6 +88,7 @@ namespace tut { LLJoint lljoint; LLVector3 vec3(2.3f,30.f,10.f); + // SL-315 lljoint.setPosition(vec3); LLVector3 pos = lljoint.getPosition(); ensure("setPosition()/getPosition() failed ", (vec3 == pos)); @@ -98,6 +99,7 @@ namespace tut { LLJoint lljoint; LLVector3 vec3(2.3f,30.f,10.f); + // SL-315 lljoint.setWorldPosition(vec3); LLVector3 pos = lljoint.getWorldPosition(); ensure("1:setWorldPosition()/getWorldPosition() failed ", (vec3 == pos)); diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 44f45144e5..5bce2b8809 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -40,6 +40,7 @@ set(llcommon_SOURCE_FILES llbase64.cpp llbitpack.cpp llcallbacklist.cpp + llcallstack.cpp llcommon.cpp llcommonutils.cpp llcoros.cpp @@ -58,6 +59,7 @@ set(llcommon_SOURCE_FILES lleventfilter.cpp llevents.cpp lleventtimer.cpp + llexception.cpp llfasttimer.cpp llfile.cpp llfindlocale.cpp @@ -114,6 +116,7 @@ set(llcommon_SOURCE_FILES llworkerthread.cpp timing.cpp u64.cpp + StackWalker.cpp ) set(llcommon_HEADER_FILES @@ -134,6 +137,7 @@ set(llcommon_HEADER_FILES llbitpack.h llboost.h llcallbacklist.h + llcallstack.h llcommon.h llcommonutils.h llcoros.h @@ -236,6 +240,7 @@ set(llcommon_HEADER_FILES stringize.h timer.h u64.h + StackWalker.h ) set_source_files_properties(${llcommon_HEADER_FILES} @@ -316,7 +321,7 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llprocinfo "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lltrace "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}") @@ -329,6 +334,11 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llstreamqueue "" "${test_libs}") +## llexception_test.cpp isn't a regression test, and doesn't need to be run +## every build. It's to help a developer make implementation choices about +## throwing and catching exceptions. +##LL_ADD_INTEGRATION_TEST(llexception "" "${test_libs}") + # *TODO - reenable these once tcmalloc libs no longer break the build. #ADD_BUILD_TEST(llallocator llcommon) #ADD_BUILD_TEST(llallocator_heap_profile llcommon) diff --git a/indra/llcommon/StackWalker.cpp b/indra/llcommon/StackWalker.cpp new file mode 100644 index 0000000000..c0d3104099 --- /dev/null +++ b/indra/llcommon/StackWalker.cpp @@ -0,0 +1,1388 @@ +/********************************************************************** + * + * StackWalker.cpp + * http://stackwalker.codeplex.com/ + * + * + * $LicenseInfo:firstyear=2016&license=bsd$ + * + * Linden notes: Small modifications from the original source at https://stackwalker.codeplex.com/ + * + * History: + * 2005-07-27 v1 - First public release on http://www.codeproject.com/ + * http://www.codeproject.com/threads/StackWalker.asp + * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack + * (to simplify the usage) + * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL + * (should also be enough) + * - Changed to compile correctly with the PSDK of VC7.0 + * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined: + * it uses LPSTR instead of LPCSTR as first paremeter) + * - Added declarations to support VC5/6 without using 'dbghelp.h' + * - Added a 'pUserData' member to the ShowCallstack function and the + * PReadProcessMemoryRoutine declaration (to pass some user-defined data, + * which can be used in the readMemoryFunction-callback) + * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default + * - Added example for doing an exception-callstack-walking in main.cpp + * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268) + * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse! + * 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx + * Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN" + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx + * Fixed Bug: Compiling with "/Wall" + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx + * Fixed Bug: Now checking SymUseSymSrv + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx + * Fixed Bug: Support for recursive function calls + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx + * Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32" + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx + * Fixed Bug: SymDia is number 7, not 9! + * 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8! + * Thanks to Teajay which reported the bug... + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx + * 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory + * Thanks to Luiz Salamon which reported this "bug"... + * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx + * 2009-04-10 v9 License slihtly corrected (<ORGANIZATION> replaced) + * 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/ + * 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available + * 2010-04-15 v12 Added support for VS2010 RTM + * 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon: + * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx + * 2013-01-07 v14 Runtime Check Error VS2010 Debug Builds fixed: + * http://stackwalker.codeplex.com/workitem/10511 + * + * + * LICENSE (http://www.opensource.org/licenses/bsd-license.php) + * + * Copyright (c) 2005-2013, Jochen Kalmbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of Jochen Kalmbach nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ +#if LL_WINDOWS + +#include <windows.h> +#include <tchar.h> +#include <stdio.h> +#include <stdlib.h> +#pragma comment(lib, "version.lib") // for "VerQueryValue" +#pragma warning(disable:4826) + +#include "StackWalker.h" + + +// If VC7 and later, then use the shipped 'dbghelp.h'-file +#pragma pack(push,8) +#if _MSC_VER >= 1300 +#include <dbghelp.h> +#else +// inline the important dbghelp.h-declarations... +typedef enum { + SymNone = 0, + SymCoff, + SymCv, + SymPdb, + SymExport, + SymDeferred, + SymSym, + SymDia, + SymVirtual, + NumSymTypes +} SYM_TYPE; +typedef struct _IMAGEHLP_LINE64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) + PVOID Key; // internal + DWORD LineNumber; // line number in file + PCHAR FileName; // full filename + DWORD64 Address; // first instruction of line +} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; +typedef struct _IMAGEHLP_MODULE64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name +} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64; +typedef struct _IMAGEHLP_SYMBOL64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) + DWORD64 Address; // virtual address including dll base address + DWORD Size; // estimated size of symbol, can be zero + DWORD Flags; // info about the symbols, see the SYMF defines + DWORD MaxNameLength; // maximum size of symbol name in 'Name' + CHAR Name[1]; // symbol name (null terminated string) +} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; +typedef enum { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat +} ADDRESS_MODE; +typedef struct _tagADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; +} ADDRESS64, *LPADDRESS64; +typedef struct _KDHELP64 { + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 Reserved[8]; +} KDHELP64, *PKDHELP64; +typedef struct _tagSTACKFRAME64 { + ADDRESS64 AddrPC; // program counter + ADDRESS64 AddrReturn; // return address + ADDRESS64 AddrFrame; // frame pointer + ADDRESS64 AddrStack; // stack pointer + ADDRESS64 AddrBStore; // backing store pointer + PVOID FuncTableEntry; // pointer to pdata/fpo or NULL + DWORD64 Params[4]; // possible arguments to the function + BOOL Far; // WOW far call + BOOL Virtual; // is this a virtual frame? + DWORD64 Reserved[3]; + KDHELP64 KdHelp; +} STACKFRAME64, *LPSTACKFRAME64; +typedef +BOOL +(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( + HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead + ); +typedef +PVOID +(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( + HANDLE hProcess, + DWORD64 AddrBase + ); +typedef +DWORD64 +(__stdcall *PGET_MODULE_BASE_ROUTINE64)( + HANDLE hProcess, + DWORD64 Address + ); +typedef +DWORD64 +(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( + HANDLE hProcess, + HANDLE hThread, + LPADDRESS64 lpaddr + ); +#define SYMOPT_CASE_INSENSITIVE 0x00000001 +#define SYMOPT_UNDNAME 0x00000002 +#define SYMOPT_DEFERRED_LOADS 0x00000004 +#define SYMOPT_NO_CPP 0x00000008 +#define SYMOPT_LOAD_LINES 0x00000010 +#define SYMOPT_OMAP_FIND_NEAREST 0x00000020 +#define SYMOPT_LOAD_ANYTHING 0x00000040 +#define SYMOPT_IGNORE_CVREC 0x00000080 +#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 +#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 +#define SYMOPT_EXACT_SYMBOLS 0x00000400 +#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 +#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 +#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 +#define SYMOPT_PUBLICS_ONLY 0x00004000 +#define SYMOPT_NO_PUBLICS 0x00008000 +#define SYMOPT_AUTO_PUBLICS 0x00010000 +#define SYMOPT_NO_IMAGE_SEARCH 0x00020000 +#define SYMOPT_SECURE 0x00040000 +#define SYMOPT_DEBUG 0x80000000 +#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration +#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration; +#endif // _MSC_VER < 1300 +#pragma pack(pop) + +// Some missing defines (for VC5/6): +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + + +// secure-CRT_functions are only available starting with VC8 +#if _MSC_VER < 1400 +#define strcpy_s(dst, len, src) strcpy(dst, src) +#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src) +#define strcat_s(dst, len, src) strcat(dst, src) +#define _snprintf_s _snprintf +#define _tcscat_s _tcscat +#endif + +static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc) +{ + if (nMaxDestSize <= 0) return; + strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE); + szDest[nMaxDestSize-1] = 0; // INFO: _TRUNCATE will ensure that it is nul-terminated; but with older compilers (<1400) it uses "strncpy" and this does not!) +} // MyStrCpy + +// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL') +#define USED_CONTEXT_FLAGS CONTEXT_FULL + + +class StackWalkerInternal +{ +public: + StackWalkerInternal(StackWalker *parent, HANDLE hProcess) + { + m_parent = parent; + m_hDbhHelp = NULL; + pSC = NULL; + m_hProcess = hProcess; + m_szSymPath = NULL; + pSFTA = NULL; + pSGLFA = NULL; + pSGMB = NULL; + pSGMI = NULL; + pSGO = NULL; + pSGSFA = NULL; + pSI = NULL; + pSLM = NULL; + pSSO = NULL; + pSW = NULL; + pUDSN = NULL; + pSGSP = NULL; + } + ~StackWalkerInternal() + { + if (pSC != NULL) + pSC(m_hProcess); // SymCleanup + if (m_hDbhHelp != NULL) + FreeLibrary(m_hDbhHelp); + m_hDbhHelp = NULL; + m_parent = NULL; + if(m_szSymPath != NULL) + free(m_szSymPath); + m_szSymPath = NULL; + } + BOOL Init(LPCSTR szSymPath) + { + if (m_parent == NULL) + return FALSE; + // Dynamically load the Entry-Points for dbghelp.dll: + // First try to load the newsest one from + TCHAR szTemp[4096]; + // But before wqe do this, we first check if the ".local" file exists + if (GetModuleFileName(NULL, szTemp, 4096) > 0) + { + _tcscat_s(szTemp, _T(".local")); + if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES) + { + // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows" + // Ok, first try the new path according to the archtitecture: +#ifdef _M_IX86 + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#elif _M_X64 + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#elif _M_IA64 + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#endif + // If still not found, try the old directories... + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll")); + // now check if the file exists: + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#if defined _M_X64 || defined _M_IA64 + // Still not found? Then try to load the (old) 64-Bit version: + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) + { + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll")); + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) + { + m_hDbhHelp = LoadLibrary(szTemp); + } + } +#endif + } + } + if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one + m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") ); + if (m_hDbhHelp == NULL) + return FALSE; + pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" ); + pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" ); + + pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" ); + pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" ); + pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" ); + + pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" ); + pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" ); + pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" ); + pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" ); + pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" ); + pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" ); + pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" ); + pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" ); + + if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || + pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL || + pSW == NULL || pUDSN == NULL || pSLM == NULL ) + { + FreeLibrary(m_hDbhHelp); + m_hDbhHelp = NULL; + pSC = NULL; + return FALSE; + } + + // SymInitialize + if (szSymPath != NULL) + m_szSymPath = _strdup(szSymPath); + if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) + this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); + + DWORD symOptions = this->pSGO(); // SymGetOptions + symOptions |= SYMOPT_LOAD_LINES; + symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; + //symOptions |= SYMOPT_NO_PROMPTS; + // SymSetOptions + symOptions = this->pSSO(symOptions); + + char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0}; + if (this->pSGSP != NULL) + { + if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE) + this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0); + } + char szUserName[1024] = {0}; + DWORD dwSize = 1024; + GetUserNameA(szUserName, &dwSize); + this->m_parent->OnSymInit(buf, symOptions, szUserName); + + return TRUE; + } + + StackWalker *m_parent; + + HMODULE m_hDbhHelp; + HANDLE m_hProcess; + LPSTR m_szSymPath; + +#pragma pack(push,8) +typedef struct IMAGEHLP_MODULE64_V3 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name + // new elements: 07-Jun-2002 + CHAR LoadedPdbName[256]; // pdb file name + DWORD CVSig; // Signature of the CV record in the debug directories + CHAR CVData[MAX_PATH * 3]; // Contents of the CV record + DWORD PdbSig; // Signature of PDB + GUID PdbSig70; // Signature of PDB (VC 7 and up) + DWORD PdbAge; // DBI age of pdb + BOOL PdbUnmatched; // loaded an unmatched pdb + BOOL DbgUnmatched; // loaded an unmatched dbg + BOOL LineNumbers; // we have line number information + BOOL GlobalSymbols; // we have internal symbol information + BOOL TypeInfo; // we have type information + // new elements: 17-Dec-2003 + BOOL SourceIndexed; // pdb supports source server + BOOL Publics; // contains public symbols +}; + +typedef struct IMAGEHLP_MODULE64_V2 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name +}; +#pragma pack(pop) + + + // SymCleanup() + typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess ); + tSC pSC; + + // SymFunctionTableAccess64() + typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase ); + tSFTA pSFTA; + + // SymGetLineFromAddr64() + typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, + OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line ); + tSGLFA pSGLFA; + + // SymGetModuleBase64() + typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr ); + tSGMB pSGMB; + + // SymGetModuleInfo64() + typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo ); + tSGMI pSGMI; + + // SymGetOptions() + typedef DWORD (__stdcall *tSGO)( VOID ); + tSGO pSGO; + + // SymGetSymFromAddr64() + typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, + OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol ); + tSGSFA pSGSFA; + + // SymInitialize() + typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess ); + tSI pSI; + + // SymLoadModule64() + typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile, + IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll ); + tSLM pSLM; + + // SymSetOptions() + typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions ); + tSSO pSSO; + + // StackWalk64() + typedef BOOL (__stdcall *tSW)( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, + PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress ); + tSW pSW; + + // UnDecorateSymbolName() + typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName, + DWORD UndecoratedLength, DWORD Flags ); + tUDSN pUDSN; + + typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength); + tSGSP pSGSP; + + +private: + // **************************************** ToolHelp32 ************************ + #define MAX_MODULE_NAME32 255 + #define TH32CS_SNAPMODULE 0x00000008 + #pragma pack( push, 8 ) + typedef struct tagMODULEENTRY32 + { + DWORD dwSize; + DWORD th32ModuleID; // This module + DWORD th32ProcessID; // owning process + DWORD GlblcntUsage; // Global usage count on the module + DWORD ProccntUsage; // Module usage count in th32ProcessID's context + BYTE * modBaseAddr; // Base address of module in th32ProcessID's context + DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr + HMODULE hModule; // The hModule of this module in th32ProcessID's context + char szModule[MAX_MODULE_NAME32 + 1]; + char szExePath[MAX_PATH]; + } MODULEENTRY32; + typedef MODULEENTRY32 * PMODULEENTRY32; + typedef MODULEENTRY32 * LPMODULEENTRY32; + #pragma pack( pop ) + + BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid) + { + // CreateToolhelp32Snapshot() + typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID); + // Module32First() + typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); + // Module32Next() + typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); + + // try both dlls... + const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") }; + HINSTANCE hToolhelp = NULL; + tCT32S pCT32S = NULL; + tM32F pM32F = NULL; + tM32N pM32N = NULL; + + HANDLE hSnap; + MODULEENTRY32 me; + me.dwSize = sizeof(me); + BOOL keepGoing; + size_t i; + + for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ ) + { + hToolhelp = LoadLibrary( dllname[i] ); + if (hToolhelp == NULL) + continue; + pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot"); + pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First"); + pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next"); + if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) ) + break; // found the functions! + FreeLibrary(hToolhelp); + hToolhelp = NULL; + } + + if (hToolhelp == NULL) + return FALSE; + + hSnap = pCT32S( TH32CS_SNAPMODULE, pid ); + if (hSnap == (HANDLE) -1) + { + FreeLibrary(hToolhelp); + return FALSE; + } + + keepGoing = !!pM32F( hSnap, &me ); + int cnt = 0; + while (keepGoing) + { + this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize); + cnt++; + keepGoing = !!pM32N( hSnap, &me ); + } + CloseHandle(hSnap); + FreeLibrary(hToolhelp); + if (cnt <= 0) + return FALSE; + return TRUE; + } // GetModuleListTH32 + + // **************************************** PSAPI ************************ + typedef struct _MODULEINFO { + LPVOID lpBaseOfDll; + DWORD SizeOfImage; + LPVOID EntryPoint; + } MODULEINFO, *LPMODULEINFO; + + BOOL GetModuleListPSAPI(HANDLE hProcess) + { + // EnumProcessModules() + typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ); + // GetModuleFileNameEx() + typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); + // GetModuleBaseName() + typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); + // GetModuleInformation() + typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize ); + + HINSTANCE hPsapi; + tEPM pEPM; + tGMFNE pGMFNE; + tGMBN pGMBN; + tGMI pGMI; + + DWORD i; + //ModuleEntry e; + DWORD cbNeeded; + MODULEINFO mi; + HMODULE *hMods = 0; + char *tt = NULL; + char *tt2 = NULL; + const SIZE_T TTBUFLEN = 8096; + int cnt = 0; + + hPsapi = LoadLibrary( _T("psapi.dll") ); + if (hPsapi == NULL) + return FALSE; + + pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" ); + pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" ); + pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" ); + pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" ); + if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) ) + { + // we couldnt find all functions + FreeLibrary(hPsapi); + return FALSE; + } + + hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE))); + tt = (char*) malloc(sizeof(char) * TTBUFLEN); + tt2 = (char*) malloc(sizeof(char) * TTBUFLEN); + if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) ) + goto cleanup; + + if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) ) + { + //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle ); + goto cleanup; + } + + if ( cbNeeded > TTBUFLEN ) + { + //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) ); + goto cleanup; + } + + for ( i = 0; i < cbNeeded / sizeof(hMods[0]); i++ ) + { + // base address, size + pGMI(hProcess, hMods[i], &mi, sizeof(mi)); + // image file name + tt[0] = 0; + pGMFNE(hProcess, hMods[i], tt, TTBUFLEN ); + // module name + tt2[0] = 0; + pGMBN(hProcess, hMods[i], tt2, TTBUFLEN ); + + DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage); + if (dwRes != ERROR_SUCCESS) + this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0); + cnt++; + } + + cleanup: + if (hPsapi != NULL) FreeLibrary(hPsapi); + if (tt2 != NULL) free(tt2); + if (tt != NULL) free(tt); + if (hMods != NULL) free(hMods); + + return cnt != 0; + } // GetModuleListPSAPI + + DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size) + { + CHAR *szImg = _strdup(img); + CHAR *szMod = _strdup(mod); + DWORD result = ERROR_SUCCESS; + if ( (szImg == NULL) || (szMod == NULL) ) + result = ERROR_NOT_ENOUGH_MEMORY; + else + { + if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0) + result = GetLastError(); + } + ULONGLONG fileVersion = 0; + if ( (m_parent != NULL) && (szImg != NULL) ) + { + // try to retrive the file-version: + if ( (this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0) + { + VS_FIXEDFILEINFO *fInfo = NULL; + DWORD dwHandle; + DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle); + if (dwSize > 0) + { + LPVOID vData = malloc(dwSize); + if (vData != NULL) + { + if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0) + { + UINT len; + TCHAR szSubBlock[] = _T("\\"); + if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0) + fInfo = NULL; + else + { + fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32); + } + } + free(vData); + } + } + } + + // Retrive some additional-infos about the module + IMAGEHLP_MODULE64_V3 Module; + const char *szSymType = "-unknown-"; + if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE) + { + switch(Module.SymType) + { + case SymNone: + szSymType = "-nosymbols-"; + break; + case SymCoff: // 1 + szSymType = "COFF"; + break; + case SymCv: // 2 + szSymType = "CV"; + break; + case SymPdb: // 3 + szSymType = "PDB"; + break; + case SymExport: // 4 + szSymType = "-exported-"; + break; + case SymDeferred: // 5 + szSymType = "-deferred-"; + break; + case SymSym: // 6 + szSymType = "SYM"; + break; + case 7: // SymDia: + szSymType = "DIA"; + break; + case 8: //SymVirtual: + szSymType = "Virtual"; + break; + } + } + LPCSTR pdbName = Module.LoadedImageName; + if (Module.LoadedPdbName[0] != 0) + pdbName = Module.LoadedPdbName; + this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName, fileVersion); + } + if (szImg != NULL) free(szImg); + if (szMod != NULL) free(szMod); + return result; + } +public: + BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId) + { + // first try toolhelp32 + if (GetModuleListTH32(hProcess, dwProcessId)) + return true; + // then try psapi + return GetModuleListPSAPI(hProcess); + } + + + BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3 *pModuleInfo) + { + memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3)); + if(this->pSGMI == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + // First try to use the larger ModuleInfo-Structure + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); + void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites... + if (pData == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3)); + static bool s_useV3Version = true; + if (s_useV3Version) + { + if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE) + { + // only copy as much memory as is reserved... + memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3)); + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); + free(pData); + return TRUE; + } + s_useV3Version = false; // to prevent unneccessarry calls with the larger struct... + } + + // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)... + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); + memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2)); + if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE) + { + // only copy as much memory as is reserved... + memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2)); + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); + free(pData); + return TRUE; + } + free(pData); + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } +}; + +// ############################################################# +StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) +{ + this->m_verbose = true; + this->m_options = OptionsAll; + this->m_modulesLoaded = FALSE; + this->m_hProcess = hProcess; + this->m_sw = new StackWalkerInternal(this, this->m_hProcess); + this->m_dwProcessId = dwProcessId; + this->m_szSymPath = NULL; + this->m_MaxRecursionCount = 1000; +} +StackWalker::StackWalker(bool verbose, int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) +{ + this->m_verbose = verbose; + this->m_options = options; + this->m_modulesLoaded = FALSE; + this->m_hProcess = hProcess; + this->m_sw = new StackWalkerInternal(this, this->m_hProcess); + this->m_dwProcessId = dwProcessId; + if (szSymPath != NULL) + { + this->m_szSymPath = _strdup(szSymPath); + this->m_options |= SymBuildPath; + } + else + this->m_szSymPath = NULL; + this->m_MaxRecursionCount = 1000; +} + +StackWalker::~StackWalker() +{ + if (m_szSymPath != NULL) + free(m_szSymPath); + m_szSymPath = NULL; + if (this->m_sw != NULL) + delete this->m_sw; + this->m_sw = NULL; +} + +BOOL StackWalker::LoadModules() +{ + if (this->m_sw == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + if (m_modulesLoaded != FALSE) + return TRUE; + + // Build the sym-path: + char *szSymPath = NULL; + if ( (this->m_options & SymBuildPath) != 0) + { + const size_t nSymPathLen = 4096; + szSymPath = (char*) malloc(nSymPathLen); + if (szSymPath == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + szSymPath[0] = 0; + // Now first add the (optional) provided sympath: + if (this->m_szSymPath != NULL) + { + strcat_s(szSymPath, nSymPathLen, this->m_szSymPath); + strcat_s(szSymPath, nSymPathLen, ";"); + } + + strcat_s(szSymPath, nSymPathLen, ".;"); + + const size_t nTempLen = 1024; + char szTemp[nTempLen]; + // Now add the current directory: + if (GetCurrentDirectoryA(nTempLen, szTemp) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + + // Now add the path for the main-module: + if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p) + { + // locate the rightmost path separator + if ( (*p == '\\') || (*p == '/') || (*p == ':') ) + { + *p = 0; + break; + } + } // for (search for path separator...) + if (strlen(szTemp) > 0) + { + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + } + if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + // also add the "system32"-directory: + strcat_s(szTemp, nTempLen, "\\system32"); + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, ";"); + } + + if ( (this->m_options & SymUseSymSrv) != 0) + { + if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0) + { + szTemp[nTempLen-1] = 0; + strcat_s(szSymPath, nSymPathLen, "SRV*"); + strcat_s(szSymPath, nSymPathLen, szTemp); + strcat_s(szSymPath, nSymPathLen, "\\websymbols"); + strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;"); + } + else + strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"); + } + } // if SymBuildPath + + // First Init the whole stuff... + BOOL bRet = this->m_sw->Init(szSymPath); + if (szSymPath != NULL) free(szSymPath); szSymPath = NULL; + if (bRet == FALSE) + { + this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0); + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId); + if (bRet != FALSE) + m_modulesLoaded = TRUE; + return bRet; +} + + +// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction +// This has to be done due to a problem with the "hProcess"-parameter in x64... +// Because this class is in no case multi-threading-enabled (because of the limitations +// of dbghelp.dll) it is "safe" to use a static-variable +static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; +static LPVOID s_readMemoryFunction_UserData = NULL; + +BOOL StackWalker::ShowCallstack(bool verbose, HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData) +{ + m_verbose = verbose; + CONTEXT c; + CallstackEntry csEntry; + IMAGEHLP_SYMBOL64 *pSym = NULL; + StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module; + IMAGEHLP_LINE64 Line; + int frameNum; + bool bLastEntryCalled = true; + int curRecursionCount = 0; + + if (m_modulesLoaded == FALSE) + this->LoadModules(); // ignore the result... + + if (this->m_sw->m_hDbhHelp == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + s_readMemoryFunction = readMemoryFunction; + s_readMemoryFunction_UserData = pUserData; + + if (context == NULL) + { + // If no context is provided, capture the context + // See: https://stackwalker.codeplex.com/discussions/446958 +#if _WIN32_WINNT <= 0x0501 + // If we need to support XP, we need to use the "old way", because "GetThreadId" is not available! + if (hThread == GetCurrentThread()) +#else + if (GetThreadId(hThread) == GetCurrentThreadId()) +#endif + { + GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS); + } + else + { + SuspendThread(hThread); + memset(&c, 0, sizeof(CONTEXT)); + c.ContextFlags = USED_CONTEXT_FLAGS; + if (GetThreadContext(hThread, &c) == FALSE) + { + ResumeThread(hThread); + return FALSE; + } + } + } + else + c = *context; + + // init STACKFRAME for first call + STACKFRAME64 s; // in/out stackframe + memset(&s, 0, sizeof(s)); + DWORD imageType; +#ifdef _M_IX86 + // normally, call ImageNtHeader() and use machine info from PE header + imageType = IMAGE_FILE_MACHINE_I386; + s.AddrPC.Offset = c.Eip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Ebp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Esp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_X64 + imageType = IMAGE_FILE_MACHINE_AMD64; + s.AddrPC.Offset = c.Rip; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.Rsp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrStack.Offset = c.Rsp; + s.AddrStack.Mode = AddrModeFlat; +#elif _M_IA64 + imageType = IMAGE_FILE_MACHINE_IA64; + s.AddrPC.Offset = c.StIIP; + s.AddrPC.Mode = AddrModeFlat; + s.AddrFrame.Offset = c.IntSp; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrBStore.Offset = c.RsBSP; + s.AddrBStore.Mode = AddrModeFlat; + s.AddrStack.Offset = c.IntSp; + s.AddrStack.Mode = AddrModeFlat; +#else +#error "Platform not supported!" +#endif + + pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); + if (!pSym) goto cleanup; // not enough memory... + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; + + memset(&Line, 0, sizeof(Line)); + Line.SizeOfStruct = sizeof(Line); + + memset(&Module, 0, sizeof(Module)); + Module.SizeOfStruct = sizeof(Module); + + for (frameNum = 0; ; ++frameNum ) + { + // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64()) + // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can + // assume that either you are done, or that the stack is so hosed that the next + // deeper frame could not be found. + // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386! + if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) ) + { + // INFO: "StackWalk64" does not set "GetLastError"... + this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset); + break; + } + + csEntry.offset = s.AddrPC.Offset; + csEntry.name[0] = 0; + csEntry.undName[0] = 0; + csEntry.undFullName[0] = 0; + csEntry.offsetFromSmybol = 0; + csEntry.offsetFromLine = 0; + csEntry.lineFileName[0] = 0; + csEntry.lineNumber = 0; + csEntry.loadedImageName[0] = 0; + csEntry.moduleName[0] = 0; + if (s.AddrPC.Offset == s.AddrReturn.Offset) + { + if ( (this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount) ) + { + this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset); + break; + } + curRecursionCount++; + } + else + curRecursionCount = 0; + if (s.AddrPC.Offset != 0) + { + // we seem to have a valid PC + // show procedure info (SymGetSymFromAddr64()) + if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE) + { + MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name); + // UnDecorateSymbolName() + this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY ); + this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE ); + } + else + { + this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset); + } + + // show line number info, NT5.0-method (SymGetLineFromAddr64()) + if (this->m_sw->pSGLFA != NULL ) + { // yes, we have SymGetLineFromAddr64() + if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE) + { + csEntry.lineNumber = Line.LineNumber; + MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName); + } + else + { + this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset); + } + } // yes, we have SymGetLineFromAddr64() + + if (m_verbose) // getting module info is very slow, skip unless we're being verbose. + { + // show module info (SymGetModuleInfo64()) + if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE) + { // got module info OK + switch ( Module.SymType ) + { + case SymNone: + csEntry.symTypeString = "-nosymbols-"; + break; + case SymCoff: + csEntry.symTypeString = "COFF"; + break; + case SymCv: + csEntry.symTypeString = "CV"; + break; + case SymPdb: + csEntry.symTypeString = "PDB"; + break; + case SymExport: + csEntry.symTypeString = "-exported-"; + break; + case SymDeferred: + csEntry.symTypeString = "-deferred-"; + break; + case SymSym: + csEntry.symTypeString = "SYM"; + break; +#if API_VERSION_NUMBER >= 9 + case SymDia: + csEntry.symTypeString = "DIA"; + break; +#endif + case 8: //SymVirtual: + csEntry.symTypeString = "Virtual"; + break; + default: + //_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType ); + csEntry.symTypeString = NULL; + break; + } + + MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName); + csEntry.baseOfImage = Module.BaseOfImage; + MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName); + } // got module info OK + else + { + this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset); + } + } + else + { + MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, "MODULE?"); + } + } // we seem to have a valid PC + + CallstackEntryType et = nextEntry; + if (frameNum == 0) + et = firstEntry; + bLastEntryCalled = false; + this->OnCallstackEntry(et, csEntry); + + if (s.AddrReturn.Offset == 0) + { + bLastEntryCalled = true; + this->OnCallstackEntry(lastEntry, csEntry); + SetLastError(ERROR_SUCCESS); + break; + } + } // for ( frameNum ) + + cleanup: + if (pSym) free( pSym ); + + if (bLastEntryCalled == false) + this->OnCallstackEntry(lastEntry, csEntry); + + if (context == NULL) + ResumeThread(hThread); + + return TRUE; +} + +BOOL __stdcall StackWalker::myReadProcMem( + HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead + ) +{ + if (s_readMemoryFunction == NULL) + { + SIZE_T st; + BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st); + *lpNumberOfBytesRead = (DWORD) st; + //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet); + return bRet; + } + else + { + return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData); + } +} + +void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + if (fileVersion == 0) + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName); + else + { + DWORD v4 = (DWORD) (fileVersion & 0xFFFF); + DWORD v3 = (DWORD) ((fileVersion>>16) & 0xFFFF); + DWORD v2 = (DWORD) ((fileVersion>>32) & 0xFFFF); + DWORD v1 = (DWORD) ((fileVersion>>48) & 0xFFFF); + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4); + } + if (m_verbose) + { + OnOutput(buffer); + } +} + +void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + if ( (eType != lastEntry) && (entry.offset != 0) ) + { + if (entry.name[0] == 0) + MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)"); + if (entry.undName[0] != 0) + MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName); + if (entry.undFullName[0] != 0) + MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName); + if (entry.lineFileName[0] == 0) + { + MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)"); + if (entry.moduleName[0] == 0) + MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)"); + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name); + } + else + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name); + buffer[STACKWALK_MAX_NAMELEN-1] = 0; + OnOutput(buffer); + } +} + +void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr); + if (m_verbose) + { + OnOutput(buffer); + } +} + +#pragma warning (disable : 4996) + +void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) +{ + CHAR buffer[STACKWALK_MAX_NAMELEN]; + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName); + if (m_verbose) + { + OnOutput(buffer); + } + // Also display the OS-version +#if _MSC_VER <= 1200 + OSVERSIONINFOA ver; + ZeroMemory(&ver, sizeof(OSVERSIONINFOA)); + ver.dwOSVersionInfoSize = sizeof(ver); + if (GetVersionExA(&ver) != FALSE) + { + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", + ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, + ver.szCSDVersion); + if (m_verbose) + { + OnOutput(buffer); + } + } +#else + OSVERSIONINFOEXA ver; + ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA)); + ver.dwOSVersionInfoSize = sizeof(ver); + if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE) + { + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", + ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, + ver.szCSDVersion, ver.wSuiteMask, ver.wProductType); + if (m_verbose) + { + OnOutput(buffer); + } + } +#endif +} + +void StackWalker::OnOutput(LPCSTR buffer) +{ + OutputDebugStringA(buffer); +} + +#endif // LL_WINDOWS diff --git a/indra/llcommon/StackWalker.h b/indra/llcommon/StackWalker.h new file mode 100644 index 0000000000..834f89c471 --- /dev/null +++ b/indra/llcommon/StackWalker.h @@ -0,0 +1,226 @@ +/********************************************************************** + * + * StackWalker.h + * + * + * + * $LicenseInfo:firstyear=2016&license=bsd$ + * + * Linden notes: Small modifications from the original source at https://stackwalker.codeplex.com/ + * + * LICENSE (http://www.opensource.org/licenses/bsd-license.php) + * + * Copyright (c) 2005-2009, Jochen Kalmbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of Jochen Kalmbach nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * **********************************************************************/ + +#if LL_WINDOWS + +// #pragma once is supported starting with _MCS_VER 1000, +// so we need not to check the version (because we only support _MSC_VER >= 1100)! +#pragma once + +#include <windows.h> + +// special defines for VC5/6 (if no actual PSDK is installed): +#if _MSC_VER < 1300 +typedef unsigned __int64 DWORD64, *PDWORD64; +#if defined(_WIN64) +typedef unsigned __int64 SIZE_T, *PSIZE_T; +#else +typedef unsigned long SIZE_T, *PSIZE_T; +#endif +#endif // _MSC_VER < 1300 + +class StackWalkerInternal; // forward +class StackWalker +{ +public: + typedef enum StackWalkOptions + { + // No addition info will be retrived + // (only the address is available) + RetrieveNone = 0, + + // Try to get the symbol-name + RetrieveSymbol = 1, + + // Try to get the line for this symbol + RetrieveLine = 2, + + // Try to retrieve the module-infos + RetrieveModuleInfo = 4, + + // Also retrieve the version for the DLL/EXE + RetrieveFileVersion = 8, + + // Contains all the abouve + RetrieveVerbose = 0xF, + + // Generate a "good" symbol-search-path + SymBuildPath = 0x10, + + // Also use the public Microsoft-Symbol-Server + SymUseSymSrv = 0x20, + + // Contains all the abouve "Sym"-options + SymAll = 0x30, + + // Contains all options (default) + OptionsAll = 0x3F + } StackWalkOptions; + + StackWalker( + bool verbose = true, + int options = OptionsAll, // 'int' is by design, to combine the enum-flags + LPCSTR szSymPath = NULL, + DWORD dwProcessId = GetCurrentProcessId(), + HANDLE hProcess = GetCurrentProcess() + ); + StackWalker(DWORD dwProcessId, HANDLE hProcess); + virtual ~StackWalker(); + + typedef BOOL (__stdcall *PReadProcessMemoryRoutine)( + HANDLE hProcess, + DWORD64 qwBaseAddress, + PVOID lpBuffer, + DWORD nSize, + LPDWORD lpNumberOfBytesRead, + LPVOID pUserData // optional data, which was passed in "ShowCallstack" + ); + + BOOL LoadModules(); + + BOOL ShowCallstack( + bool verbose, + HANDLE hThread = GetCurrentThread(), + const CONTEXT *context = NULL, + PReadProcessMemoryRoutine readMemoryFunction = NULL, + LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback + ); + +#if _MSC_VER >= 1300 +// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" +// in older compilers in order to use it... starting with VC7 we can declare it as "protected" +protected: +#endif + enum { STACKWALK_MAX_NAMELEN = 4096 }; // max name length for found symbols + +protected: + // Entry for each Callstack-Entry + typedef struct CallstackEntry + { + DWORD64 offset; // if 0, we have no valid entry + CHAR name[STACKWALK_MAX_NAMELEN]; + CHAR undName[STACKWALK_MAX_NAMELEN]; + CHAR undFullName[STACKWALK_MAX_NAMELEN]; + DWORD64 offsetFromSmybol; + DWORD offsetFromLine; + DWORD lineNumber; + CHAR lineFileName[STACKWALK_MAX_NAMELEN]; + DWORD symType; + LPCSTR symTypeString; + CHAR moduleName[STACKWALK_MAX_NAMELEN]; + DWORD64 baseOfImage; + CHAR loadedImageName[STACKWALK_MAX_NAMELEN]; + } CallstackEntry; + + typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry}; + + virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName); + virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion); + virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry); + virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr); + virtual void OnOutput(LPCSTR szText); + + StackWalkerInternal *m_sw; + HANDLE m_hProcess; + DWORD m_dwProcessId; + BOOL m_modulesLoaded; + LPSTR m_szSymPath; + + bool m_verbose; + int m_options; + int m_MaxRecursionCount; + + static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead); + + friend StackWalkerInternal; +}; // class StackWalker + + +// The "ugly" assembler-implementation is needed for systems before XP +// If you have a new PSDK and you only compile for XP and later, then you can use +// the "RtlCaptureContext" +// Currently there is no define which determines the PSDK-Version... +// So we just use the compiler-version (and assumes that the PSDK is +// the one which was installed by the VS-IDE) + +// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later... +// But I currently use it in x64/IA64 environments... +//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400) + +#if defined(_M_IX86) +#ifdef CURRENT_THREAD_VIA_EXCEPTION +// TODO: The following is not a "good" implementation, +// because the callstack is only valid in the "__except" block... +#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ + do { \ + memset(&c, 0, sizeof(CONTEXT)); \ + EXCEPTION_POINTERS *pExp = NULL; \ + __try { \ + throw 0; \ + } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \ + if (pExp != NULL) \ + memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \ + c.ContextFlags = contextFlags; \ + } while(0); +#else +// The following should be enough for walking the callstack... +#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ + do { \ + memset(&c, 0, sizeof(CONTEXT)); \ + c.ContextFlags = contextFlags; \ + __asm call x \ + __asm x: pop eax \ + __asm mov c.Eip, eax \ + __asm mov c.Ebp, ebp \ + __asm mov c.Esp, esp \ + } while(0); +#endif + +#else + +// The following is defined for x86 (XP and higher), x64 and IA64: +#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ + do { \ + memset(&c, 0, sizeof(CONTEXT)); \ + c.ContextFlags = contextFlags; \ + RtlCaptureContext(&c); \ +} while(0); +#endif + +#endif // LL_WINDOWS diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index a548c96002..86f407cdb0 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -294,9 +294,11 @@ void LLScopedLock::unlock() bool ll_apr_warn_status(apr_status_t status) { if(APR_SUCCESS == status) return false; +#if !LL_LINUX char buf[MAX_STRING]; /* Flawfinder: ignore */ apr_strerror(status, buf, sizeof(buf)); LL_WARNS("APR") << "APR: " << buf << LL_ENDL; +#endif return true; } diff --git a/indra/llcommon/llcallstack.cpp b/indra/llcommon/llcallstack.cpp new file mode 100644 index 0000000000..8db291eed1 --- /dev/null +++ b/indra/llcommon/llcallstack.cpp @@ -0,0 +1,190 @@ +/** + * @file llcallstack.cpp + * @brief run-time extraction of the current callstack + * + * $LicenseInfo:firstyear=2016&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2016, 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 "linden_common.h" + +#include "llcommon.h" +#include "llcallstack.h" +#include "StackWalker.h" +#include "llthreadlocalstorage.h" + +#if LL_WINDOWS +class LLCallStackImpl: public StackWalker +{ +public: + LLCallStackImpl(): + StackWalker(false,0) // non-verbose, options = 0 + { + } + ~LLCallStackImpl() + { + } + void getStack(std::vector<std::string>& stack, S32 skip_count=0, bool verbose=false) + { + m_stack.clear(); + ShowCallstack(verbose); + // Skip the first few lines because they're just bookkeeping for LLCallStack, + // plus any additional lines requested to skip. + S32 first_line = skip_count + 3; + for (S32 i=first_line; i<m_stack.size(); ++i) + { + stack.push_back(m_stack[i]); + } + } +protected: + virtual void OnOutput(LPCSTR szText) + { + m_stack.push_back(szText); + } + std::vector<std::string> m_stack; +}; +#else +// Stub - not implemented currently on other platforms. +class LLCallStackImpl +{ +public: + LLCallStackImpl() {} + ~LLCallStackImpl() {} + void getStack(std::vector<std::string>& stack, S32 skip_count=0, bool verbose=false) + { + stack.clear(); + } +}; +#endif + +LLCallStackImpl *LLCallStack::s_impl = NULL; + +LLCallStack::LLCallStack(S32 skip_count, bool verbose): + m_skipCount(skip_count), + m_verbose(verbose) +{ + if (!s_impl) + { + s_impl = new LLCallStackImpl; + } + LLTimer t; + s_impl->getStack(m_strings, m_skipCount, m_verbose); +} + +bool LLCallStack::contains(const std::string& str) +{ + for (std::vector<std::string>::const_iterator it = m_strings.begin(); + it != m_strings.end(); ++it) + { + if (it->find(str) != std::string::npos) + { + return true; + } + } + return false; +} + +std::ostream& operator<<(std::ostream& s, const LLCallStack& call_stack) +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD + std::vector<std::string>::const_iterator it; + for (it=call_stack.m_strings.begin(); it!=call_stack.m_strings.end(); ++it) + { + s << *it; + } +#else + s << "UNAVAILABLE IN RELEASE"; +#endif + return s; +} + +LLContextStrings::LLContextStrings() +{ +} + +// static +LLContextStrings* LLContextStrings::getThreadLocalInstance() +{ + LLContextStrings *cons = LLThreadLocalSingletonPointer<LLContextStrings>::getInstance(); + if (!cons) + { + LLThreadLocalSingletonPointer<LLContextStrings>::setInstance(new LLContextStrings); + } + return LLThreadLocalSingletonPointer<LLContextStrings>::getInstance(); +} + +// static +void LLContextStrings::addContextString(const std::string& str) +{ + LLContextStrings *cons = getThreadLocalInstance(); + //LL_INFOS() << "CTX " << (S32)cons << " ADD " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL; + cons->m_contextStrings[str]++; +} + +// static +void LLContextStrings::removeContextString(const std::string& str) +{ + LLContextStrings *cons = getThreadLocalInstance(); + cons->m_contextStrings[str]--; + //LL_INFOS() << "CTX " << (S32)cons << " REMOVE " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL; + if (cons->m_contextStrings[str] == 0) + { + cons->m_contextStrings.erase(str); + } +} + +// static +bool LLContextStrings::contains(const std::string& str) +{ + const std::map<std::string,S32>& strings = + LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->m_contextStrings; + for (std::map<std::string,S32>::const_iterator it = strings.begin(); it!=strings.end(); ++it) + { + if (it->first.find(str) != std::string::npos) + { + return true; + } + } + return false; +} + +// static +void LLContextStrings::output(std::ostream& os) +{ + const std::map<std::string,S32>& strings = + LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->m_contextStrings; + for (std::map<std::string,S32>::const_iterator it = strings.begin(); it!=strings.end(); ++it) + { + os << it->first << "[" << it->second << "]" << "\n"; + } +} + +// static +std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status) +{ + LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->output(s); + return s; +} + +bool LLContextStatus::contains(const std::string& str) +{ + return LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->contains(str); +} diff --git a/indra/llcommon/llcallstack.h b/indra/llcommon/llcallstack.h new file mode 100644 index 0000000000..1f7a7689d7 --- /dev/null +++ b/indra/llcommon/llcallstack.h @@ -0,0 +1,80 @@ +/** + * @file llcallstack.h + * @brief run-time extraction of the current callstack + * + * $LicenseInfo:firstyear=2016&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2016, 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 <map> + +class LLCallStackImpl; + +class LLCallStack +{ +public: + LLCallStack(S32 skip_count=0, bool verbose=false); + std::vector<std::string> m_strings; + bool m_verbose; + bool contains(const std::string& str); +private: + static LLCallStackImpl *s_impl; + S32 m_skipCount; +}; + +LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLCallStack& call_stack); + +class LLContextStrings +{ +public: + LLContextStrings(); + static void addContextString(const std::string& str); + static void removeContextString(const std::string& str); + static void output(std::ostream& os); + static LLContextStrings* getThreadLocalInstance(); + static bool contains(const std::string& str); +private: + std::map<std::string,S32> m_contextStrings; +}; + +class LLScopedContextString +{ +public: + LLScopedContextString(const std::string& str): + m_str(str) + { + LLContextStrings::addContextString(m_str); + } + ~LLScopedContextString() + { + LLContextStrings::removeContextString(m_str); + } +private: + std::string m_str; +}; + +// Mostly exists as a class to hook an ostream override to. +struct LLContextStatus +{ + bool contains(const std::string& str); +}; + +LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status); diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index d16bf0160b..8e516d8beb 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -38,6 +38,7 @@ #include "llevents.h" #include "llerror.h" #include "stringize.h" +#include "llexception.h" // do nothing, when we need nothing done void LLCoros::no_cleanup(CoroData*) {} @@ -131,9 +132,9 @@ bool LLCoros::cleanup(const LLSD&) if ((previousCount < 5) || !(previousCount % 50)) { if (previousCount < 5) - LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL; + LL_DEBUGS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL; else - LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << "("<< previousCount << ")" << LL_ENDL; + LL_DEBUGS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << "("<< previousCount << ")" << LL_ENDL; } // The erase() call will invalidate its passed iterator value -- @@ -185,9 +186,9 @@ std::string LLCoros::generateDistinctName(const std::string& prefix) const if ((previousCount < 5) || !(previousCount % 50)) { if (previousCount < 5) - LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL; + LL_DEBUGS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL; else - LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << "(" << previousCount << ")" << LL_ENDL; + LL_DEBUGS("LLCoros") << "LLCoros: launching coroutine " << name << "(" << previousCount << ")" << LL_ENDL; } @@ -223,7 +224,7 @@ std::string LLCoros::getName() const void LLCoros::setStackSize(S32 stacksize) { - LL_INFOS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL; + LL_DEBUGS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL; mStackSize = stacksize; } @@ -235,7 +236,23 @@ void LLCoros::toplevel(coro::self& self, CoroData* data, const callable_t& calla // capture the 'self' param in CoroData data->mSelf = &self; // run the code the caller actually wants in the coroutine - callable(); + try + { + callable(); + } + catch (const LLContinueError&) + { + // Any uncaught exception derived from LLContinueError will be caught + // here and logged. This coroutine will terminate but the rest of the + // viewer will carry on. + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << data->mName)); + } + catch (...) + { + // Any OTHER kind of uncaught exception will cause the viewer to + // crash, hopefully informatively. + CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << data->mName)); + } // This cleanup isn't perfectly symmetrical with the way we initially set // data->mPrev, but this is our last chance to reset mCurrentCoro. sCurrentCoro.reset(data->mPrev); diff --git a/indra/llcommon/lldependencies.cpp b/indra/llcommon/lldependencies.cpp index 87a699ff14..0d5757effd 100644 --- a/indra/llcommon/lldependencies.cpp +++ b/indra/llcommon/lldependencies.cpp @@ -39,8 +39,8 @@ #include <boost/graph/adjacency_list.hpp> #include <boost/graph/topological_sort.hpp> #include <boost/graph/exception.hpp> -#include <boost/throw_exception.hpp> // other Linden headers +#include "llexception.h" LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const EdgeList& edges) const { @@ -77,7 +77,7 @@ LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const // Omit independent nodes: display only those that might contribute to // the cycle. describe(out, false); - BOOST_THROW_EXCEPTION(Cycle(out.str())); + LLTHROW(Cycle(out.str())); } // A peculiarity of boost::topological_sort() is that it emits results in // REVERSE topological order: to get the result you want, you must diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 5ed348e13c..7887a942e9 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -921,11 +921,6 @@ namespace std::ostringstream message_stream; - if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation)) - { - message_stream << site.mLocationString << " "; - } - if (show_time && r->wantsTime() && s->mTimeFunction != NULL) { message_stream << s->mTimeFunction() << " "; @@ -933,17 +928,17 @@ namespace if (show_level && r->wantsLevel()) { - message_stream << site.mLevelString; + message_stream << site.mLevelString << " "; } if (show_tags && r->wantsTags()) { message_stream << site.mTagString; } - if ((show_level && r->wantsLevel())|| - (show_tags && r->wantsTags())) + + if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation)) { - message_stream << " "; + message_stream << site.mLocationString << " "; } if (show_function && r->wantsFunctionName()) @@ -1493,3 +1488,20 @@ namespace LLError } } +bool debugLoggingEnabled(const std::string& tag) +{ + const char* tags[] = {tag.c_str()}; + ::size_t tag_count = 1; + LLError::CallSite _site(LLError::LEVEL_DEBUG, __FILE__, __LINE__, + typeid(_LL_CLASS_TO_LOG), __FUNCTION__, false, tags, tag_count); + if (LL_UNLIKELY(_site.shouldLog())) + { + return true; + } + else + { + return false; + } +} + + diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 3beef65723..3573b3f44e 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -174,7 +174,8 @@ namespace LLError // not really a level // used to indicate that no messages should be logged }; - + // If you change ELevel, please update llvlog() macro below. + /* Macro support The classes CallSite and Log are used by the logging macros below. They are not intended for general use. @@ -305,24 +306,38 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; ///////////////////////////////// // Error Logging Macros -// See top of file for common usage. +// See top of file for common usage. ///////////////////////////////// -// this macro uses a one-shot do statement to avoid parsing errors when writing control flow statements -// without braces: -// if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL - -#define lllog(level, once, ...) \ - do { \ - const char* tags[] = {"", ##__VA_ARGS__}; \ - ::size_t tag_count = LL_ARRAY_SIZE(tags) - 1; \ - static LLError::CallSite _site( \ - level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, once, &tags[1], tag_count);\ - if (LL_UNLIKELY(_site.shouldLog())) \ - { \ - std::ostringstream* _out = LLError::Log::out(); \ +// Instead of using LL_DEBUGS(), LL_INFOS() et al., it may be tempting to +// directly code the lllog() macro so you can pass in the LLError::ELevel as a +// variable. DON'T DO IT! The reason is that the first time control passes +// through lllog(), it initializes a local static LLError::CallSite with that +// *first* ELevel value. All subsequent visits will decide whether or not to +// emit output based on the *first* ELevel value bound into that static +// CallSite instance. Use LL_VLOGS() instead. lllog() assumes its ELevel +// argument never varies. + +// this macro uses a one-shot do statement to avoid parsing errors when +// writing control flow statements without braces: +// if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL; + +#define lllog(level, once, ...) \ + do { \ + const char* tags[] = {"", ##__VA_ARGS__}; \ + static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \ + lllog_test_() + +#define lllog_test_() \ + if (LL_UNLIKELY(_site.shouldLog())) \ + { \ + std::ostringstream* _out = LLError::Log::out(); \ (*_out) +#define lllog_site_args_(level, once, tags) \ + level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \ + __FUNCTION__, once, &tags[1], LL_ARRAY_SIZE(tags)-1 + //Use this construct if you need to do computation in the middle of a //message: // @@ -363,4 +378,49 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; #define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__) #define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__) +// Use this if you need to pass LLError::ELevel as a variable. +#define LL_VLOGS(level, ...) llvlog(level, false, ##__VA_ARGS__) +#define LL_VLOGS_ONCE(level, ...) llvlog(level, true, ##__VA_ARGS__) + +// The problem with using lllog() with a variable level is that the first time +// through, it initializes a static CallSite instance with whatever level you +// pass. That first level is bound into the CallSite; the level parameter is +// never again examined. One approach to variable level would be to +// dynamically construct a CallSite instance every call -- which could get +// expensive, depending on context. So instead, initialize a static CallSite +// for each level value we support, then dynamically select the CallSite +// instance for the passed level value. +// Compare implementation to lllog() above. +#define llvlog(level, once, ...) \ + do { \ + const char* tags[] = {"", ##__VA_ARGS__}; \ + /* Need a static CallSite instance per expected ELevel value. */ \ + /* Since we intend to index this array with the ELevel, */ \ + /* _sites[0] should be ELevel(0), and so on -- avoid using */ \ + /* ELevel symbolic names when initializing -- except for */ \ + /* the last entry, which handles anything beyond the end. */ \ + /* (Commented ELevel value names are from 2016-09-01.) */ \ + /* Passing an ELevel past the end of this array is itself */ \ + /* a fatal error, so ensure the last is LEVEL_ERROR. */ \ + static LLError::CallSite _sites[] = \ + { \ + /* LEVEL_DEBUG */ \ + LLError::CallSite(lllog_site_args_(LLError::ELevel(0), once, tags)), \ + /* LEVEL_INFO */ \ + LLError::CallSite(lllog_site_args_(LLError::ELevel(1), once, tags)), \ + /* LEVEL_WARN */ \ + LLError::CallSite(lllog_site_args_(LLError::ELevel(2), once, tags)), \ + /* LEVEL_ERROR */ \ + LLError::CallSite(lllog_site_args_(LLError::LEVEL_ERROR, once, tags)) \ + }; \ + /* Clamp the passed 'level' to at most last entry */ \ + std::size_t which((std::size_t(level) >= LL_ARRAY_SIZE(_sites)) ? \ + (LL_ARRAY_SIZE(_sites) - 1) : std::size_t(level)); \ + /* selected CallSite *must* be named _site for LL_ENDL */ \ + LLError::CallSite& _site(_sites[which]); \ + lllog_test_() + +// Check at run-time whether logging is enabled, without generating output +bool debugLoggingEnabled(const std::string& tag); + #endif // LL_LLERROR_H diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index f444530a17..56367b8f54 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -34,12 +34,12 @@ #include <map> // std headers // external library headers -#include <boost/throw_exception.hpp> // other Linden headers #include "llsdserialize.h" #include "llerror.h" #include "llcoros.h" #include "llmake.h" +#include "llexception.h" #include "lleventfilter.h" @@ -352,7 +352,7 @@ LLSD errorException(const LLEventWithID& result, const std::string& desc) // returning it, deliver it via exception. if (result.second) { - BOOST_THROW_EXCEPTION(LLErrorEvent(desc, result.first)); + LLTHROW(LLErrorEvent(desc, result.first)); } // That way, our caller knows a simple return must be from the reply // pump (pump 0). diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 50919edb8e..97270e4931 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -45,7 +45,6 @@ #include <cctype> // external library headers #include <boost/range/iterator_range.hpp> -#include <boost/throw_exception.hpp> #if LL_WINDOWS #pragma warning (push) #pragma warning (disable : 4701) // compiler thinks might use uninitialized var, but no @@ -58,6 +57,7 @@ #include "stringize.h" #include "llerror.h" #include "llsdutil.h" +#include "llexception.h" #if LL_MSVC #pragma warning (disable : 4702) #endif @@ -175,7 +175,7 @@ std::string LLEventPumps::registerNew(const LLEventPump& pump, const std::string // Unless we're permitted to tweak it, that's Bad. if (! tweak) { - BOOST_THROW_EXCEPTION(LLEventPump::DupPumpName(std::string("Duplicate LLEventPump name '") + name + "'")); + LLTHROW(LLEventPump::DupPumpName("Duplicate LLEventPump name '" + name + "'")); } // The passed name isn't unique, but we're permitted to tweak it. Find the // first decimal-integer suffix not already taken. The insert() attempt @@ -276,6 +276,8 @@ LLEventPumps::~LLEventPumps() #pragma warning (push) #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally #endif +const std::string LLEventPump::ANONYMOUS = std::string(); + LLEventPump::LLEventPump(const std::string& name, bool tweak): // Register every new instance with LLEventPumps @@ -314,147 +316,162 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL const NameList& after, const NameList& before) { - // Check for duplicate name before connecting listener to mSignal - ConnectionMap::const_iterator found = mConnections.find(name); - // In some cases the user might disconnect a connection explicitly -- or - // might use LLEventTrackable to disconnect implicitly. Either way, we can - // end up retaining in mConnections a zombie connection object that's - // already been disconnected. Such a connection object can't be - // reconnected -- nor, in the case of LLEventTrackable, would we want to - // try, since disconnection happens with the destruction of the listener - // object. That means it's safe to overwrite a disconnected connection - // object with the new one we're attempting. The case we want to prevent - // is only when the existing connection object is still connected. - if (found != mConnections.end() && found->second.connected()) - { - BOOST_THROW_EXCEPTION( - DupListenerName(std::string("Attempt to register duplicate listener name '") + name + - "' on " + typeid(*this).name() + " '" + getName() + "'")); - } - // Okay, name is unique, try to reconcile its dependencies. Specify a new - // "node" value that we never use for an mSignal placement; we'll fix it - // later. - DependencyMap::node_type& newNode = mDeps.add(name, -1.0, after, before); - // What if this listener has been added, removed and re-added? In that - // case newNode already has a non-negative value because we never remove a - // listener from mDeps. But keep processing uniformly anyway in case the - // listener was added back with different dependencies. Then mDeps.sort() - // would put it in a different position, and the old newNode placement - // value would be wrong, so we'd have to reassign it anyway. Trust that - // re-adding a listener with the same dependencies is the trivial case for - // mDeps.sort(): it can just replay its cache. - DependencyMap::sorted_range sorted_range; - try - { - // Can we pick an order that works including this new entry? - sorted_range = mDeps.sort(); - } - catch (const DependencyMap::Cycle& e) - { - // No: the new node's after/before dependencies have made mDeps - // unsortable. If we leave the new node in mDeps, it will continue - // to screw up all future attempts to sort()! Pull it out. - mDeps.remove(name); - BOOST_THROW_EXCEPTION( - Cycle(std::string("New listener '") + name + "' on " + typeid(*this).name() + - " '" + getName() + "' would cause cycle: " + e.what())); - } - // Walk the list to verify that we haven't changed the order. - float previous = 0.0, myprev = 0.0; - DependencyMap::sorted_iterator mydmi = sorted_range.end(); // need this visible after loop - for (DependencyMap::sorted_iterator dmi = sorted_range.begin(); - dmi != sorted_range.end(); ++dmi) + float nodePosition = 1.0; + + // if the supplied name is empty we are not interested in the ordering mechanism + // and can bypass attempting to find the optimal location to insert the new + // listener. We'll just tack it on to the end. + if (!name.empty()) // should be the same as testing against ANONYMOUS { - // Since we've added the new entry with an invalid placement, - // recognize it and skip it. - if (dmi->first == name) + // Check for duplicate name before connecting listener to mSignal + ConnectionMap::const_iterator found = mConnections.find(name); + // In some cases the user might disconnect a connection explicitly -- or + // might use LLEventTrackable to disconnect implicitly. Either way, we can + // end up retaining in mConnections a zombie connection object that's + // already been disconnected. Such a connection object can't be + // reconnected -- nor, in the case of LLEventTrackable, would we want to + // try, since disconnection happens with the destruction of the listener + // object. That means it's safe to overwrite a disconnected connection + // object with the new one we're attempting. The case we want to prevent + // is only when the existing connection object is still connected. + if (found != mConnections.end() && found->second.connected()) { - // Remember the iterator belonging to our new node, and which - // placement value was 'previous' at that point. - mydmi = dmi; - myprev = previous; - continue; + LLTHROW(DupListenerName("Attempt to register duplicate listener name '" + name + + "' on " + typeid(*this).name() + " '" + getName() + "'")); } - // If the new node has rearranged the existing nodes, we'll find - // that their placement values are no longer in increasing order. - if (dmi->second < previous) + // Okay, name is unique, try to reconcile its dependencies. Specify a new + // "node" value that we never use for an mSignal placement; we'll fix it + // later. + DependencyMap::node_type& newNode = mDeps.add(name, -1.0, after, before); + // What if this listener has been added, removed and re-added? In that + // case newNode already has a non-negative value because we never remove a + // listener from mDeps. But keep processing uniformly anyway in case the + // listener was added back with different dependencies. Then mDeps.sort() + // would put it in a different position, and the old newNode placement + // value would be wrong, so we'd have to reassign it anyway. Trust that + // re-adding a listener with the same dependencies is the trivial case for + // mDeps.sort(): it can just replay its cache. + DependencyMap::sorted_range sorted_range; + try { - // This is another scenario in which we'd better back out the - // newly-added node from mDeps -- but don't do it yet, we want to - // traverse the existing mDeps to report on it! - // Describe the change to the order of our listeners. Copy - // everything but the newest listener to a vector we can sort to - // obtain the old order. - typedef std::vector< std::pair<float, std::string> > SortNameList; - SortNameList sortnames; - for (DependencyMap::sorted_iterator cdmi(sorted_range.begin()), cdmend(sorted_range.end()); - cdmi != cdmend; ++cdmi) + // Can we pick an order that works including this new entry? + sorted_range = mDeps.sort(); + } + catch (const DependencyMap::Cycle& e) + { + // No: the new node's after/before dependencies have made mDeps + // unsortable. If we leave the new node in mDeps, it will continue + // to screw up all future attempts to sort()! Pull it out. + mDeps.remove(name); + LLTHROW(Cycle("New listener '" + name + "' on " + typeid(*this).name() + + " '" + getName() + "' would cause cycle: " + e.what())); + } + // Walk the list to verify that we haven't changed the order. + float previous = 0.0, myprev = 0.0; + DependencyMap::sorted_iterator mydmi = sorted_range.end(); // need this visible after loop + for (DependencyMap::sorted_iterator dmi = sorted_range.begin(); + dmi != sorted_range.end(); ++dmi) + { + // Since we've added the new entry with an invalid placement, + // recognize it and skip it. + if (dmi->first == name) { - if (cdmi->first != name) - { - sortnames.push_back(SortNameList::value_type(cdmi->second, cdmi->first)); - } + // Remember the iterator belonging to our new node, and which + // placement value was 'previous' at that point. + mydmi = dmi; + myprev = previous; + continue; } - std::sort(sortnames.begin(), sortnames.end()); - std::ostringstream out; - out << "New listener '" << name << "' on " << typeid(*this).name() << " '" << getName() - << "' would move previous listener '" << dmi->first << "'\nwas: "; - SortNameList::const_iterator sni(sortnames.begin()), snend(sortnames.end()); - if (sni != snend) + // If the new node has rearranged the existing nodes, we'll find + // that their placement values are no longer in increasing order. + if (dmi->second < previous) { - out << sni->second; - while (++sni != snend) + // This is another scenario in which we'd better back out the + // newly-added node from mDeps -- but don't do it yet, we want to + // traverse the existing mDeps to report on it! + // Describe the change to the order of our listeners. Copy + // everything but the newest listener to a vector we can sort to + // obtain the old order. + typedef std::vector< std::pair<float, std::string> > SortNameList; + SortNameList sortnames; + for (DependencyMap::sorted_iterator cdmi(sorted_range.begin()), cdmend(sorted_range.end()); + cdmi != cdmend; ++cdmi) { - out << ", " << sni->second; + if (cdmi->first != name) + { + sortnames.push_back(SortNameList::value_type(cdmi->second, cdmi->first)); + } } - } - out << "\nnow: "; - DependencyMap::sorted_iterator ddmi(sorted_range.begin()), ddmend(sorted_range.end()); - if (ddmi != ddmend) - { - out << ddmi->first; - while (++ddmi != ddmend) + std::sort(sortnames.begin(), sortnames.end()); + std::ostringstream out; + out << "New listener '" << name << "' on " << typeid(*this).name() << " '" << getName() + << "' would move previous listener '" << dmi->first << "'\nwas: "; + SortNameList::const_iterator sni(sortnames.begin()), snend(sortnames.end()); + if (sni != snend) { - out << ", " << ddmi->first; + out << sni->second; + while (++sni != snend) + { + out << ", " << sni->second; + } } + out << "\nnow: "; + DependencyMap::sorted_iterator ddmi(sorted_range.begin()), ddmend(sorted_range.end()); + if (ddmi != ddmend) + { + out << ddmi->first; + while (++ddmi != ddmend) + { + out << ", " << ddmi->first; + } + } + // NOW remove the offending listener node. + mDeps.remove(name); + // Having constructed a description of the order change, inform caller. + LLTHROW(OrderChange(out.str())); } - // NOW remove the offending listener node. - mDeps.remove(name); - // Having constructed a description of the order change, inform caller. - BOOST_THROW_EXCEPTION(OrderChange(out.str())); + // This node becomes the previous one. + previous = dmi->second; } - // This node becomes the previous one. - previous = dmi->second; - } - // We just got done with a successful mDeps.add(name, ...) call. We'd - // better have found 'name' somewhere in that sorted list! - assert(mydmi != sorted_range.end()); - // Four cases: - // 0. name is the only entry: placement 1.0 - // 1. name is the first of several entries: placement (next placement)/2 - // 2. name is between two other entries: placement (myprev + (next placement))/2 - // 3. name is the last entry: placement ceil(myprev) + 1.0 - // Since we've cleverly arranged for myprev to be 0.0 if name is the - // first entry, this folds down to two cases. Case 1 is subsumed by - // case 2, and case 0 is subsumed by case 3. So we need only handle - // cases 2 and 3, which means we need only detect whether name is the - // last entry. Increment mydmi to see if there's anything beyond. - if (++mydmi != sorted_range.end()) - { - // The new node isn't last. Place it between the previous node and - // the successor. - newNode = (myprev + mydmi->second)/2.f; - } - else - { - // The new node is last. Bump myprev up to the next integer, add - // 1.0 and use that. - newNode = std::ceil(myprev) + 1.f; + // We just got done with a successful mDeps.add(name, ...) call. We'd + // better have found 'name' somewhere in that sorted list! + assert(mydmi != sorted_range.end()); + // Four cases: + // 0. name is the only entry: placement 1.0 + // 1. name is the first of several entries: placement (next placement)/2 + // 2. name is between two other entries: placement (myprev + (next placement))/2 + // 3. name is the last entry: placement ceil(myprev) + 1.0 + // Since we've cleverly arranged for myprev to be 0.0 if name is the + // first entry, this folds down to two cases. Case 1 is subsumed by + // case 2, and case 0 is subsumed by case 3. So we need only handle + // cases 2 and 3, which means we need only detect whether name is the + // last entry. Increment mydmi to see if there's anything beyond. + if (++mydmi != sorted_range.end()) + { + // The new node isn't last. Place it between the previous node and + // the successor. + newNode = (myprev + mydmi->second) / 2.f; + } + else + { + // The new node is last. Bump myprev up to the next integer, add + // 1.0 and use that. + newNode = std::ceil(myprev) + 1.f; + } + + nodePosition = newNode; } // Now that newNode has a value that places it appropriately in mSignal, // connect it. - LLBoundListener bound = mSignal->connect(newNode, listener); - mConnections[name] = bound; + LLBoundListener bound = mSignal->connect(nodePosition, listener); + + if (!name.empty()) + { // note that we are not tracking anonymous listeners here either. + // This means that it is the caller's responsibility to either assign + // to a TempBoundListerer (scoped_connection) or manually disconnect + // when done. + mConnections[name] = bound; + } return bound; } @@ -611,7 +628,7 @@ bool LLListenerOrPumpName::operator()(const LLSD& event) const { if (! mListener) { - BOOST_THROW_EXCEPTION(Empty("attempting to call uninitialized")); + LLTHROW(Empty("attempting to call uninitialized")); } return (*mListener)(event); } diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 8ff337911d..a3b9ec02e0 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -95,12 +95,32 @@ struct LLStopWhenHandled result_type operator()(InputIterator first, InputIterator last) const { for (InputIterator si = first; si != last; ++si) - { - if (*si) - { - return true; - } - } + { + try + { + if (*si) + { + return true; + } + } + catch (const LLContinueError&) + { + // We catch LLContinueError here because an LLContinueError- + // based exception means the viewer as a whole should carry on + // to the best of our ability. Therefore subsequent listeners + // on the same LLEventPump should still receive this event. + + // The iterator passed to a boost::signals2 Combiner is very + // clever, but provides no contextual information. We would + // very much like to be able to log the name of the LLEventPump + // plus the name of this particular listener, but alas. + LOG_UNHANDLED_EXCEPTION("LLEventPump"); + } + // We do NOT catch (...) here because we might as well let it + // propagate out to the generic handler. If we were able to log + // context information here, that would be great, but we can't, so + // there's no point. + } return false; } }; @@ -365,6 +385,8 @@ typedef boost::signals2::trackable LLEventTrackable; class LL_COMMON_API LLEventPump: public LLEventTrackable { public: + static const std::string ANONYMOUS; // constant for anonymous listeners. + /** * Exception thrown by LLEventPump(). You are trying to instantiate an * LLEventPump (subclass) using the same name as some other instance, and @@ -476,6 +498,12 @@ public: * instantiate your listener, then passing the same name on each listen() * call, allows us to optimize away the second and subsequent dependency * sorts. + * + * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire + * dependency and ordering calculation. In this case, it is critical that + * the result be assigned to a LLTempBoundListener or the listener is + * manually disconnected when no longer needed since there will be no + * way to later find and disconnect this listener manually. * * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a * listener, listen() will inspect the components of that expression. If a diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp new file mode 100644 index 0000000000..b32ec2c9c9 --- /dev/null +++ b/indra/llcommon/llexception.cpp @@ -0,0 +1,55 @@ +/** + * @file llexception.cpp + * @author Nat Goodspeed + * @date 2016-08-12 + * @brief Implementation for llexception. + * + * $LicenseInfo:firstyear=2016&license=viewerlgpl$ + * Copyright (c) 2016, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llexception.h" +// STL headers +// std headers +#include <typeinfo> +// external library headers +#include <boost/exception/diagnostic_information.hpp> +// other Linden headers +#include "llerror.h" +#include "llerrorcontrol.h" + +namespace { +// used by crash_on_unhandled_exception_() and log_unhandled_exception_() +void log_unhandled_exception_(LLError::ELevel level, + const char* file, int line, const char* pretty_function, + const std::string& context) +{ + // log same message but allow caller-specified severity level + LL_VLOGS(level, "LLException") << LLError::abbreviateFile(file) + << "(" << line << "): Unhandled exception caught in " << pretty_function; + if (! context.empty()) + { + LL_CONT << ": " << context; + } + LL_CONT << ":\n" << boost::current_exception_diagnostic_information() << LL_ENDL; +} +} + +void crash_on_unhandled_exception_(const char* file, int line, const char* pretty_function, + const std::string& context) +{ + // LL_ERRS() terminates and propagates message into crash dump. + log_unhandled_exception_(LLError::LEVEL_ERROR, file, line, pretty_function, context); +} + +void log_unhandled_exception_(const char* file, int line, const char* pretty_function, + const std::string& context) +{ + // Use LL_WARNS() because we seriously do not expect this to happen + // routinely, but we DO expect to return from this function. + log_unhandled_exception_(LLError::LEVEL_WARN, file, line, pretty_function, context); +} diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h index 3ac2f4762f..dfcb7c192f 100644 --- a/indra/llcommon/llexception.h +++ b/indra/llcommon/llexception.h @@ -14,22 +14,24 @@ #include <stdexcept> #include <boost/exception/exception.hpp> +#include <boost/throw_exception.hpp> +#include <boost/current_function.hpp> + +// "Found someone who can comfort me +// But there are always exceptions..." +// - Empty Pages, Traffic, from John Barleycorn (1970) +// https://www.youtube.com/watch?v=dRH0CGVK7ic /** * LLException is intended as the common base class from which all - * viewer-specific exceptions are derived. It is itself a subclass of - * boost::exception; use catch (const boost::exception& e) clause to log the - * string from boost::diagnostic_information(e). - * - * Since it is also derived from std::exception, a generic catch (const - * std::exception&) should also work, though what() is unlikely to be as - * informative as boost::diagnostic_information(). + * viewer-specific exceptions are derived. Rationale for why it's derived from + * both std::exception and boost::exception is explained in + * tests/llexception_test.cpp. * - * Please use BOOST_THROW_EXCEPTION() - * http://www.boost.org/doc/libs/release/libs/exception/doc/BOOST_THROW_EXCEPTION.html - * to throw viewer exceptions whenever possible. This enriches the exception's - * diagnostic_information() with the source file, line and containing function - * of the BOOST_THROW_EXCEPTION() macro. + * boost::current_exception_diagnostic_information() is quite wonderful: if + * all we need to do with an exception is log it, in most places we should + * catch (...) and log boost::current_exception_diagnostic_information(). + * See CRASH_ON_UNHANDLED_EXCEPTION() and LOG_UNHANDLED_EXCEPTION() below. * * There may be circumstances in which it would be valuable to distinguish an * exception explicitly thrown by viewer code from an exception thrown by @@ -60,4 +62,24 @@ struct LLContinueError: public LLException {} }; +/** + * Please use LLTHROW() to throw viewer exceptions whenever possible. This + * enriches the exception's diagnostic_information() with the source file, + * line and containing function of the LLTHROW() macro. + */ +// Currently we implement that using BOOST_THROW_EXCEPTION(). Wrap it in +// LLTHROW() in case we ever want to revisit that implementation decision. +#define LLTHROW(x) BOOST_THROW_EXCEPTION(x) + +/// Call this macro from a catch (...) clause +#define CRASH_ON_UNHANDLED_EXCEPTION(CONTEXT) \ + crash_on_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT) +void crash_on_unhandled_exception_(const char*, int, const char*, const std::string&); + +/// Call this from a catch (const LLContinueError&) clause, or from a catch +/// (...) clause in which you do NOT want the viewer to crash. +#define LOG_UNHANDLED_EXCEPTION(CONTEXT) \ + log_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT) +void log_unhandled_exception_(const char*, int, const char*, const std::string&); + #endif /* ! defined(LL_LLEXCEPTION_H) */ diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 2370253078..f56e5596f5 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -296,7 +296,16 @@ LL_FORCE_INLINE BlockTimer::BlockTimer(BlockTimerStatHandle& timer) { #if LL_FAST_TIMER_ON BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); - if (!cur_timer_data) return; + if (!cur_timer_data) + { + // How likely is it that + // LLThreadLocalSingletonPointer<T>::getInstance() will return NULL? + // Even without researching, what we can say is that if we exit + // without setting mStartTime at all, gcc 4.7 produces (fatal) + // warnings about a possibly-uninitialized data member. + mStartTime = 0; + return; + } TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); accumulator.mActiveCount++; // keep current parent as long as it is active when we are diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index a8bb9bc53a..c87d2a3e58 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -21,7 +21,6 @@ #include <boost/bind.hpp> #include <boost/scoped_ptr.hpp> #include <boost/tokenizer.hpp> -#include <boost/throw_exception.hpp> // other Linden headers #include "llerror.h" #include "llstring.h" @@ -34,6 +33,7 @@ #include "lltimer.h" #include "lluuid.h" #include "llleaplistener.h" +#include "llexception.h" #if LL_MSVC #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally @@ -70,7 +70,7 @@ public: // Rule out empty vector if (plugin.empty()) { - BOOST_THROW_EXCEPTION(Error("no plugin command")); + LLTHROW(Error("no plugin command")); } // Don't leave desc empty either, but in this case, if we weren't @@ -113,7 +113,7 @@ public: // If that didn't work, no point in keeping this LLLeap object. if (! mChild) { - BOOST_THROW_EXCEPTION(Error(STRINGIZE("failed to run " << mDesc))); + LLTHROW(Error(STRINGIZE("failed to run " << mDesc))); } // Okay, launch apparently worked. Change our mDonePump listener. diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 0fb257aab1..575edddc43 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -110,11 +110,15 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) #if defined(LL_WINDOWS) return _aligned_malloc(size, align); #else + char* aligned = NULL; void* mem = malloc( size + (align - 1) + sizeof(void*) ); - char* aligned = ((char*)mem) + sizeof(void*); - aligned += align - ((uintptr_t)aligned & (align - 1)); + if (mem) + { + aligned = ((char*)mem) + sizeof(void*); + aligned += align - ((uintptr_t)aligned & (align - 1)); - ((void**)aligned)[-1] = mem; + ((void**)aligned)[-1] = mem; + } return aligned; #endif } diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index ca19c94736..8c321d06b9 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -34,12 +34,12 @@ #include "llapr.h" #include "apr_signal.h" #include "llevents.h" +#include "llexception.h" #include <boost/foreach.hpp> #include <boost/bind.hpp> #include <boost/asio/streambuf.hpp> #include <boost/asio/buffers_iterator.hpp> -#include <boost/throw_exception.hpp> #include <iostream> #include <stdexcept> #include <limits> @@ -531,9 +531,8 @@ LLProcess::LLProcess(const LLSDOrParams& params): if (! params.validateBlock(true)) { - BOOST_THROW_EXCEPTION( - LLProcessError(STRINGIZE("not launched: failed parameter validation\n" - << LLSDNotationStreamer(params)))); + LLTHROW(LLProcessError(STRINGIZE("not launched: failed parameter validation\n" + << LLSDNotationStreamer(params)))); } mPostend = params.postend; @@ -598,11 +597,10 @@ LLProcess::LLProcess(const LLSDOrParams& params): } else { - BOOST_THROW_EXCEPTION( - LLProcessError(STRINGIZE("For " << params.executable() - << ": unsupported FileParam for " << which - << ": type='" << fparam.type() - << "', name='" << fparam.name() << "'"))); + LLTHROW(LLProcessError(STRINGIZE("For " << params.executable() + << ": unsupported FileParam for " << which + << ": type='" << fparam.type() + << "', name='" << fparam.name() << "'"))); } } // By default, pass APR_NO_PIPE for unspecified slots. @@ -681,7 +679,7 @@ LLProcess::LLProcess(const LLSDOrParams& params): if (ll_apr_warn_status(apr_proc_create(&mProcess, argv[0], &argv[0], NULL, procattr, gAPRPoolp))) { - BOOST_THROW_EXCEPTION(LLProcessError(STRINGIZE(params << " failed"))); + LLTHROW(LLProcessError(STRINGIZE(params << " failed"))); } // arrange to call status_callback() @@ -1066,7 +1064,7 @@ PIPETYPE& LLProcess::getPipe(FILESLOT slot) PIPETYPE* wp = getPipePtr<PIPETYPE>(error, slot); if (! wp) { - BOOST_THROW_EXCEPTION(NoPipe(error)); + LLTHROW(NoPipe(error)); } return *wp; } diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 0435cb8a08..b024b47225 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -242,7 +242,6 @@ inline T* get_ptr_in_map(const std::map<K,T*>& inmap, const K& key) template <typename K, typename T> inline bool is_in_map(const std::map<K,T>& inmap, const K& key) { - typedef typename std::map<K,T>::const_iterator map_iter; if(inmap.find(key) == inmap.end()) { return false; diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp index a004618e96..491f920c0f 100644 --- a/indra/llcommon/llthreadsafequeue.cpp +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -26,8 +26,8 @@ #include "linden_common.h" #include <apr_pools.h> #include <apr_queue.h> -#include <boost/throw_exception.hpp> #include "llthreadsafequeue.h" +#include "llexception.h" @@ -42,13 +42,13 @@ LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * po { if(mOwnsPool) { apr_status_t status = apr_pool_create(&mPool, 0); - if(status != APR_SUCCESS) BOOST_THROW_EXCEPTION(LLThreadSafeQueueError("failed to allocate pool")); + if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate pool")); } else { ; // No op. } apr_status_t status = apr_queue_create(&mQueue, capacity, mPool); - if(status != APR_SUCCESS) BOOST_THROW_EXCEPTION(LLThreadSafeQueueError("failed to allocate queue")); + if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate queue")); } @@ -69,9 +69,9 @@ void LLThreadSafeQueueImplementation::pushFront(void * element) apr_status_t status = apr_queue_push(mQueue, element); if(status == APR_EINTR) { - BOOST_THROW_EXCEPTION(LLThreadSafeQueueInterrupt()); + LLTHROW(LLThreadSafeQueueInterrupt()); } else if(status != APR_SUCCESS) { - BOOST_THROW_EXCEPTION(LLThreadSafeQueueError("push failed")); + LLTHROW(LLThreadSafeQueueError("push failed")); } else { ; // Success. } @@ -89,9 +89,9 @@ void * LLThreadSafeQueueImplementation::popBack(void) apr_status_t status = apr_queue_pop(mQueue, &element); if(status == APR_EINTR) { - BOOST_THROW_EXCEPTION(LLThreadSafeQueueInterrupt()); + LLTHROW(LLThreadSafeQueueInterrupt()); } else if(status != APR_SUCCESS) { - BOOST_THROW_EXCEPTION(LLThreadSafeQueueError("pop failed")); + LLTHROW(LLThreadSafeQueueError("pop failed")); } else { return element; } diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index 0b10438b9f..3094b627a2 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -257,7 +257,13 @@ F64Kilobytes Recording::getMean(const StatType<MemAccumulator>& stat) if (active_accumulator && active_accumulator->mSize.hasValue()) { - return F64Bytes(lerp(accumulator.mSize.getMean(), active_accumulator->mSize.getMean(), active_accumulator->mSize.getSampleCount() / (accumulator.mSize.getSampleCount() + active_accumulator->mSize.getSampleCount()))); + F32 t = 0.0f; + S32 div = accumulator.mSize.getSampleCount() + active_accumulator->mSize.getSampleCount(); + if (div > 0) + { + t = active_accumulator->mSize.getSampleCount() / div; + } + return F64Bytes(lerp(accumulator.mSize.getMean(), active_accumulator->mSize.getMean(), t)); } else { @@ -426,7 +432,13 @@ F64 Recording::getMean( const StatType<SampleAccumulator>& stat ) const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; if (active_accumulator && active_accumulator->hasValue()) { - return lerp(accumulator.getMean(), active_accumulator->getMean(), active_accumulator->getSampleCount() / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + F32 t = 0.0f; + S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); + if (div > 0) + { + t = active_accumulator->getSampleCount() / div; + } + return lerp(accumulator.getMean(), active_accumulator->getMean(), t); } else { @@ -506,7 +518,13 @@ F64 Recording::getMean( const StatType<EventAccumulator>& stat ) const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; if (active_accumulator && active_accumulator->hasValue()) { - return lerp(accumulator.getMean(), active_accumulator->getMean(), active_accumulator->getSampleCount() / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + F32 t = 0.0f; + S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); + if (div > 0) + { + t = active_accumulator->getSampleCount() / div; + } + return lerp(accumulator.getMean(), active_accumulator->getMean(), t); } else { diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index 82d0dc8b4b..c275b90120 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -205,9 +205,9 @@ void LLUriParser::glue(std::string& uri) const uri = first_part + second_part; } -void LLUriParser::glueFirst(std::string& uri) const +void LLUriParser::glueFirst(std::string& uri, bool use_scheme) const { - if (mScheme.size()) + if (use_scheme && mScheme.size()) { uri = mScheme; uri += "://"; diff --git a/indra/llcommon/lluriparser.h b/indra/llcommon/lluriparser.h index 2df8085ae6..cfbf54f3c8 100644 --- a/indra/llcommon/lluriparser.h +++ b/indra/llcommon/lluriparser.h @@ -60,7 +60,7 @@ public: void extractParts(); void glue(std::string& uri) const; - void glueFirst(std::string& uri) const; + void glueFirst(std::string& uri, bool use_scheme = true) const; void glueSecond(std::string& uri) const; bool test() const; S32 normalize(); diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 785cf47926..d4af2c6b01 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -83,7 +83,7 @@ unsigned int decode( char const * fiveChars ) throw( bad_input_data ) unsigned int ret = 0; for( int ix = 0; ix < 5; ++ix ) { char * s = strchr( encodeTable, fiveChars[ ix ] ); -if( s == 0 ) BOOST_THROW_EXCEPTION(bad_input_data()); +if( s == 0 ) LLTHROW(bad_input_data()); ret = ret * 85 + (s-encodeTable); } return ret; diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index f51279e817..20de205454 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -237,8 +237,21 @@ namespace tut void ErrorTestObject::test<4>() // file abbreviation { - std::string thisFile = __FILE__; - std::string abbreviateFile = LLError::abbreviateFile(thisFile); + std::string prev, abbreviateFile = __FILE__; + do + { + prev = abbreviateFile; + abbreviateFile = LLError::abbreviateFile(abbreviateFile); + // __FILE__ is assumed to end with + // indra/llcommon/tests/llerror_test.cpp. This test used to call + // abbreviateFile() exactly once, then check below whether it + // still contained the string 'indra'. That fails if the FIRST + // part of the pathname also contains indra! Certain developer + // machine images put local directory trees under + // /ngi-persist/indra, which is where we observe the problem. So + // now, keep calling abbreviateFile() until it returns its + // argument unchanged, THEN check. + } while (abbreviateFile != prev); ensure_ends_with("file name abbreviation", abbreviateFile, @@ -551,9 +564,9 @@ namespace tut function; writeReturningLocationAndFunction(location, function); - ensure_equals("order is location time type function message", + ensure_equals("order is time location type function message", message(0), - location + roswell() + " INFO: " + function + ": apple"); + roswell() + " INFO: " + location + function + ": apple"); } template<> template<> diff --git a/indra/llcommon/tests/llexception_test.cpp b/indra/llcommon/tests/llexception_test.cpp new file mode 100644 index 0000000000..6bee1943c2 --- /dev/null +++ b/indra/llcommon/tests/llexception_test.cpp @@ -0,0 +1,308 @@ +/** + * @file llexception_test.cpp + * @author Nat Goodspeed + * @date 2016-08-12 + * @brief Tests for throwing exceptions. + * + * This isn't a regression test: it doesn't need to be run every build, which + * is why the corresponding line in llcommon/CMakeLists.txt is commented out. + * Rather it's a head-to-head test of what kind of exception information we + * can collect from various combinations of exception base classes, type of + * throw verb and sequences of catch clauses. + * + * This "test" makes no ensure() calls: its output goes to stdout for human + * examination. + * + * As of 2016-08-12 with Boost 1.57, we come to the following conclusions. + * These should probably be re-examined from time to time as we update Boost. + * + * - It is indisputably beneficial to use BOOST_THROW_EXCEPTION() rather than + * plain throw. The macro annotates the exception object with the filename, + * line number and function name from which the exception was thrown. + * + * - That being the case, deriving only from boost::exception isn't an option. + * Every exception object passed to BOOST_THROW_EXCEPTION() must be derived + * directly or indirectly from std::exception. The only question is whether + * to also derive from boost::exception. We decided to derive LLException + * from both, as it makes message output slightly cleaner, but this is a + * trivial reason: if a strong reason emerges to prefer single inheritance, + * dropping the boost::exception base class shouldn't be a problem. + * + * - (As you will have guessed, ridiculous things like a char* or int or a + * class derived from neither boost::exception nor std::exception can only + * be caught by that specific type or (...), and + * boost::current_exception_diagnostic_information() simply throws up its + * hands and confesses utter ignorance. Stay away from such nonsense.) + * + * - But if you derive from std::exception, to nat's surprise, + * boost::current_exception_diagnostic_information() gives as much + * information about exceptions in a catch (...) clause as you can get from + * a specific catch (const std::exception&) clause, notably the concrete + * exception class and the what() string. So instead of a sequence like + * + * try { ... } + * catch (const boost::exception& e) { ... boost-flavored logging ... } + * catch (const std::exception& e) { ... std::exception logging ... } + * catch (...) { ... generic logging ... } + * + * we should be able to get away with only a catch (...) clause that logs + * boost::current_exception_diagnostic_information(). + * + * - Going further: boost::current_exception_diagnostic_information() provides + * just as much information even within a std::set_terminate() handler. So + * it might not even be strictly necessary to include a catch (...) clause + * since the viewer does use std::set_terminate(). + * + * - (We might consider adding a catch (int) clause because Kakadu internally + * throws ints, and who knows if one of those might leak out. If it does, + * boost::current_exception_diagnostic_information() can do nothing with it. + * A catch (int) clause could at least log the value and rethrow.) + * + * $LicenseInfo:firstyear=2016&license=viewerlgpl$ + * Copyright (c) 2016, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llexception.h" +// STL headers +// std headers +#include <typeinfo> +// external library headers +#include <boost/throw_exception.hpp> +// other Linden headers +#include "../test/lltut.h" + +// helper for display output +// usage: std::cout << center(some string value, fill char, width) << std::endl; +// (assumes it's the only thing on that particular line) +struct center +{ + center(const std::string& label, char fill, std::size_t width): + mLabel(label), + mFill(fill), + mWidth(width) + {} + + // Use friend declaration not because we need to grant access, but because + // it lets us declare a free operator like a member function. + friend std::ostream& operator<<(std::ostream& out, const center& ctr) + { + std::size_t padded = ctr.mLabel.length() + 2; + std::size_t left = (ctr.mWidth - padded) / 2; + std::size_t right = ctr.mWidth - left - padded; + return out << std::string(left, ctr.mFill) << ' ' << ctr.mLabel << ' ' + << std::string(right, ctr.mFill); + } + + std::string mLabel; + char mFill; + std::size_t mWidth; +}; + +/***************************************************************************** +* Four kinds of exceptions: derived from boost::exception, from +* std::exception, from both, from neither +*****************************************************************************/ +// Interestingly, we can't use this variant with BOOST_THROW_EXCEPTION() +// (which we want) -- we reach a failure topped by this comment: +// //All boost exceptions are required to derive from std::exception, +// //to ensure compatibility with BOOST_NO_EXCEPTIONS. +struct FromBoost: public boost::exception +{ + FromBoost(const std::string& what): mWhat(what) {} + ~FromBoost() throw() {} + std::string what() const { return mWhat; } + std::string mWhat; +}; + +struct FromStd: public std::runtime_error +{ + FromStd(const std::string& what): std::runtime_error(what) {} +}; + +struct FromBoth: public boost::exception, public std::runtime_error +{ + FromBoth(const std::string& what): std::runtime_error(what) {} +}; + +// Same deal with FromNeither: can't use with BOOST_THROW_EXCEPTION(). +struct FromNeither +{ + FromNeither(const std::string& what): mWhat(what) {} + std::string what() const { return mWhat; } + std::string mWhat; +}; + +/***************************************************************************** +* Two kinds of throws: plain throw and BOOST_THROW_EXCEPTION() +*****************************************************************************/ +template <typename EXC> +void plain_throw(const std::string& what) +{ + throw EXC(what); +} + +template <typename EXC> +void boost_throw(const std::string& what) +{ + BOOST_THROW_EXCEPTION(EXC(what)); +} + +// Okay, for completeness, functions that throw non-class values. We wouldn't +// even deign to consider these if we hadn't found examples in our own source +// code! (Note that Kakadu's internal exception support is still based on +// throwing ints.) +void throw_char_ptr(const std::string& what) +{ + throw what.c_str(); // umm... +} + +void throw_int(const std::string& what) +{ + throw int(what.length()); +} + +/***************************************************************************** +* Three sequences of catch clauses: +* boost::exception then ..., +* std::exception then ..., +* or just ... +*****************************************************************************/ +void catch_boost_dotdotdot(void (*thrower)(const std::string&), const std::string& what) +{ + try + { + thrower(what); + } + catch (const boost::exception& e) + { + std::cout << "catch (const boost::exception& e)" << std::endl; + std::cout << "e is " << typeid(e).name() << std::endl; + std::cout << "boost::diagnostic_information(e):\n'" + << boost::diagnostic_information(e) << "'" << std::endl; + // no way to report e.what() + } + catch (...) + { + std::cout << "catch (...)" << std::endl; + std::cout << "boost::current_exception_diagnostic_information():\n'" + << boost::current_exception_diagnostic_information() << "'" + << std::endl; + } +} + +void catch_std_dotdotdot(void (*thrower)(const std::string&), const std::string& what) +{ + try + { + thrower(what); + } + catch (const std::exception& e) + { + std::cout << "catch (const std::exception& e)" << std::endl; + std::cout << "e is " << typeid(e).name() << std::endl; + std::cout << "boost::diagnostic_information(e):\n'" + << boost::diagnostic_information(e) << "'" << std::endl; + std::cout << "e.what: '" + << e.what() << "'" << std::endl; + } + catch (...) + { + std::cout << "catch (...)" << std::endl; + std::cout << "boost::current_exception_diagnostic_information():\n'" + << boost::current_exception_diagnostic_information() << "'" + << std::endl; + } +} + +void catch_dotdotdot(void (*thrower)(const std::string&), const std::string& what) +{ + try + { + thrower(what); + } + catch (...) + { + std::cout << "catch (...)" << std::endl; + std::cout << "boost::current_exception_diagnostic_information():\n'" + << boost::current_exception_diagnostic_information() << "'" + << std::endl; + } +} + +/***************************************************************************** +* Try a particular kind of throw against each of three catch sequences +*****************************************************************************/ +void catch_several(void (*thrower)(const std::string&), const std::string& what) +{ + std::cout << std::string(20, '-') << "catch_boost_dotdotdot(" << what << ")" << std::endl; + catch_boost_dotdotdot(thrower, "catch_boost_dotdotdot(" + what + ")"); + + std::cout << std::string(20, '-') << "catch_std_dotdotdot(" << what << ")" << std::endl; + catch_std_dotdotdot(thrower, "catch_std_dotdotdot(" + what + ")"); + + std::cout << std::string(20, '-') << "catch_dotdotdot(" << what << ")" << std::endl; + catch_dotdotdot(thrower, "catch_dotdotdot(" + what + ")"); +} + +/***************************************************************************** +* For a particular kind of exception, try both kinds of throw against all +* three catch sequences +*****************************************************************************/ +template <typename EXC> +void catch_both_several(const std::string& what) +{ + std::cout << std::string(20, '*') << "plain_throw<" << what << ">" << std::endl; + catch_several(plain_throw<EXC>, "plain_throw<" + what + ">"); + + std::cout << std::string(20, '*') << "boost_throw<" << what << ">" << std::endl; + catch_several(boost_throw<EXC>, "boost_throw<" + what + ">"); +} + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct llexception_data + { + }; + typedef test_group<llexception_data> llexception_group; + typedef llexception_group::object object; + llexception_group llexceptiongrp("llexception"); + + template<> template<> + void object::test<1>() + { + set_test_name("throwing exceptions"); + + // For each kind of exception, try both kinds of throw against all + // three catch sequences + std::size_t margin = 72; + std::cout << center("FromStd", '=', margin) << std::endl; + catch_both_several<FromStd>("FromStd"); + + std::cout << center("FromBoth", '=', margin) << std::endl; + catch_both_several<FromBoth>("FromBoth"); + + std::cout << center("FromBoost", '=', margin) << std::endl; + // can't throw with BOOST_THROW_EXCEPTION(), just use catch_several() + catch_several(plain_throw<FromBoost>, "plain_throw<FromBoost>"); + + std::cout << center("FromNeither", '=', margin) << std::endl; + // can't throw this with BOOST_THROW_EXCEPTION() either + catch_several(plain_throw<FromNeither>, "plain_throw<FromNeither>"); + + std::cout << center("const char*", '=', margin) << std::endl; + // We don't expect BOOST_THROW_EXCEPTION() to throw anything so daft + // as a const char* or an int, so don't bother with + // catch_both_several() -- just catch_several(). + catch_several(throw_char_ptr, "throw_char_ptr"); + + std::cout << center("int", '=', margin) << std::endl; + catch_several(throw_int, "throw_int"); + } +} // namespace tut diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index d342dece84..c387da6c48 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -110,10 +110,7 @@ namespace tut // finding indra/lib/python. Use our __FILE__, with // raw-string syntax to deal with Windows pathnames. "mydir = os.path.dirname(r'" << __FILE__ << "')\n" - // We expect mydir to be .../indra/llcommon/tests. - "sys.path.insert(0,\n" - " os.path.join(mydir, os.pardir, os.pardir, 'lib', 'python'))\n" - "from indra.base import llsd\n" + "from llbase import llsd\n" "\n" "class ProtocolError(Exception):\n" " def __init__(self, msg, data):\n" diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index 6fbb9abfc0..81b930e1e2 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1518,10 +1518,7 @@ namespace tut // scanner. import_llsd("import os.path\n" "import sys\n" - "sys.path.insert(0,\n" - " os.path.join(os.path.dirname(r'" __FILE__ "'),\n" - " os.pardir, os.pardir, 'lib', 'python'))\n" - "from indra.base import llsd\n") + "from llbase import llsd\n") {} ~TestPythonCompatible() {} diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index fa16fd6915..9a4bbbd630 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -40,7 +40,6 @@ #include <boost/bind.hpp> #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> -#include <boost/throw_exception.hpp> #include <list> #include <string> @@ -79,7 +78,7 @@ struct WrapLLErrs error = message; // Also throw an appropriate exception since calling code is likely to // assume that control won't continue beyond LL_ERRS. - BOOST_THROW_EXCEPTION(FatalException(message)); + LLTHROW(FatalException(message)); } std::string error; diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py index 04cde651c4..6c5f37d407 100755 --- a/indra/llcorehttp/tests/test_llcorehttp_peer.py +++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py @@ -42,10 +42,8 @@ except ImportError: from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler from SocketServer import ThreadingMixIn -mydir = os.path.dirname(__file__) # expected to be .../indra/llcorehttp/tests/ -sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python")) -from indra.util.fastest_elementtree import parse as xml_parse -from indra.base import llsd +from llbase.fastest_elementtree import parse as xml_parse +from llbase import llsd from testrunner import freeport, run, debug, VERBOSE class TestHTTPRequestHandler(BaseHTTPRequestHandler): diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index feb97ec2ab..f71607096c 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1426,7 +1426,12 @@ void LLImageRaw::copyScaled( LLImageRaw* src ) bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data ) { - llassert((1 == getComponents()) || (3 == getComponents()) || (4 == getComponents()) ); + S32 components = getComponents(); + if (! ((1 == components) || (3 == components) || (4 == components) )) + { + LL_WARNS() << "Invalid getComponents value (" << components << ")" << LL_ENDL; + return false; + } if (isBufferInvalid()) { @@ -1446,67 +1451,53 @@ bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data ) if (scale_image_data) { - /* - S32 temp_data_size = old_width * new_height * getComponents(); - llassert_always(temp_data_size > 0); - std::vector<U8> temp_buffer(temp_data_size); - - // Vertical - for( S32 col = 0; col < old_width; col++ ) - { - copyLineScaled( getData() + (getComponents() * col), &temp_buffer[0] + (getComponents() * col), old_height, new_height, old_width, old_width ); - } - - deleteData(); + S32 new_data_size = new_width * new_height * components; - U8* new_buffer = allocateDataSize(new_width, new_height, getComponents()); + if (new_data_size > 0) + { + U8 *new_data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), new_data_size); + if(NULL == new_data) + { + return false; + } - // Horizontal - for( S32 row = 0; row < new_height; row++ ) - { - copyLineScaled( &temp_buffer[0] + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 ); - } - */ - - S32 new_data_size = new_width * new_height * getComponents(); - llassert_always(new_data_size > 0); - - U8 *new_data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), new_data_size); - if(NULL == new_data) - { - return false; + bilinear_scale(getData(), old_width, old_height, components, old_width*components, new_data, new_width, new_height, components, new_width*components); + setDataAndSize(new_data, new_width, new_height, components); } - - bilinear_scale(getData(), old_width, old_height, getComponents(), old_width*getComponents(), new_data, new_width, new_height, getComponents(), new_width*getComponents()); - setDataAndSize(new_data, new_width, new_height, getComponents()); } else { // copy out existing image data - S32 temp_data_size = old_width * old_height * getComponents(); + S32 temp_data_size = old_width * old_height * components; std::vector<U8> temp_buffer(temp_data_size); memcpy(&temp_buffer[0], getData(), temp_data_size); // allocate new image data, will delete old data - U8* new_buffer = allocateDataSize(new_width, new_height, getComponents()); - - for( S32 row = 0; row < new_height; row++ ) - { - if (row < old_height) - { - memcpy(new_buffer + (new_width * row * getComponents()), &temp_buffer[0] + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width)); - if (old_width < new_width) - { - // pad out rest of row with black - memset(new_buffer + (getComponents() * ((new_width * row) + old_width)), 0, getComponents() * (new_width - old_width)); - } - } - else - { - // pad remaining rows with black - memset(new_buffer + (new_width * row * getComponents()), 0, new_width * getComponents()); - } - } + U8* new_buffer = allocateDataSize(new_width, new_height, components); + + if (!new_buffer) + { + LL_WARNS() << "Failed to allocate new image data buffer" << LL_ENDL; + return false; + } + + for( S32 row = 0; row < new_height; row++ ) + { + if (row < old_height) + { + memcpy(new_buffer + (new_width * row * components), &temp_buffer[0] + (old_width * row * components), components * llmin(old_width, new_width)); + if (old_width < new_width) + { + // pad out rest of row with black + memset(new_buffer + (components * ((new_width * row) + old_width)), 0, components * (new_width - old_width)); + } + } + else + { + // pad remaining rows with black + memset(new_buffer + (new_width * row * components), 0, new_width * components); + } + } } return true ; diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index 0b7d4c717f..da289ea889 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -32,12 +32,12 @@ #include "llpngwrapper.h" #include "llexception.h" -#include <boost/throw_exception.hpp> namespace { -struct PngError: public LLException +// Failure to load an image shouldn't crash the whole viewer. +struct PngError: public LLContinueError { - PngError(png_const_charp msg): LLException(msg) {} + PngError(png_const_charp msg): LLContinueError(msg) {} }; } // anonymous namespace @@ -88,7 +88,7 @@ BOOL LLPngWrapper::isValidPng(U8* src) // occurs. We throw PngError and let our try/catch block clean up. void LLPngWrapper::errorHandler(png_structp png_ptr, png_const_charp msg) { - BOOST_THROW_EXCEPTION(PngError(msg)); + LLTHROW(PngError(msg)); } // Called by the libpng library when reading (decoding) the PNG file. We @@ -138,7 +138,7 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf this, &errorHandler, NULL); if (mReadPngPtr == NULL) { - BOOST_THROW_EXCEPTION(PngError("Problem creating png read structure")); + LLTHROW(PngError("Problem creating png read structure")); } // Allocate/initialize the memory for image information. @@ -297,14 +297,14 @@ BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest) if (mColorType == -1) { - BOOST_THROW_EXCEPTION(PngError("Unsupported image: unexpected number of channels")); + LLTHROW(PngError("Unsupported image: unexpected number of channels")); } mWritePngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &errorHandler, NULL); if (!mWritePngPtr) { - BOOST_THROW_EXCEPTION(PngError("Problem creating png write structure")); + LLTHROW(PngError("Problem creating png write structure")); } mWriteInfoPtr = png_create_info_struct(mWritePngPtr); diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index d9f0935712..dce4216320 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -1,4 +1,4 @@ - /** +/** * @file llimagej2ckdu.cpp * @brief This is an implementation of JPEG2000 encode/decode using Kakadu * @@ -35,18 +35,51 @@ #include "kdu_block_coding.h" -#include <stdexcept> -#include <iostream> #include "llexception.h" -#include <boost/throw_exception.hpp> +#include <boost/exception/diagnostic_information.hpp> +#include <sstream> +#include <iomanip> namespace { -// exception used to keep KDU from terminating entire program -- see comments -// in LLKDUMessageError::flush() -struct KDUError: public LLException +// Failure to load an image shouldn't crash the whole viewer. +struct KDUError: public LLContinueError { - KDUError(const std::string& msg): LLException(msg) {} + KDUError(const std::string& msg): LLContinueError(msg) {} }; + +// KDU defines int error codes as hex values, so we should log them in hex +// so we can grep KDU headers for the hex. However those hex values +// generally "happen" to encode big-endian multibyte character sequences, +// e.g. KDU_ERROR_EXCEPTION is 0x6b647545: 'kduE' +// But beware because KDU_NULL_EXCEPTION is simply 0 -- which doesn't +// preclude somebody from throwing it. +std::string report_kdu_exception(kdu_exception mb) +{ + std::ostringstream out; + // always report mb in hex + out << "kdu_exception " << std::hex << mb; + + // Also display as many chars as are encoded in the kdu_exception + // value. Make a char array; reserve 1 extra byte for nul terminator. + char bytes[sizeof(kdu_exception) + 1]; + // Back up through 'bytes' + char *bptr = bytes + sizeof(bytes); + *(--bptr) = '\0'; + while (mb) + { + // store low-order byte of mb in next-left char + *(--bptr) = char(mb & 0xFF); + // then shift mb right by one byte + mb >>= 8; + } + // did that produce any characters? + if (*bptr) + { + out << " (" << bptr << ')'; + } + + return out.str(); +} } // anonymous namespace // stream kdu_dims to std::ostream @@ -198,7 +231,7 @@ struct LLKDUMessageError : public LLKDUMessage // shutdown will NOT engage the behavior described above. if (end_of_message) { - throw "KDU throwing an exception"; + LLTHROW(KDUError("LLKDUMessageError::flush()")); } } }; @@ -312,10 +345,10 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod { // This method is only called from methods that catch KDUError. // We want to fail the image load, not crash the viewer. - throw KDUError(STRINGIZE("Component " << idx << " dimensions " + LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions " << other_dims << " do not match component 0 dimensions " - << dims << "!")); + << dims << "!"))); } } @@ -442,9 +475,19 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco base.setLastError(msg.what()); return false; } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + return false; + } catch (...) { - base.setLastError("Unknown J2C error"); + base.setLastError("Unknown J2C error: " + + boost::current_exception_diagnostic_information()); return false; } @@ -540,9 +583,21 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco cleanupCodeStream(); return true; // done } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + base.decodeFailed(); + cleanupCodeStream(); + return true; // done + } catch (...) { - base.setLastError( "Unknown J2C error" ); + base.setLastError("Unknown J2C error: " + + boost::current_exception_diagnostic_information()); base.decodeFailed(); cleanupCodeStream(); return true; // done @@ -731,9 +786,19 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co base.setLastError(msg.what()); return false; } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + return false; + } catch( ... ) { - base.setLastError( "Unknown J2C error" ); + base.setLastError("Unknown J2C error: " + + boost::current_exception_diagnostic_information()); return false; } @@ -755,9 +820,19 @@ bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base) base.setLastError(msg.what()); return false; } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + return false; + } catch (...) { - base.setLastError( "Unknown J2C error" ); + base.setLastError("Unknown J2C error: " + + boost::current_exception_diagnostic_information()); return false; } } diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index d141298f69..216334752a 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -121,7 +121,7 @@ public: res.add(z); } - inline void affineTransform(const LLVector4a& v, LLVector4a& res) + inline void affineTransformSSE(const LLVector4a& v, LLVector4a& res) { LLVector4a x,y,z; @@ -137,6 +137,43 @@ public: z.add(mMatrix[3]); res.setAdd(x,z); } + + inline void affineTransformNonSSE(const LLVector4a& v, LLVector4a& res) + { + F32 x = v[0] * mMatrix[0][0] + v[1] * mMatrix[1][0] + v[2] * mMatrix[2][0] + mMatrix[3][0]; + F32 y = v[0] * mMatrix[0][1] + v[1] * mMatrix[1][1] + v[2] * mMatrix[2][1] + mMatrix[3][1]; + F32 z = v[0] * mMatrix[0][2] + v[1] * mMatrix[1][2] + v[2] * mMatrix[2][2] + mMatrix[3][2]; + F32 w = 1.0f; + res.set(x,y,z,w); + } + + inline void affineTransform(const LLVector4a& v, LLVector4a& res) + { + affineTransformSSE(v,res); + } }; +inline LLVector4a rowMul(const LLVector4a &row, const LLMatrix4a &mat) +{ + LLVector4a result; + result = _mm_mul_ps(_mm_shuffle_ps(row, row, _MM_SHUFFLE(0, 0, 0, 0)), mat.mMatrix[0]); + result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(row, row, _MM_SHUFFLE(1, 1, 1, 1)), mat.mMatrix[1])); + result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(row, row, _MM_SHUFFLE(2, 2, 2, 2)), mat.mMatrix[2])); + result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(row, row, _MM_SHUFFLE(3, 3, 3, 3)), mat.mMatrix[3])); + return result; +} + +inline void matMul(const LLMatrix4a &a, const LLMatrix4a &b, LLMatrix4a &res) +{ + LLVector4a row0 = rowMul(a.mMatrix[0], b); + LLVector4a row1 = rowMul(a.mMatrix[1], b); + LLVector4a row2 = rowMul(a.mMatrix[2], b); + LLVector4a row3 = rowMul(a.mMatrix[3], b); + + res.mMatrix[0] = row0; + res.mMatrix[1] = row1; + res.mMatrix[2] = row2; + res.mMatrix[3] = row3; +} + #endif diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index d932eb53a0..6f0b4b2410 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2143,19 +2143,22 @@ BOOL LLVolume::generate() F32 profile_detail = mDetail; F32 path_detail = mDetail; - - U8 path_type = mParams.getPathParams().getCurveType(); - U8 profile_type = mParams.getProfileParams().getCurveType(); - - if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) - { //cylinders don't care about Z-Axis - mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); - } - else if (path_type == LL_PCODE_PATH_CIRCLE) - { - mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); + + if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) + { + U8 path_type = mParams.getPathParams().getCurveType(); + U8 profile_type = mParams.getProfileParams().getCurveType(); + if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) + { + //cylinders don't care about Z-Axis + mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); + } + else if (path_type == LL_PCODE_PATH_CIRCLE) + { + mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); + } } - + BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); @@ -2544,7 +2547,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) U16 influence = weights[idx++]; influence |= ((U16) weights[idx++] << 8); - F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f); + F32 w = llclamp((F32) influence / 65535.f, 0.001f, 0.999f); wght.mV[cur_influence] = w; joints[cur_influence] = joint; cur_influence++; @@ -2561,11 +2564,15 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW]; if (wsum <= 0.f) { - wght = LLVector4(0.99999f,0.f,0.f,0.f); + wght = LLVector4(0.999f,0.f,0.f,0.f); } for (U32 k=0; k<4; k++) { - joints_with_weights[k] = (F32) joints[k] + wght[k]; + F32 f_combined = (F32) joints[k] + wght[k]; + joints_with_weights[k] = f_combined; + // Any weights we added above should wind up non-zero and applied to a specific bone. + // A failure here would indicate a floating point precision error in the math. + llassert((k >= cur_influence) || (f_combined - S32(f_combined) > 0.0f)); } face.mWeights[cur_vertex].loadua(joints_with_weights.mV); @@ -4568,6 +4575,7 @@ LLVolumeFace::LLVolumeFace() : mTexCoords(NULL), mIndices(NULL), mWeights(NULL), + mWeightsScrubbed(FALSE), mOctree(NULL), mOptimized(FALSE) { @@ -4593,6 +4601,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) mTexCoords(NULL), mIndices(NULL), mWeights(NULL), + mWeightsScrubbed(FALSE), mOctree(NULL) { mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); @@ -4664,6 +4673,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) ll_aligned_free_16(mWeights); mWeights = NULL; } + mWeightsScrubbed = src.mWeightsScrubbed; } if (mNumIndices) diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 1da2d0c6b1..d66004cdad 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -953,6 +953,8 @@ public: // mWeights.size() should be empty or match mVertices.size() LLVector4a* mWeights; + mutable BOOL mWeightsScrubbed; + LLOctreeNode<LLVolumeTriangle>* mOctree; //whether or not face has been cache optimized diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 1ca5f58ae2..004db546b7 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -43,6 +43,8 @@ #include "llcoros.h" #include "lleventcoro.h" #include "llcorehttputil.h" +#include "llexception.h" +#include "stringize.h" #include <map> #include <set> @@ -231,13 +233,12 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults); } - catch (std::exception e) - { - LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL; - } catch (...) { - LL_WARNS() << "Caught unknown exception." << LL_ENDL; + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName() + << "('" << url << "', " << agentIds.size() + << " Agent Ids)")); + throw; } } diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index d4c0788b7d..74cdff2b00 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -27,6 +27,8 @@ #include "linden_common.h" #include "llcoproceduremanager.h" +#include "llexception.h" +#include "stringize.h" #include <boost/assign.hpp> //========================================================================= @@ -388,14 +390,14 @@ void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdap { coproc->mProc(httpAdapter, coproc->mId); } - catch (std::exception &e) - { - LL_WARNS() << "Coprocedure(" << coproc->mName << ") id=" << coproc->mId.asString() << - " threw an exception! Message=\"" << e.what() << "\"" << LL_ENDL; - } catch (...) { - LL_WARNS() << "A non std::exception was thrown from " << coproc->mName << " with id=" << coproc->mId << "." << " in pool \"" << mPoolName << "\"" << LL_ENDL; + LOG_UNHANDLED_EXCEPTION(STRINGIZE("Coprocedure('" << coproc->mName + << "', id=" << coproc->mId.asString() + << ") in pool '" << mPoolName << "'")); + // must NOT omit this or we deplete the pool + mActiveCoprocs.erase(itActive); + throw; } LL_INFOS() << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL; diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 7742cbc182..9bf38fb336 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -642,7 +642,7 @@ HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request) mHttpRequest(request) { mBoundListener = LLEventPumps::instance().obtain("mainloop"). - listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1)); + listen(LLEventPump::ANONYMOUS, boost::bind(&HttpRequestPumper::pollRequest, this, _1)); } HttpRequestPumper::~HttpRequestPumper() diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 48ce258ba2..04b34a296c 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -32,7 +32,6 @@ #include "llstl.h" #include "llhttpconstants.h" #include "llexception.h" -#include <boost/throw_exception.hpp> const std::string CONTEXT_HEADERS("headers"); const std::string CONTEXT_PATH("path"); @@ -103,19 +102,19 @@ namespace { // virtual LLSD LLHTTPNode::simpleGet() const { - BOOST_THROW_EXCEPTION(NotImplemented()); + LLTHROW(NotImplemented()); } // virtual LLSD LLHTTPNode::simplePut(const LLSD& input) const { - BOOST_THROW_EXCEPTION(NotImplemented()); + LLTHROW(NotImplemented()); } // virtual LLSD LLHTTPNode::simplePost(const LLSD& input) const { - BOOST_THROW_EXCEPTION(NotImplemented()); + LLTHROW(NotImplemented()); } @@ -175,7 +174,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons // virtual LLSD LLHTTPNode::simpleDel(const LLSD&) const { - BOOST_THROW_EXCEPTION(NotImplemented()); + LLTHROW(NotImplemented()); } // virtual diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index 4aba5cae72..e0590dfdff 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -294,7 +294,7 @@ S32 LLXfer::processEOF() } else { - LL_INFOS() << "xfer from " << mRemoteHost << " failed, code " + LL_INFOS() << "xfer from " << mRemoteHost << " failed or aborted, code " << mCallbackResult << ": " << getFileName() << LL_ENDL; } diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 0ab67b8dda..272dbbc785 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -401,7 +401,7 @@ U64 LLXferManager::registerXfer(const void *datap, const S32 length) /////////////////////////////////////////////////////////// -void LLXferManager::requestFile(const std::string& local_filename, +U64 LLXferManager::requestFile(const std::string& local_filename, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, @@ -424,10 +424,12 @@ void LLXferManager::requestFile(const std::string& local_filename, { // cout << "requested a xfer already in progress" << endl; - return; + return xferp->mID; } } + U64 xfer_id = 0; + S32 chunk_size = use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1; xferp = (LLXfer *) new LLXfer_File(chunk_size); if (xferp) @@ -438,13 +440,15 @@ void LLXferManager::requestFile(const std::string& local_filename, // around. // Note: according to AaronB, this is here to deal with locks on files that were // in transit during a crash, - if(delete_remote_on_completion && - (remote_filename.substr(remote_filename.length()-4) == ".tmp")) + if( delete_remote_on_completion + && (remote_filename.substr(remote_filename.length()-4) == ".tmp") + && gDirUtilp->fileExists(local_filename)) { LLFile::remove(local_filename); } + xfer_id = getNextID(); ((LLXfer_File *)xferp)->initializeRequest( - getNextID(), + xfer_id, local_filename, remote_filename, remote_path, @@ -457,6 +461,7 @@ void LLXferManager::requestFile(const std::string& local_filename, { LL_ERRS() << "Xfer allocation error" << LL_ENDL; } + return xfer_id; } void LLXferManager::requestFile(const std::string& remote_filename, @@ -616,7 +621,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user if (!xferp) { char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_WARNS() << "received xfer data from " << mesgsys->getSender() + LL_INFOS() << "received xfer data from " << mesgsys->getSender() << " for non-existent xfer id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << LL_ENDL; return; @@ -1103,6 +1108,29 @@ void LLXferManager::retransmitUnackedPackets () } } +/////////////////////////////////////////////////////////// + +void LLXferManager::abortRequestById(U64 xfer_id, S32 result_code) +{ + LLXfer * xferp = findXfer(xfer_id, mReceiveList); + if (xferp) + { + if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) + { + // causes processAbort(); + xferp->abort(result_code); + } + else + { + xferp->mCallbackResult = result_code; + xferp->processEOF(); //should notify requester + removeXfer(xferp, &mReceiveList); + } + // Since already removed or marked as aborted no need + // to wait for processAbort() to start new download + startPendingDownloads(); + } +} /////////////////////////////////////////////////////////// diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h index b3d110e7a1..d258f0a5ce 100644 --- a/indra/llmessage/llxfermanager.h +++ b/indra/llmessage/llxfermanager.h @@ -140,7 +140,7 @@ class LLXferManager // file requesting routines // .. to file - virtual void requestFile(const std::string& local_filename, + virtual U64 requestFile(const std::string& local_filename, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, @@ -202,6 +202,7 @@ class LLXferManager virtual void retransmitUnackedPackets (); // error handling + void abortRequestById(U64 xfer_id, S32 result_code); virtual void processAbort (LLMessageSystem *mesgsys, void **user_data); }; diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index cecb2021e7..290b67feb3 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -4007,7 +4007,7 @@ void LLMessageSystem::sendUntrustedSimulatorMessageCoro(std::string url, std::st { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("untrustedSimulatorMessage", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); diff --git a/indra/llmessage/tests/commtest.h b/indra/llmessage/tests/commtest.h index 5dff56b44f..7c8f27bbd2 100644 --- a/indra/llmessage/tests/commtest.h +++ b/indra/llmessage/tests/commtest.h @@ -38,7 +38,6 @@ #include <map> #include <string> #include <boost/lexical_cast.hpp> -#include <boost/throw_exception.hpp> struct CommtestError: public LLException { @@ -69,7 +68,7 @@ static int query_port(const std::string& var) const char* cport = getenv(var.c_str()); if (! cport) { - BOOST_THROW_EXCEPTION(CommtestError(STRINGIZE("missing environment variable" << var))); + LLTHROW(CommtestError(STRINGIZE("missing environment variable" << var))); } // This will throw, too, if the value of PORT isn't numeric. int port(boost::lexical_cast<int>(cport)); diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h index 6aaecf9bac..5eb739393f 100644 --- a/indra/llmessage/tests/networkio.h +++ b/indra/llmessage/tests/networkio.h @@ -35,7 +35,6 @@ #include "llpumpio.h" #include "llhttpclient.h" #include "llexception.h" -#include <boost/throw_exception.hpp> /***************************************************************************** * NetworkIO @@ -53,7 +52,7 @@ public: ll_init_apr(); if (! gAPRPoolp) { - BOOST_THROW_EXCEPTION(LLException("Can't initialize APR")); + LLTHROW(LLException("Can't initialize APR")); } // Create IO Pump to use for HTTP Requests. @@ -61,7 +60,7 @@ public: LLHTTPClient::setPump(*mServicePump); if (ll_init_ares() == NULL || !gAres->isInitialized()) { - BOOST_THROW_EXCEPTION(LLException("Can't start DNS resolver")); + LLTHROW(LLException("Can't start DNS resolver")); } // You can interrupt pump() without waiting the full timeout duration diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py index e45249b1cb..bac18fa374 100755 --- a/indra/llmessage/tests/test_llsdmessage_peer.py +++ b/indra/llmessage/tests/test_llsdmessage_peer.py @@ -34,10 +34,8 @@ import sys from threading import Thread from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler -mydir = os.path.dirname(__file__) # expected to be .../indra/llmessage/tests/ -sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python")) -from indra.util.fastest_elementtree import parse as xml_parse -from indra.base import llsd +from llbase.fastest_elementtree import parse as xml_parse +from llbase import llsd from testrunner import freeport, run, debug, VERBOSE import time diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 3d173d0459..f1b6fe0a12 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -73,6 +73,7 @@ bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::s // Queue up the media init message -- it will be sent after all the currently queued messages. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); message.setValue("target", mTarget); + message.setValueReal("factor", mZoomFactor); sendMessage(message); mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); @@ -116,7 +117,7 @@ void LLPluginClassMedia::reset() mMediaHeight = 0; mDirtyRect = LLRect::null; mAutoScaleMedia = false; - mRequestedVolume = 1.0f; + mRequestedVolume = 0.0f; mPriority = PRIORITY_NORMAL; mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; mAllowDownsample = false; @@ -1259,7 +1260,7 @@ void LLPluginClassMedia::focus(bool focused) sendMessage(message); } -void LLPluginClassMedia::set_page_zoom_factor( double factor ) +void LLPluginClassMedia::set_page_zoom_factor( F64 factor ) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_page_zoom_factor"); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index fc27b7bea3..3b0739d044 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -68,6 +68,7 @@ public: int getTextureHeight() const; int getFullWidth() const { return mFullMediaWidth; }; int getFullHeight() const { return mFullMediaHeight; }; + F64 getZoomFactor() const { return mZoomFactor; }; // This may return NULL. Callers need to check for and handle this case. unsigned char* getBitsData(); @@ -83,7 +84,8 @@ public: void setSize(int width, int height); void setAutoScale(bool auto_scale); - + void setZoomFactor(F64 zoom_factor) { mZoomFactor = zoom_factor; } + void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; @@ -204,7 +206,7 @@ public: bool pluginSupportsMediaBrowser(void); void focus(bool focused); - void set_page_zoom_factor( double factor ); + void set_page_zoom_factor( F64 factor ); void clear_cache(); void clear_cookies(); void set_cookies(const std::string &cookies); @@ -367,6 +369,8 @@ protected: int mTextureHeight; int mMediaWidth; int mMediaHeight; + + F64 mZoomFactor; float mRequestedVolume; diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 00bde8dbc3..d73bdd7693 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -807,17 +807,19 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac // LLDAELoader //----------------------------------------------------------------------------- LLDAELoader::LLDAELoader( - std::string filename, - S32 lod, + std::string filename, + S32 lod, load_callback_t load_cb, joint_lookup_func_t joint_lookup_func, texture_load_func_t texture_load_func, - state_callback_t state_cb, - void* opaque_userdata, - JointTransformMap& jointMap, - JointSet& jointsFromNodes, + state_callback_t state_cb, + void* opaque_userdata, + JointTransformMap& jointTransformMap, + JointNameSet& jointsFromNodes, + std::map<std::string, std::string>& jointAliasMap, + U32 maxJointsPerMesh, U32 modelLimit, - bool preprocess) + bool preprocess) : LLModelLoader( filename, lod, @@ -826,10 +828,12 @@ LLDAELoader::LLDAELoader( texture_load_func, state_cb, opaque_userdata, - jointMap, - jointsFromNodes), -mGeneratedModelLimit(modelLimit), -mPreprocessDAE(preprocess) + jointTransformMap, + jointsFromNodes, + jointAliasMap, + maxJointsPerMesh), + mGeneratedModelLimit(modelLimit), + mPreprocessDAE(preprocess) { } @@ -1071,7 +1075,7 @@ bool LLDAELoader::OpenFile(const std::string& filename) std::string LLDAELoader::preprocessDAE(std::string filename) { // Open a DAE file for some preprocessing (like removing space characters in IDs), see MAINT-5678 - std::ifstream inFile; + llifstream inFile; inFile.open(filename.c_str(), std::ios_base::in); std::stringstream strStream; strStream << inFile.rdbuf(); @@ -1148,28 +1152,29 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae->getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - - //Try to get at the skeletal instance controller - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement ); + U32 skeleton_count = dae->getDatabase()->getElementCount( NULL, "skeleton" ); + std::vector<domInstance_controller::domSkeleton*> skeletons; + for (S32 i=0; i<skeleton_count; i++) + { + daeElement* pElement = 0; + dae->getDatabase()->getElement( &pElement, i, 0, "skeleton" ); + + //Try to get at the skeletal instance controller + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement ); + daeElement* pSkeletonRootNode = NULL; + if (pSkeleton) + { + pSkeletonRootNode = pSkeleton->getValue().getElement(); + } + if (pSkeleton && pSkeletonRootNode) + { + skeletons.push_back(pSkeleton); + } + } bool missingSkeletonOrScene = false; //If no skeleton, do a breadth-first search to get at specific joints - bool rootNode = false; - - //Need to test for a skeleton that does not have a root node - //This occurs when your instance controller does not have an associated scene - if ( pSkeleton ) - { - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - rootNode = true; - } - - } - if ( !pSkeleton || !rootNode ) + if ( skeletons.size() == 0 ) { daeElement* pScene = root->getDescendant("visual_scene"); if ( !pScene ) @@ -1184,7 +1189,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do S32 childCount = children.getCount(); //Process any children that are joints - //Not all children are joints, some code be ambient lights, cameras, geometry etc.. + //Not all children are joints, some could be ambient lights, cameras, geometry etc.. for (S32 i = 0; i < childCount; ++i) { domNode* pNode = daeSafeCast<domNode>(children[i]); @@ -1196,83 +1201,90 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do } } else - //Has Skeleton - { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - //Once we have the root node - start acccessing it's joint components - const int jointCnt = mJointMap.size(); - JointMap :: const_iterator jointIt = mJointMap.begin(); - - //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. - for ( int i=0; i<jointCnt; ++i, ++jointIt ) - { - //Build a joint for the resolver to work with - char str[64]={0}; - sprintf(str,"./%s",(*jointIt).first.c_str() ); - //LL_WARNS()<<"Joint "<< str <<LL_ENDL; - - //Setup the resolver - daeSIDResolver resolver( pSkeletonRootNode, str ); - - //Look for the joint - domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolverA( pJoint, "./translate" ); - domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); - daeSIDResolver jointResolverB( pJoint, "./location" ); - domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslateA ) - { - extractTranslation( pTranslateA, workingTransform ); - } - else - if ( pTranslateB ) - { - extractTranslation( pTranslateB, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); - if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) - { - LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; - missingSkeletonOrScene = true; - } - else - if ( pTranslateElement ) - { - extractTranslationViaElement( pTranslateElement, workingTransform ); - } - else - { - extractTranslationViaSID( pJoint, workingTransform ); - } - - } - - //Store the joint transform w/respect to it's name. - mJointList[(*jointIt).second.c_str()] = workingTransform; - } - } - - //If anything failed in regards to extracting the skeleton, joints or translation id, - //mention it - if ( missingSkeletonOrScene ) - { - LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL; - } - }//got skeleton? - } + //Has one or more skeletons + for (std::vector<domInstance_controller::domSkeleton*>::iterator skel_it = skeletons.begin(); + skel_it != skeletons.end(); ++skel_it) + { + domInstance_controller::domSkeleton* pSkeleton = *skel_it; + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + //Once we have the root node - start acccessing it's joint components + const int jointCnt = mJointMap.size(); + JointMap :: const_iterator jointIt = mJointMap.begin(); + + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i<jointCnt; ++i, ++jointIt ) + { + //Build a joint for the resolver to work with + char str[64]={0}; + sprintf(str,"./%s",(*jointIt).first.c_str() ); + //LL_WARNS()<<"Joint "<< str <<LL_ENDL; + + //Setup the resolver + daeSIDResolver resolver( pSkeletonRootNode, str ); + + //Look for the joint + domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() ); + if ( pJoint ) + { + // FIXME this has a lot of overlap with processJointNode(), would be nice to refactor. + + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolverA( pJoint, "./translate" ); + domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); + daeSIDResolver jointResolverB( pJoint, "./location" ); + domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); + + LLMatrix4 workingTransform; + + //Translation via SID + if ( pTranslateA ) + { + extractTranslation( pTranslateA, workingTransform ); + } + else + { + if ( pTranslateB ) + { + extractTranslation( pTranslateB, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) + { + LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; + missingSkeletonOrScene = true; + } + else + if ( pTranslateElement ) + { + extractTranslationViaElement( pTranslateElement, workingTransform ); + } + else + { + extractTranslationViaSID( pJoint, workingTransform ); + } + + } + } + + //Store the joint transform w/respect to its name. + mJointList[(*jointIt).second.c_str()] = workingTransform; + } + } + + //If anything failed in regards to extracting the skeleton, joints or translation id, + //mention it + if ( missingSkeletonOrScene ) + { + LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL; + } + }//got skeleton? + } domSkin::domJoints* joints = skin->getJoints(); @@ -1307,7 +1319,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do name = mJointMap[name]; } model->mSkinInfo.mJointNames.push_back(name); - model->mSkinInfo.mJointMap[name] = j; + model->mSkinInfo.mJointNums.push_back(-1); } } else @@ -1325,7 +1337,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do name = mJointMap[name]; } model->mSkinInfo.mJointNames.push_back(name); - model->mSkinInfo.mJointMap[name] = j; + model->mSkinInfo.mJointNums.push_back(-1); } } } @@ -1353,8 +1365,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do mat.mMatrix[i][j] = transform[k*16 + i + j*4]; } } - - model->mSkinInfo.mInvBindMatrix.push_back(mat); + model->mSkinInfo.mInvBindMatrix.push_back(mat); } } } @@ -1370,35 +1381,48 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do if ( !missingSkeletonOrScene ) { - //Set the joint translations on the avatar - if it's a full mapping - //The joints are reset in the dtor - if ( getRigWithSceneParity() ) - { - JointMap :: const_iterator masterJointIt = mJointMap.begin(); - JointMap :: const_iterator masterJointItEnd = mJointMap.end(); - for (;masterJointIt!=masterJointItEnd;++masterJointIt ) - { - std::string lookingForJoint = (*masterJointIt).first.c_str(); - - if ( mJointList.find( lookingForJoint ) != mJointList.end() ) - { - //LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL; - LLMatrix4 jointTransform = mJointList[lookingForJoint]; - LLJoint* pJoint = mJointLookupFunc(lookingForJoint,mOpaqueData); - if ( pJoint ) - { - LLUUID fake_mesh_id; - fake_mesh_id.generate(); - pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, ""); - } - else - { - //Most likely an error in the asset. - LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL; - } - } - } - } + // FIXME: mesh_id is used to determine which mesh gets to + // set the joint offset, in the event of a conflict. Since + // we don't know the mesh id yet, we can't guarantee that + // joint offsets will be applied with the same priority as + // in the uploaded model. If the file contains multiple + // meshes with conflicting joint offsets, preview may be + // incorrect. + LLUUID fake_mesh_id; + fake_mesh_id.generate(); + + //Set the joint translations on the avatar + JointMap :: const_iterator masterJointIt = mJointMap.begin(); + JointMap :: const_iterator masterJointItEnd = mJointMap.end(); + for (;masterJointIt!=masterJointItEnd;++masterJointIt ) + { + std::string lookingForJoint = (*masterJointIt).first.c_str(); + + if ( mJointList.find( lookingForJoint ) != mJointList.end() ) + { + //LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL; + LLMatrix4 jointTransform = mJointList[lookingForJoint]; + LLJoint* pJoint = mJointLookupFunc(lookingForJoint,mOpaqueData); + if ( pJoint ) + { + const LLVector3& joint_pos = jointTransform.getTranslation(); + if (pJoint->aboveJointPosThreshold(joint_pos)) + { + bool override_changed; // not used + pJoint->addAttachmentPosOverride(joint_pos, fake_mesh_id, "", override_changed); + if (model->mSkinInfo.mLockScaleIfJointPosition) + { + pJoint->addAttachmentScaleOverride(pJoint->getDefaultScale(), fake_mesh_id, ""); + } + } + } + else + { + //Most likely an error in the asset. + LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL; + } + } + } } //missingSkeletonOrScene //We need to construct the alternate bind matrix (which contains the new joint positions) @@ -1412,16 +1436,15 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do std::string lookingForJoint = (*jointIt).c_str(); //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key //and store it in the alternate bind matrix - if ( mJointList.find( lookingForJoint ) != mJointList.end() ) + if ( mJointMap.find( lookingForJoint ) != mJointMap.end() ) { - LLMatrix4 jointTransform = mJointList[lookingForJoint]; LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() ); model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse ); - } + } else { - LL_WARNS()<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<LL_ENDL; + LL_DEBUGS("Mesh")<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<"] "<<LL_ENDL; } } @@ -1868,7 +1891,7 @@ daeElement* LLDAELoader::getChildFromElement( daeElement* pElement, std::string { return pChildOfElement; } - LL_WARNS()<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL; + LL_DEBUGS("Mesh")<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL; return NULL; } diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h index 27db5326d5..4e990dbe5e 100644 --- a/indra/llprimitive/lldaeloader.h +++ b/indra/llprimitive/lldaeloader.h @@ -47,17 +47,19 @@ public: dae_model_map mModelsMap; LLDAELoader( - std::string filename, - S32 lod, + std::string filename, + S32 lod, LLModelLoader::load_callback_t load_cb, LLModelLoader::joint_lookup_func_t joint_lookup_func, LLModelLoader::texture_load_func_t texture_load_func, LLModelLoader::state_callback_t state_cb, - void* opaque_userdata, - JointTransformMap& jointMap, - JointSet& jointsFromNodes, + void* opaque_userdata, + JointTransformMap& jointTransformMap, + JointNameSet& jointsFromNodes, + std::map<std::string, std::string>& jointAliasMap, + U32 maxJointsPerMesh, U32 modelLimit, - bool preprocess); + bool preprocess); virtual ~LLDAELoader() ; virtual bool OpenFile(const std::string& filename); diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index e494c55250..db6d00bc2c 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -50,8 +50,12 @@ std::string model_names[] = const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string); LLModel::LLModel(LLVolumeParams& params, F32 detail) - : LLVolume(params, detail), mNormalizedScale(1,1,1), mNormalizedTranslation(0,0,0) - , mPelvisOffset( 0.0f ), mStatus(NO_ERRORS), mSubmodelID(0) + : LLVolume(params, detail), + mNormalizedScale(1,1,1), + mNormalizedTranslation(0,0,0), + mPelvisOffset( 0.0f ), + mStatus(NO_ERRORS), + mSubmodelID(0) { mDecompID = -1; mLocalID = -1; @@ -667,6 +671,7 @@ LLSD LLModel::writeModel( const LLModel::Decomposition& decomp, BOOL upload_skin, BOOL upload_joints, + BOOL lock_scale_if_joint_position, BOOL nowrite, BOOL as_slm, int submodel_id) @@ -686,7 +691,7 @@ LLSD LLModel::writeModel( if (skinning) { //write skinning block - mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints); + mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints, lock_scale_if_joint_position); } if (!decomp.mBaseHull.empty() || @@ -867,6 +872,7 @@ LLSD LLModel::writeModel( S32 count = 0; for (weight_list::iterator iter = weights.begin(); iter != weights.end(); ++iter) { + // Note joint index cannot exceed 255. if (iter->mJointIdx < 255 && iter->mJointIdx >= 0) { U8 idx = (U8) iter->mJointIdx; @@ -1000,7 +1006,7 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) { - //1. If a vertex has been weighted then we'll find it via pos and return it's weight list + //1. If a vertex has been weighted then we'll find it via pos and return its weight list weight_map::iterator iterPos = mSkinWeights.begin(); weight_map::iterator iterEnd = mSkinWeights.end(); @@ -1223,7 +1229,6 @@ bool LLModel::loadModel(std::istream& is) } return false; - } bool LLModel::isMaterialListSubset( LLModel* ref ) @@ -1338,7 +1343,6 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn return true; } - bool LLModel::loadSkinInfo(LLSD& header, std::istream &is) { S32 offset = header["skin"]["offset"].asInteger(); @@ -1381,8 +1385,17 @@ bool LLModel::loadDecomposition(LLSD& header, std::istream& is) return true; } +LLMeshSkinInfo::LLMeshSkinInfo(): + mPelvisOffset(0.0), + mLockScaleIfJointPosition(false), + mInvalidJointsScrubbed(false) +{ +} -LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin) +LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin): + mPelvisOffset(0.0), + mLockScaleIfJointPosition(false), + mInvalidJointsScrubbed(false) { fromLLSD(skin); } @@ -1394,6 +1407,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) for (U32 i = 0; i < skin["joint_names"].size(); ++i) { mJointNames.push_back(skin["joint_names"][i]); + mJointNums.push_back(-1); } } @@ -1446,9 +1460,18 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) { mPelvisOffset = skin["pelvis_offset"].asReal(); } + + if (skin.has("lock_scale_if_joint_position")) + { + mLockScaleIfJointPosition = skin["lock_scale_if_joint_position"].asBoolean(); + } + else + { + mLockScaleIfJointPosition = false; + } } -LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const +LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_position) const { LLSD ret; @@ -1486,6 +1509,11 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const } } + if (lock_scale_if_joint_position) + { + ret["lock_scale_if_joint_position"] = lock_scale_if_joint_position; + } + ret["pelvis_offset"] = mPelvisOffset; } diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index ae602c09df..097558ef67 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -42,18 +42,21 @@ class domMesh; class LLMeshSkinInfo { public: + LLMeshSkinInfo(); + LLMeshSkinInfo(LLSD& data); + void fromLLSD(LLSD& data); + LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const; + LLUUID mMeshID; std::vector<std::string> mJointNames; + mutable std::vector<S32> mJointNums; std::vector<LLMatrix4> mInvBindMatrix; std::vector<LLMatrix4> mAlternateBindMatrix; - std::map<std::string, U32> mJointMap; - LLMeshSkinInfo() { } - LLMeshSkinInfo(LLSD& data); - void fromLLSD(LLSD& data); - LLSD asLLSD(bool include_joints) const; LLMatrix4 mBindShapeMatrix; float mPelvisOffset; + bool mLockScaleIfJointPosition; + bool mInvalidJointsScrubbed; }; class LLModel : public LLVolume @@ -138,6 +141,7 @@ public: const LLModel::Decomposition& decomp, BOOL upload_skin, BOOL upload_joints, + BOOL lock_scale_if_joint_position, BOOL nowrite = FALSE, BOOL as_slm = FALSE, int submodel_id = 0); diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index f86eceb98d..4e468ff45f 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -102,16 +102,18 @@ void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& // LLModelLoader //----------------------------------------------------------------------------- LLModelLoader::LLModelLoader( - std::string filename, - S32 lod, + std::string filename, + S32 lod, load_callback_t load_cb, joint_lookup_func_t joint_lookup_func, texture_load_func_t texture_load_func, - state_callback_t state_cb, - void* opaque_userdata, - JointTransformMap& jointMap, - JointSet& jointsFromNodes ) -: mJointList( jointMap ) + state_callback_t state_cb, + void* opaque_userdata, + JointTransformMap& jointTransformMap, + JointNameSet& jointsFromNodes, + JointMap& legalJointNamesMap, + U32 maxJointsPerMesh) +: mJointList( jointTransformMap ) , mJointsFromNode( jointsFromNodes ) , LLThread("Model Loader") , mFilename(filename) @@ -124,124 +126,14 @@ LLModelLoader::LLModelLoader( , mTextureLoadFunc(texture_load_func) , mStateCallback(state_cb) , mOpaqueData(opaque_userdata) -, mRigParityWithScene(false) -, mRigValidJointUpload(false) -, mLegacyRigValid(false) +, mRigValidJointUpload(true) +, mLegacyRigValid(true) , mNoNormalize(false) , mNoOptimize(false) , mCacheOnlyHitIfRigged(false) -{ - mJointMap["mPelvis"] = "mPelvis"; - mJointMap["mTorso"] = "mTorso"; - mJointMap["mChest"] = "mChest"; - mJointMap["mNeck"] = "mNeck"; - mJointMap["mHead"] = "mHead"; - mJointMap["mSkull"] = "mSkull"; - mJointMap["mEyeRight"] = "mEyeRight"; - mJointMap["mEyeLeft"] = "mEyeLeft"; - mJointMap["mCollarLeft"] = "mCollarLeft"; - mJointMap["mShoulderLeft"] = "mShoulderLeft"; - mJointMap["mElbowLeft"] = "mElbowLeft"; - mJointMap["mWristLeft"] = "mWristLeft"; - mJointMap["mCollarRight"] = "mCollarRight"; - mJointMap["mShoulderRight"] = "mShoulderRight"; - mJointMap["mElbowRight"] = "mElbowRight"; - mJointMap["mWristRight"] = "mWristRight"; - mJointMap["mHipRight"] = "mHipRight"; - mJointMap["mKneeRight"] = "mKneeRight"; - mJointMap["mAnkleRight"] = "mAnkleRight"; - mJointMap["mFootRight"] = "mFootRight"; - mJointMap["mToeRight"] = "mToeRight"; - mJointMap["mHipLeft"] = "mHipLeft"; - mJointMap["mKneeLeft"] = "mKneeLeft"; - mJointMap["mAnkleLeft"] = "mAnkleLeft"; - mJointMap["mFootLeft"] = "mFootLeft"; - mJointMap["mToeLeft"] = "mToeLeft"; - - mJointMap["avatar_mPelvis"] = "mPelvis"; - mJointMap["avatar_mTorso"] = "mTorso"; - mJointMap["avatar_mChest"] = "mChest"; - mJointMap["avatar_mNeck"] = "mNeck"; - mJointMap["avatar_mHead"] = "mHead"; - mJointMap["avatar_mSkull"] = "mSkull"; - mJointMap["avatar_mEyeRight"] = "mEyeRight"; - mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; - mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; - mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; - mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; - mJointMap["avatar_mWristLeft"] = "mWristLeft"; - mJointMap["avatar_mCollarRight"] = "mCollarRight"; - mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; - mJointMap["avatar_mElbowRight"] = "mElbowRight"; - mJointMap["avatar_mWristRight"] = "mWristRight"; - mJointMap["avatar_mHipRight"] = "mHipRight"; - mJointMap["avatar_mKneeRight"] = "mKneeRight"; - mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; - mJointMap["avatar_mFootRight"] = "mFootRight"; - mJointMap["avatar_mToeRight"] = "mToeRight"; - mJointMap["avatar_mHipLeft"] = "mHipLeft"; - mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; - mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; - mJointMap["avatar_mFootLeft"] = "mFootLeft"; - mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - - mJointMap["hip"] = "mPelvis"; - mJointMap["abdomen"] = "mTorso"; - mJointMap["chest"] = "mChest"; - mJointMap["neck"] = "mNeck"; - mJointMap["head"] = "mHead"; - mJointMap["figureHair"] = "mSkull"; - mJointMap["lCollar"] = "mCollarLeft"; - mJointMap["lShldr"] = "mShoulderLeft"; - mJointMap["lForeArm"] = "mElbowLeft"; - mJointMap["lHand"] = "mWristLeft"; - mJointMap["rCollar"] = "mCollarRight"; - mJointMap["rShldr"] = "mShoulderRight"; - mJointMap["rForeArm"] = "mElbowRight"; - mJointMap["rHand"] = "mWristRight"; - mJointMap["rThigh"] = "mHipRight"; - mJointMap["rShin"] = "mKneeRight"; - mJointMap["rFoot"] = "mFootRight"; - mJointMap["lThigh"] = "mHipLeft"; - mJointMap["lShin"] = "mKneeLeft"; - mJointMap["lFoot"] = "mFootLeft"; - - //move into joint mapper class - //1. joints for joint offset verification - mMasterJointList.push_front("mPelvis"); - mMasterJointList.push_front("mTorso"); - mMasterJointList.push_front("mChest"); - mMasterJointList.push_front("mNeck"); - mMasterJointList.push_front("mHead"); - mMasterJointList.push_front("mCollarLeft"); - mMasterJointList.push_front("mShoulderLeft"); - mMasterJointList.push_front("mElbowLeft"); - mMasterJointList.push_front("mWristLeft"); - mMasterJointList.push_front("mCollarRight"); - mMasterJointList.push_front("mShoulderRight"); - mMasterJointList.push_front("mElbowRight"); - mMasterJointList.push_front("mWristRight"); - mMasterJointList.push_front("mHipRight"); - mMasterJointList.push_front("mKneeRight"); - mMasterJointList.push_front("mFootRight"); - mMasterJointList.push_front("mHipLeft"); - mMasterJointList.push_front("mKneeLeft"); - mMasterJointList.push_front("mFootLeft"); - - //2. legacy joint list - used to verify rigs that will not be using joint offsets - mMasterLegacyJointList.push_front("mPelvis"); - mMasterLegacyJointList.push_front("mTorso"); - mMasterLegacyJointList.push_front("mChest"); - mMasterLegacyJointList.push_front("mNeck"); - mMasterLegacyJointList.push_front("mHead"); - mMasterLegacyJointList.push_front("mHipRight"); - mMasterLegacyJointList.push_front("mKneeRight"); - mMasterLegacyJointList.push_front("mFootRight"); - mMasterLegacyJointList.push_front("mHipLeft"); - mMasterLegacyJointList.push_front("mKneeLeft"); - mMasterLegacyJointList.push_front("mFootLeft"); - +, mMaxJointsPerMesh(maxJointsPerMesh) +, mJointMap(legalJointNamesMap) +{ assert_main_thread(); sActiveLoaderList.push_back(this) ; } @@ -258,6 +150,23 @@ void LLModelLoader::run() doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); } +// static +bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::string& slm_filename) +{ + slm_filename = model_filename; + + std::string::size_type i = model_filename.rfind("."); + if (i != std::string::npos) + { + slm_filename.replace(i, model_filename.size()-1, ".slm"); + return true; + } + else + { + return false; + } +} + bool LLModelLoader::doLoadModel() { //first, look for a .slm file of the same name that was modified later @@ -265,20 +174,17 @@ bool LLModelLoader::doLoadModel() if (mTrySLM) { - std::string filename = mFilename; - - std::string::size_type i = filename.rfind("."); - if (i != std::string::npos) - { - filename.replace(i, filename.size()-1, ".slm"); + std::string slm_filename; + if (getSLMFilename(mFilename, slm_filename)) + { llstat slm_status; - if (LLFile::stat(filename, &slm_status) == 0) + if (LLFile::stat(slm_filename, &slm_status) == 0) { //slm file exists llstat dae_status; if (LLFile::stat(mFilename, &dae_status) != 0 || dae_status.st_mtime < slm_status.st_mtime) { - if (loadFromSLM(filename)) + if (loadFromSLM(slm_filename)) { //slm successfully loaded, if this fails, fall through and //try loading from dae @@ -476,8 +382,6 @@ void LLModelLoader::loadModelCallback() //----------------------------------------------------------------------------- void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset ) { - critiqueJointToNodeMappingFromScene(); - //Determines the following use cases for a rig: //1. It is suitable for upload with skin weights & joint positions, or //2. It is suitable for upload as standard av with just skin weights @@ -485,59 +389,27 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset ); bool isRigLegacyOK = isRigLegacy( jointListFromAsset ); - //It's OK that both could end up being true, both default to false - if ( isJointPositionUploadOK ) + // It's OK that both could end up being true. + + // Both start out as true and are forced to false if any mesh in + // the model file is not vald by that criterion. Note that a file + // can contain multiple meshes. + if ( !isJointPositionUploadOK ) { - setRigValidForJointPositionUpload( true ); + // This starts out true, becomes false if false for any loaded + // mesh. + setRigValidForJointPositionUpload( false ); } - if ( isRigLegacyOK) + if ( !isRigLegacyOK) { - setLegacyRigValid( true ); + // This starts out true, becomes false if false for any loaded + // mesh. + setLegacyRigValid( false ); } } -//----------------------------------------------------------------------------- -// critiqueJointToNodeMappingFromScene() -//----------------------------------------------------------------------------- -void LLModelLoader::critiqueJointToNodeMappingFromScene( void ) -{ - //Do the actual nodes back the joint listing from the dae? - //if yes then this is a fully rigged asset, otherwise it's just a partial rig - - JointSet::iterator jointsFromNodeIt = mJointsFromNode.begin(); - JointSet::iterator jointsFromNodeEndIt = mJointsFromNode.end(); - bool result = true; - - if ( !mJointsFromNode.empty() ) - { - for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt ) - { - std::string name = *jointsFromNodeIt; - if ( mJointTransformMap.find( name ) != mJointTransformMap.end() ) - { - continue; - } - else - { - LL_INFOS() <<"critiqueJointToNodeMappingFromScene is missing a: " << name << LL_ENDL; - result = false; - } - } - } - else - { - result = false; - } - //Determines the following use cases for a rig: - //1. Full av rig w/1-1 mapping from the scene and joint array - //2. Partial rig but w/o parity between the scene and joint array - if ( result ) - { - setRigWithSceneParity( true ); - } -} //----------------------------------------------------------------------------- // isRigLegacy() //----------------------------------------------------------------------------- @@ -549,68 +421,39 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAs return false; } - bool result = false; - - JointSet :: const_iterator masterJointIt = mMasterLegacyJointList.begin(); - JointSet :: const_iterator masterJointEndIt = mMasterLegacyJointList.end(); - - std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin(); - std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end(); - - for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) - { - result = false; - modelJointIt = jointListFromAsset.begin(); + // Too many joints in asset + if (jointListFromAsset.size()>mMaxJointsPerMesh) + { + LL_WARNS() << "Rigged to " << jointListFromAsset.size() << " joints, max is " << mMaxJointsPerMesh << LL_ENDL; + LL_WARNS() << "Skinning disabled due to too many joints" << LL_ENDL; + return false; + } + + // Unknown joints in asset + S32 unknown_joint_count = 0; + for (std::vector<std::string>::const_iterator it = jointListFromAsset.begin(); + it != jointListFromAsset.end(); ++it) + { + if (mJointMap.find(*it)==mJointMap.end()) + { + LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL; + unknown_joint_count++; + } + } + if (unknown_joint_count>0) + { + LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL; + return false; + } - for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) - { - if ( *masterJointIt == *modelJointIt ) - { - result = true; - break; - } - } - if ( !result ) - { - LL_INFOS() <<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL; - break; - } - } - return result; + return true; } //----------------------------------------------------------------------------- // isRigSuitableForJointPositionUpload() //----------------------------------------------------------------------------- bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ) { - bool result = false; - - JointSet :: const_iterator masterJointIt = mMasterJointList.begin(); - JointSet :: const_iterator masterJointEndIt = mMasterJointList.end(); - - std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin(); - std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end(); - - for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) - { - result = false; - modelJointIt = jointListFromAsset.begin(); - - for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) - { - if ( *masterJointIt == *modelJointIt ) - { - result = true; - break; - } - } - if ( !result ) - { - LL_INFOS() <<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL; - break; - } - } - return result; + return true; } diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index bb4d06dca3..d64e0a0773 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -34,10 +34,10 @@ class LLJoint; -typedef std::map<std::string, LLMatrix4> JointTransformMap; -typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt; -typedef std::map<std::string, std::string> JointMap; -typedef std::deque<std::string> JointSet; +typedef std::map<std::string, LLMatrix4> JointTransformMap; +typedef std::map<std::string, LLMatrix4>::iterator JointTransformMapIt; +typedef std::map<std::string, std::string> JointMap; +typedef std::deque<std::string> JointNameSet; const S32 SLM_SUPPORTED_VERSION = 3; const S32 NUM_LOD = 4; @@ -116,25 +116,30 @@ public: //map of avatar joints as named in COLLADA assets to internal joint names JointMap mJointMap; JointTransformMap& mJointList; - JointSet& mJointsFromNode; + JointNameSet& mJointsFromNode; + U32 mMaxJointsPerMesh; LLModelLoader( - std::string filename, - S32 lod, + std::string filename, + S32 lod, LLModelLoader::load_callback_t load_cb, LLModelLoader::joint_lookup_func_t joint_lookup_func, LLModelLoader::texture_load_func_t texture_load_func, LLModelLoader::state_callback_t state_cb, - void* opaque_userdata, - JointTransformMap& jointMap, - JointSet& jointsFromNodes); + void* opaque_userdata, + JointTransformMap& jointTransformMap, + JointNameSet& jointsFromNodes, + JointMap& legalJointNamesMap, + U32 maxJointsPerMesh); virtual ~LLModelLoader() ; virtual void setNoNormalize() { mNoNormalize = true; } virtual void setNoOptimize() { mNoOptimize = true; } virtual void run(); - + + static bool getSLMFilename(const std::string& model_filename, std::string& slm_filename); + // Will try SLM or derived class OpenFile as appropriate // virtual bool doLoadModel(); @@ -158,7 +163,6 @@ public: //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps) void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset ); - void critiqueJointToNodeMappingFromScene( void ); //Determines if a rig is a legacy from the joint list bool isRigLegacy( const std::vector<std::string> &jointListFromAsset ); @@ -166,9 +170,6 @@ public: //Determines if a rig is suitable for upload bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ); - void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; } - const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; } - const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; } void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } @@ -180,7 +181,7 @@ public: //----------------------------------------------------------------------------- bool isNodeAJoint(const char* name) { - return mJointMap.find(name) != mJointMap.end(); + return name != NULL && mJointMap.find(name) != mJointMap.end(); } protected: @@ -189,17 +190,14 @@ protected: LLModelLoader::joint_lookup_func_t mJointLookupFunc; LLModelLoader::texture_load_func_t mTextureLoadFunc; LLModelLoader::state_callback_t mStateCallback; - void* mOpaqueData; + void* mOpaqueData; - bool mRigParityWithScene; bool mRigValidJointUpload; bool mLegacyRigValid; bool mNoNormalize; bool mNoOptimize; - JointSet mMasterJointList; - JointSet mMasterLegacyJointList; JointTransformMap mJointTransformMap; static std::list<LLModelLoader*> sActiveLoaderList; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 0e2946632a..cf0a117567 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -364,12 +364,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons if (right_x) { - F32 cr_x = (cur_x - origin.mV[VX]) / sScaleX; - if (*right_x < cr_x) - { - // rightmost edge of previously drawn text, don't draw over previous text - *right_x = cr_x; - } + *right_x = (cur_x - origin.mV[VX]) / sScaleX; } //FIXME: add underline as glyph? diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index e24d3bb5ba..7757198af5 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -306,6 +306,7 @@ PFNGLUNIFORM3IVARBPROC glUniform3ivARB = NULL; PFNGLUNIFORM4IVARBPROC glUniform4ivARB = NULL; PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB = NULL; PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB = NULL; +PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv = NULL; PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB = NULL; PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB = NULL; PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL; @@ -1333,6 +1334,7 @@ void LLGLManager::initExtensions() glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4ivARB"); glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix2fvARB"); glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3fvARB"); + glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3x4fv"); glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix4fvARB"); glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterfvARB"); glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterivARB"); diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index a95872e883..722dd9050b 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -155,6 +155,7 @@ extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; +extern PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv; extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; @@ -422,6 +423,7 @@ extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; +extern PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv; extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; @@ -668,6 +670,7 @@ extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; +extern PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv; extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index b30bc1aed6..5d669fb955 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -349,8 +349,8 @@ void LLGLSLShader::unloadInternal() for (GLsizei i = 0; i < count; i++) { glDetachObjectARB(mProgramObject, obj[i]); - glDeleteObjectARB(obj[i]); - } + glDeleteObjectARB(obj[i]); + } glDeleteObjectARB(mProgramObject); @@ -1257,6 +1257,23 @@ void LLGLSLShader::uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, c } } +void LLGLSLShader::uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + glUniformMatrix3x4fv(mUniform[index], count, transpose, v); + } + } +} + void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) { if (mProgramObject > 0) diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 0746e8760a..6f10d122cb 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -115,6 +115,7 @@ public: void uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j); void uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); void uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); + void uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); void uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); void uniform1i(const LLStaticHashedString& uniform, GLint i); void uniform1f(const LLStaticHashedString& uniform, GLfloat v); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index ebed454271..81a5537f78 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -487,14 +487,15 @@ bool LLImageGL::checkSize(S32 width, S32 height) return check_power_of_two(width) && check_power_of_two(height); } -void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level) +bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level) { if (width != mWidth || height != mHeight || ncomponents != mComponents) { // Check if dimensions are a power of two! if (!checkSize(width,height)) { - LL_ERRS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL; + LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL; + return false; } if (mTexName) @@ -529,6 +530,8 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve mMaxDiscardLevel = MAX_DISCARD_LEVEL; } } + + return true; } //---------------------------------------------------------------------------- @@ -909,7 +912,11 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) S32 h = raw_image->getHeight() << discard_level; // setSize may call destroyGLTexture if the size does not match - setSize(w, h, raw_image->getComponents(), discard_level); + if (!setSize(w, h, raw_image->getComponents(), discard_level)) + { + LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; + return FALSE; + } if( !mHasExplicitFormat ) { @@ -1273,7 +1280,11 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S S32 h = raw_h << discard_level; // setSize may call destroyGLTexture if the size does not match - setSize(w, h, imageraw->getComponents(), discard_level); + if (!setSize(w, h, imageraw->getComponents(), discard_level)) + { + LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; + return FALSE; + } if( !mHasExplicitFormat ) { diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 21982eab1d..ad2aea9067 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -94,7 +94,7 @@ protected: public: virtual void dump(); // debugging info to LL_INFOS() - void setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level = -1); + bool setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level = -1); void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} void setAllowCompression(bool allow) { mAllowCompression = allow; } diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index b297223c2e..55f0791174 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -520,7 +520,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns, const std::string& if (!filename.empty()) { LL_CONT << "From " << filename << ":\n"; - } + } LL_CONT << log << LL_ENDL; } } diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 1d18cb2bb0..06fac190ed 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -123,7 +123,15 @@ bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool u // Concatenate the input string to the LL and the system clipboard bool LLClipboard::addToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) { - mString = src.substr(pos, len); + try + { + mString = src.substr(pos, len); + } + catch (const std::exception& e) + { + LL_WARNS() << "Can't add the substring to clipboard: " << e.what() << LL_ENDL; + return false; + } return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString)); } diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 8166ef6a07..f9664e0658 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -684,6 +684,13 @@ void LLFolderView::draw() } } + if (mRenameItem && mRenamer && mRenamer->getVisible() && !getVisibleRect().overlaps(mRenamer->getRect())) + { + // renamer is not connected to the item we are renaming in any form so manage it manually + // TODO: consider stopping on any scroll action instead of when out of visible area + finishRenamingItem(); + } + // skip over LLFolderViewFolder::draw since we don't want the folder icon, label, // and arrow for the root folder LLView::draw(); diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 5eb5ca4f82..3d618548c4 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -127,6 +127,8 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mIsSelected( FALSE ), mIsCurSelection( FALSE ), mSelectPending(FALSE), + mIsItemCut(false), + mCutGeneration(0), mLabelStyle( LLFontGL::NORMAL ), mHasVisibleChildren(FALSE), mIsFolderComplete(true), @@ -694,6 +696,19 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L return mIsCurSelection; } +/*virtual*/ bool LLFolderViewItem::isFadeItem() +{ + LLClipboard& clipboard = LLClipboard::instance(); + if (mCutGeneration != clipboard.getGeneration()) + { + mCutGeneration = clipboard.getGeneration(); + mIsItemCut = clipboard.isCutMode() + && ((getParentFolder() && getParentFolder()->isFadeItem()) + || getViewModelItem()->isCutToClipboard()); + } + return mIsItemCut; +} + void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor, const LLUIColor &focusOutlineColor, const LLUIColor &mouseOverColor) { @@ -875,6 +890,12 @@ void LLFolderViewItem::draw() } LLColor4 color = (mIsSelected && filled) ? mFontHighlightColor : mFontColor; + + if (isFadeItem()) + { + // Fade out item color to indicate it's being cut + color.mV[VALPHA] *= 0.5f; + } drawLabel(font, text_left, y, color, right_x); //--------------------------------------------------------------------------------// @@ -882,7 +903,7 @@ void LLFolderViewItem::draw() // if (!mLabelSuffix.empty()) { - font->renderUTF8( mLabelSuffix, 0, right_x, y, sSuffixColor, + font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &right_x, FALSE ); } diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 0322c8836d..61c39e0175 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -121,8 +121,11 @@ protected: mIsMouseOverTitle, mAllowWear, mAllowDrop, - mSelectPending; - + mSelectPending, + mIsItemCut; + + S32 mCutGeneration; + LLUIColor mFontColor; LLUIColor mFontHighlightColor; @@ -145,6 +148,7 @@ protected: virtual void addFolder(LLFolderViewFolder*) { } virtual bool isHighlightAllowed(); virtual bool isHighlightActive(); + virtual bool isFadeItem(); virtual bool isFlashing() { return false; } virtual void setFlashState(bool) { } diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index a395af537a..641241a88c 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -173,6 +173,7 @@ public: virtual BOOL isItemCopyable() const = 0; virtual BOOL copyToClipboard() const = 0; virtual BOOL cutToClipboard() = 0; + virtual bool isCutToClipboard() { return false; }; virtual BOOL isClipboardPasteable() const = 0; virtual void pasteFromClipboard() = 0; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 492c9315d1..c89e1dac1d 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -2636,10 +2636,17 @@ void LLLineEditor::showContextMenu(S32 x, S32 y) void LLLineEditor::setContextMenu(LLContextMenu* new_context_menu) { - if (new_context_menu) - mContextMenuHandle = new_context_menu->getHandle(); - else - mContextMenuHandle.markDead(); + LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); + if (menu) + { + menu->die(); + mContextMenuHandle.markDead(); + } + + if (new_context_menu) + { + mContextMenuHandle = new_context_menu->getHandle(); + } } void LLLineEditor::setFont(const LLFontGL* font) diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index c6d472f59b..ccbd305a16 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -272,7 +272,7 @@ public: void setReplaceNewlinesWithSpaces(BOOL replace); - void setContextMenu(LLContextMenu* new_context_menu); + void resetContextMenu() { setContextMenu(NULL); }; private: // private helper methods @@ -308,6 +308,8 @@ private: virtual S32 getPreeditFontSize() const; virtual LLWString getPreeditString() const { return getWText(); } + void setContextMenu(LLContextMenu* new_context_menu); + protected: LLUIString mText; // The string being edited. std::string mPrevText; // Saved string for 'ESC' revert diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index c7d7535f87..20be739286 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -181,7 +181,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mMaxTextByteLength( p.max_text_length ), mFont(p.font), mFontShadow(p.font_shadow), - mPopupMenu(NULL), + mPopupMenuHandle(), mReadOnly(p.read_only), mSpellCheck(p.spellcheck), mSpellCheckStart(-1), @@ -1263,9 +1263,10 @@ void LLTextBase::setReadOnlyColor(const LLColor4 &c) //virtual void LLTextBase::onVisibilityChange( BOOL new_visibility ) { - if(!new_visibility && mPopupMenu) + LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); + if(!new_visibility && menu) { - mPopupMenu->hide(); + menu->hide(); } LLUICtrl::onVisibilityChange(new_visibility); } @@ -1956,41 +1957,48 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); // create and return the context menu from the XUI file - delete mPopupMenu; + + LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); + if (menu) + { + menu->die(); + mPopupMenuHandle.markDead(); + } llassert(LLMenuGL::sMenuContainer != NULL); - mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer, - LLMenuHolderGL::child_registry_t::instance()); - if (mIsFriendSignal) - { - bool isFriend = *(*mIsFriendSignal)(LLUUID(LLUrlAction::getUserID(url))); - LLView* addFriendButton = mPopupMenu->getChild<LLView>("add_friend"); - LLView* removeFriendButton = mPopupMenu->getChild<LLView>("remove_friend"); + menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer, + LLMenuHolderGL::child_registry_t::instance()); + if (menu) + { + mPopupMenuHandle = menu->getHandle(); - if (addFriendButton && removeFriendButton) - { - addFriendButton->setEnabled(!isFriend); - removeFriendButton->setEnabled(isFriend); - } - } + if (mIsFriendSignal) + { + bool isFriend = *(*mIsFriendSignal)(LLUUID(LLUrlAction::getUserID(url))); + LLView* addFriendButton = menu->getChild<LLView>("add_friend"); + LLView* removeFriendButton = menu->getChild<LLView>("remove_friend"); - if (mIsObjectBlockedSignal) - { - bool is_blocked = *(*mIsObjectBlockedSignal)(LLUUID(LLUrlAction::getObjectId(url)), LLUrlAction::getObjectName(url)); - LLView* blockButton = mPopupMenu->getChild<LLView>("block_object"); - LLView* unblockButton = mPopupMenu->getChild<LLView>("unblock_object"); + if (addFriendButton && removeFriendButton) + { + addFriendButton->setEnabled(!isFriend); + removeFriendButton->setEnabled(isFriend); + } + } - if (blockButton && unblockButton) - { - blockButton->setVisible(!is_blocked); - unblockButton->setVisible(is_blocked); - } - } - - if (mPopupMenu) - { - mPopupMenu->show(x, y); - LLMenuGL::showPopup(this, mPopupMenu, x, y); - } + if (mIsObjectBlockedSignal) + { + bool is_blocked = *(*mIsObjectBlockedSignal)(LLUUID(LLUrlAction::getObjectId(url)), LLUrlAction::getObjectName(url)); + LLView* blockButton = menu->getChild<LLView>("block_object"); + LLView* unblockButton = menu->getChild<LLView>("unblock_object"); + + if (blockButton && unblockButton) + { + blockButton->setVisible(!is_blocked); + unblockButton->setVisible(is_blocked); + } + } + menu->show(x, y); + LLMenuGL::showPopup(this, menu, x, y); + } } void LLTextBase::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 85641fd899..3d3a6ca869 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -673,7 +673,7 @@ protected: S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes // support widgets - LLContextMenu* mPopupMenu; + LLHandle<LLContextMenu> mPopupMenuHandle; LLView* mDocumentView; LLScrollContainer* mScroller; diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index 324ceb7fba..bfe0a5bb5d 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -328,6 +328,15 @@ namespace LLTextValidate return rv; } + bool validateASCIINoLeadingSpace(const LLWString &str) + { + if (LLStringOps::isSpace(str[0])) + { + return FALSE; + } + return validateASCII(str); + } + // Used for multiline text stored on the server. // Example is landmark description in Places SP. bool validateASCIIWithNewLine(const LLWString &str) diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h index 5c830d7db3..e2b6c313d6 100644 --- a/indra/llui/lltextvalidate.h +++ b/indra/llui/lltextvalidate.h @@ -52,6 +52,7 @@ namespace LLTextValidate bool validateASCIIPrintableNoPipe(const LLWString &str); bool validateASCIIPrintableNoSpace(const LLWString &str); bool validateASCII(const LLWString &str); + bool validateASCIINoLeadingSpace(const LLWString &str); bool validateASCIIWithNewLine(const LLWString &str); } diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index aabc7ed2e4..f790d8e005 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -522,7 +522,7 @@ const LLView* LLUI::resolvePath(const LLView* context, const std::string& path) else { std::string part(ti->begin(), ti->end()); - context = context->findChildView(part, recurse); + context = context->findChildView(LLURI::unescape(part), recurse); recurse = false; } } diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index e4848362a7..27a2456deb 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -183,8 +183,9 @@ bool LLUrlEntryBase::isLinkDisabled() const bool LLUrlEntryBase::isWikiLinkCorrect(std::string url) { - std::string label = getLabelFromWikiLink(url); - return (LLUrlRegistry::instance().hasUrl(label)) ? false : true; + LLWString label = utf8str_to_wstring(getLabelFromWikiLink(url)); + label.erase(std::remove(label.begin(), label.end(), L'\u200B'), label.end()); + return (LLUrlRegistry::instance().hasUrl(wstring_to_utf8str(label))) ? false : true; } std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const @@ -205,9 +206,15 @@ std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const std::string label; up.extractParts(); - up.glueFirst(label); - std::string query = url.substr(label.size()); - return query; + up.glueFirst(label, false); + + size_t pos = url.find(label); + if (pos == std::string::npos) + { + return ""; + } + pos += label.size(); + return url.substr(pos); } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 62c3f401bf..9604e5ce10 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -391,7 +391,27 @@ static void buildPathname(std::ostream& out, const LLView* view) buildPathname(out, view->getParent()); // Build pathname into ostream on the way back from recursion. - out << '/' << view->getName(); + out << '/'; + + // substitute all '/' in name with appropriate code + std::string name = view->getName(); + std::size_t found = name.find('/'); + std::size_t start = 0; + while (found != std::string::npos) + { + std::size_t sub_len = found - start; + if (sub_len > 0) + { + out << name.substr(start, sub_len); + } + out << "%2F"; + start = found + 1; + found = name.find('/', start); + } + if (start < name.size()) + { + out << name.substr(start, name.size() - start); + } } std::string LLView::getPathname() const @@ -812,7 +832,7 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask) LLView* LLView::childFromPoint(S32 x, S32 y, bool recur) { if (!getVisible()) - return false; + return NULL; BOOST_FOREACH(LLView* viewp, mChildList) { diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 5f4fb8f4a0..86a15f2ef2 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -531,6 +531,13 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd case LL_PATH_PER_ACCOUNT_CHAT_LOGS: prefix = getPerAccountChatLogsDir(); + if (prefix.empty()) + { + // potentially directory was not set yet + // intentionally return a blank string to the caller + LL_DEBUGS("LLDir") << "Conversation log directory is not yet set" << LL_ENDL; + return std::string(); + } break; case LL_PATH_LOGS: diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 0a30f4c807..a05ba8cbba 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -166,6 +166,8 @@ public: // Provide native key event data virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } + // Get system UI size based on DPI (for 96 DPI UI size should be 1.0) + virtual F32 getSystemUISize() { return 1.0; } protected: LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags); virtual ~LLWindow(); diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index d2afb3f91b..474953d3a4 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -175,6 +175,11 @@ BOOL LLWindowCallbacks::handleDeviceChange(LLWindow *window) return FALSE; } +void LLWindowCallbacks::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height) +{ + +} + void LLWindowCallbacks::handlePingWatchdog(LLWindow *window, const char * msg) { diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 6a7137e593..de789a71d9 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -65,6 +65,7 @@ public: virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); virtual BOOL handleTimerEvent(LLWindow *window); virtual BOOL handleDeviceChange(LLWindow *window); + virtual void handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); enum DragNDropAction { DNDA_START_TRACKING = 0,// Start tracking an incoming drag diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 875ffe4cd4..4086db8e52 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -60,24 +60,50 @@ #include <dinput.h> #include <Dbt.h.> -// culled from winuser.h -#ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ -const S32 WM_MOUSEWHEEL = 0x020A; -#endif -#ifndef WHEEL_DELTA /* Added to be compatible with later SDK's */ -const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */ -#endif const S32 MAX_MESSAGE_PER_UPDATE = 20; const S32 BITS_PER_PIXEL = 32; const S32 MAX_NUM_RESOLUTIONS = 32; const F32 ICON_FLASH_TIME = 0.5f; +#ifndef WM_DPICHANGED +#define WM_DPICHANGED 0x02E0 +#endif + extern BOOL gDebugWindowProc; LPWSTR gIconResource = IDI_APPLICATION; LLW32MsgCallback gAsyncMsgCallback = NULL; +#ifndef DPI_ENUMS_DECLARED + +typedef enum PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +} PROCESS_DPI_AWARENESS; + +typedef enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI +} MONITOR_DPI_TYPE; + +#endif + +typedef HRESULT(STDAPICALLTYPE *SetProcessDpiAwarenessType)(_In_ PROCESS_DPI_AWARENESS value); + +typedef HRESULT(STDAPICALLTYPE *GetProcessDpiAwarenessType)( + _In_ HANDLE hprocess, + _Out_ PROCESS_DPI_AWARENESS *value); + +typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( + _In_ HMONITOR hmonitor, + _In_ MONITOR_DPI_TYPE dpiType, + _Out_ UINT *dpiX, + _Out_ UINT *dpiY); + // // LLWindowWin32 // @@ -2593,6 +2619,24 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; } + + case WM_DPICHANGED: + { + LPRECT lprc_new_scale; + F32 new_scale = LOWORD(w_param) / USER_DEFAULT_SCREEN_DPI; + lprc_new_scale = (LPRECT)l_param; + S32 new_width = lprc_new_scale->right - lprc_new_scale->left; + S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top; + window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height); + SetWindowPos(h_wnd, + HWND_TOP, + lprc_new_scale->left, + lprc_new_scale->top, + new_width, + new_height, + SWP_NOZORDER | SWP_NOACTIVATE); + return 0; + } case WM_SETFOCUS: window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS"); @@ -3879,6 +3923,92 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) } //static +void LLWindowWin32::setDPIAwareness() +{ + HMODULE hShcore = LoadLibrary(L"shcore.dll"); + if (hShcore != NULL) + { + SetProcessDpiAwarenessType pSPDA; + pSPDA = (SetProcessDpiAwarenessType)GetProcAddress(hShcore, "SetProcessDpiAwareness"); + if (pSPDA) + { + + HRESULT hr = pSPDA(PROCESS_PER_MONITOR_DPI_AWARE); + if (hr != S_OK) + { + LL_WARNS() << "SetProcessDpiAwareness() function returned an error. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; + } + } + FreeLibrary(hShcore); + } + else + { + LL_WARNS() << "Could not load shcore.dll library (included by <ShellScalingAPI.h> from Win 8.1 SDK. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; + } +} + +F32 LLWindowWin32::getSystemUISize() +{ + float scale_value = 0; + HWND hWnd = (HWND)getPlatformWindow(); + HDC hdc = GetDC(hWnd); + HMONITOR hMonitor; + HANDLE hProcess = GetCurrentProcess(); + PROCESS_DPI_AWARENESS dpi_awareness; + + HMODULE hShcore = LoadLibrary(L"shcore.dll"); + + if (hShcore != NULL) + { + GetProcessDpiAwarenessType pGPDA; + pGPDA = (GetProcessDpiAwarenessType)GetProcAddress(hShcore, "GetProcessDpiAwareness"); + GetDpiForMonitorType pGDFM; + pGDFM = (GetDpiForMonitorType)GetProcAddress(hShcore, "GetDpiForMonitor"); + if (pGPDA != NULL && pGDFM != NULL) + { + pGPDA(hProcess, &dpi_awareness); + if (dpi_awareness == PROCESS_PER_MONITOR_DPI_AWARE) + { + POINT pt; + UINT dpix = 0, dpiy = 0; + HRESULT hr = E_FAIL; + RECT rect; + + GetWindowRect(hWnd, &rect); + // Get the DPI for the monitor, on which the center of window is displayed and set the scaling factor + pt.x = (rect.left + rect.right) / 2; + pt.y = (rect.top + rect.bottom) / 2; + hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); + hr = pGDFM(hMonitor, MDT_EFFECTIVE_DPI, &dpix, &dpiy); + if (hr == S_OK) + { + scale_value = dpix / USER_DEFAULT_SCREEN_DPI; + } + else + { + LL_WARNS() << "Could not determine DPI for monitor. Setting scale to default 100 %" << LL_ENDL; + scale_value = 1.0f; + } + } + else + { + LL_WARNS() << "Process is not per-monitor DPI-aware. Setting scale to default 100 %" << LL_ENDL; + scale_value = 1.0f; + } + } + FreeLibrary(hShcore); + } + else + { + LL_WARNS() << "Could not load shcore.dll library (included by <ShellScalingAPI.h> from Win 8.1 SDK). Using legacy DPI awareness API of Win XP/7" << LL_ENDL; + scale_value = GetDeviceCaps(hdc, LOGPIXELSX) / USER_DEFAULT_SCREEN_DPI; + } + + ReleaseDC(hWnd, hdc); + return scale_value; +} + +//static std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList() { // Fonts previously in getFontListSans() have moved to fonts.xml. diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 1a775eadaf..39ef9b31a4 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -110,10 +110,12 @@ public: /*virtual*/ void interruptLanguageTextInput(); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + /*virtual*/ F32 getSystemUISize(); + LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); static std::vector<std::string> getDynamicFallbackFontList(); - + static void setDPIAwareness(); protected: LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt index 24eb3947b4..9055e0111a 100644 --- a/indra/media_plugins/CMakeLists.txt +++ b/indra/media_plugins/CMakeLists.txt @@ -4,15 +4,18 @@ add_subdirectory(base) if (LINUX) add_subdirectory(gstreamer010) + add_subdirectory(libvlc) endif (LINUX) -if (WINDOWS OR DARWIN) +if (DARWIN) add_subdirectory(quicktime) add_subdirectory(cef) -endif (WINDOWS OR DARWIN) +endif (DARWIN) if (WINDOWS) + add_subdirectory(cef) add_subdirectory(winmmshim) + add_subdirectory(libvlc) endif (WINDOWS) ### add_subdirectory(example) diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 8d9d1dd975..4eb29c98f9 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -100,6 +100,12 @@ private: LLCEFLib* mLLCEFLib; VolumeCatcher mVolumeCatcher; + + U8 *mPopupBuffer; + U32 mPopupW; + U32 mPopupH; + U32 mPopupX; + U32 mPopupY; }; //////////////////////////////////////////////////////////////////////////////// @@ -127,12 +133,19 @@ MediaPluginBase(host_send_func, host_user_data) mCookiePath = ""; mPickedFile = ""; mLLCEFLib = new LLCEFLib(); + + mPopupBuffer = NULL; + mPopupW = 0; + mPopupH = 0; + mPopupX = 0; + mPopupY = 0; } //////////////////////////////////////////////////////////////////////////////// // MediaPluginCEF::~MediaPluginCEF() { + delete[] mPopupBuffer; } //////////////////////////////////////////////////////////////////////////////// @@ -155,20 +168,28 @@ void MediaPluginCEF::postDebugMessage(const std::string& msg) // void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y, int width, int height, bool is_popup) { - if (mPixels && pixels) + if( is_popup ) + { + delete mPopupBuffer; + mPopupBuffer = NULL; + mPopupH = 0; + mPopupW = 0; + mPopupX = 0; + mPopupY = 0; + } + + if( mPixels && pixels ) { if (is_popup) { - for (int line = 0; line < height; ++line) + if( width > 0 && height> 0 ) { - int inverted_y = mHeight - y - height; - int src = line * width * mDepth; - int dst = (inverted_y + line) * mWidth * mDepth + x * mDepth; - - if (dst + width * mDepth < mWidth * mHeight * mDepth) - { - memcpy(mPixels + dst, pixels + src, width * mDepth); - } + mPopupBuffer = new U8[ width * height * mDepth ]; + memcpy( mPopupBuffer, pixels, width * height * mDepth ); + mPopupH = height; + mPopupW = width; + mPopupX = x; + mPopupY = mHeight - y - height; } } else @@ -177,6 +198,23 @@ void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y, { memcpy(mPixels, pixels, mWidth * mHeight * mDepth); } + if( mPopupBuffer && mPopupH && mPopupW ) + { + U32 bufferSize = mWidth * mHeight * mDepth; + U32 popupStride = mPopupW * mDepth; + U32 bufferStride = mWidth * mDepth; + int dstY = mPopupY; + + int src = 0; + int dst = dstY * mWidth * mDepth + mPopupX * mDepth; + + for( int line = 0; dst + popupStride < bufferSize && line < mPopupH; ++line ) + { + memcpy( mPixels + dst, mPopupBuffer + src, popupStride ); + src += popupStride; + dst += bufferStride; + } + } } setDirty(0, 0, mWidth, mHeight); @@ -463,6 +501,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) LLCEFLib::LLCEFLibSettings settings; settings.initial_width = 1024; settings.initial_height = 1024; + settings.page_zoom_factor = message_in.getValueReal("factor"); settings.plugins_enabled = mPluginsEnabled; settings.media_stream_enabled = false; // MAINT-6060 - WebRTC media removed until we can add granualrity/query UI settings.javascript_enabled = mJavascriptEnabled; @@ -559,6 +598,8 @@ void MediaPluginCEF::receiveMessage(const char* message_string) S32 x = message_in.getValueS32("x"); S32 y = message_in.getValueS32("y"); + y = mHeight - y; + // only even send left mouse button events to LLCEFLib // (partially prompted by crash in OS X CEF when sending right button events) // we catch the right click in viewer and display our own context menu anyway diff --git a/indra/media_plugins/libvlc/CMakeLists.txt b/indra/media_plugins/libvlc/CMakeLists.txt new file mode 100644 index 0000000000..535d29125b --- /dev/null +++ b/indra/media_plugins/libvlc/CMakeLists.txt @@ -0,0 +1,86 @@ +# -*- cmake -*- + +project(media_plugin_libvlc) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(OpenGL) + +include(LibVLCPlugin) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ${VLC_INCLUDE_DIR} +) +include_directories(SYSTEM + ${LLCOMMON_SYSTEM_INCLUDE_DIRS} + ) + + +### media_plugin_libvlc + +if(NOT WORD_SIZE EQUAL 32) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif(WINDOWS) +endif(NOT WORD_SIZE EQUAL 32) + +set(media_plugin_libvlc_SOURCE_FILES + media_plugin_libvlc.cpp + ) + +add_library(media_plugin_libvlc + SHARED + ${media_plugin_libvlc_SOURCE_FILES} +) + +target_link_libraries(media_plugin_libvlc + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${VLC_PLUGIN_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} +) + +add_dependencies(media_plugin_libvlc + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +if (WINDOWS) + set_target_properties( + media_plugin_libvlc + PROPERTIES + LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /LTCG /NODEFAULTLIB:LIBCMT" + ) +endif (WINDOWS) + +if (DARWIN) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name + set_target_properties( + media_plugin_libvlc + PROPERTIES + PREFIX "" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + ) + +endif (DARWIN) diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp new file mode 100644 index 0000000000..0bd323eb58 --- /dev/null +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -0,0 +1,618 @@ +/** +* @file media_plugin_libvlc.cpp +* @brief LibVLC plugin for LLMedia API plugin system +* +* @cond +* $LicenseInfo:firstyear=2008&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +* @endcond +*/ + +#include "linden_common.h" + +#include "llgl.h" +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#include "vlc/vlc.h" +#include "vlc/libvlc_version.h" + +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginLibVLC : + public MediaPluginBase +{ +public: + MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginLibVLC(); + + /*virtual*/ void receiveMessage(const char* message_string); + +private: + bool init(); + + void initVLC(); + void playMedia(); + void resetVLC(); + void setVolume(const F64 volume); + void updateTitle(const char* title); + + static void* lock(void* data, void** p_pixels); + static void unlock(void* data, void* id, void* const* raw_pixels); + static void display(void* data, void* id); + + /*virtual*/ void setDirty(int left, int top, int right, int bottom) /* override, but that is not supported in gcc 4.6 */; + + static void eventCallbacks(const libvlc_event_t* event, void* ptr); + + libvlc_instance_t* mLibVLC; + libvlc_media_t* mLibVLCMedia; + libvlc_media_player_t* mLibVLCMediaPlayer; + + struct mLibVLCContext + { + unsigned char* texture_pixels; + libvlc_media_player_t* mp; + MediaPluginLibVLC* parent; + }; + struct mLibVLCContext mLibVLCCallbackContext; + + std::string mURL; + F64 mCurVolume; + + bool mIsLooping; + + float mCurTime; + float mDuration; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +MediaPluginLibVLC::MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : +MediaPluginBase(host_send_func, host_user_data) +{ + mTextureWidth = 0; + mTextureHeight = 0; + mWidth = 0; + mHeight = 0; + mDepth = 4; + mPixels = 0; + + mLibVLC = 0; + mLibVLCMedia = 0; + mLibVLCMediaPlayer = 0; + + mCurVolume = 0.0; + + mIsLooping = false; + + mCurTime = 0.0; + mDuration = 0.0; + + mURL = std::string(); + + setStatus(STATUS_NONE); +} + +//////////////////////////////////////////////////////////////////////////////// +// +MediaPluginLibVLC::~MediaPluginLibVLC() +{ +} + +///////////////////////////////////////////////////////////////////////////////// +// +void* MediaPluginLibVLC::lock(void* data, void** p_pixels) +{ + struct mLibVLCContext* context = (mLibVLCContext*)data; + + *p_pixels = context->texture_pixels; + + return NULL; +} + +///////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::unlock(void* data, void* id, void* const* raw_pixels) +{ + // nothing to do here for the moment + // we *could* modify pixels here to, for example, Y flip, but this is done with + // a VLC video filter transform. +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::display(void* data, void* id) +{ + struct mLibVLCContext* context = (mLibVLCContext*)data; + + context->parent->setDirty(0, 0, context->parent->mWidth, context->parent->mHeight); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::initVLC() +{ + char const* vlc_argv[] = + { + "--no-xlib", + "--video-filter=transform{type=vflip}", // MAINT-6578 Y flip textures in plugin vs client + }; + + int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv); + mLibVLC = libvlc_new(vlc_argc, vlc_argv); + + if (!mLibVLC) + { + // for the moment, if this fails, the plugin will fail and + // the media sub-system will tell the viewer something went wrong. + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::resetVLC() +{ + libvlc_media_player_stop(mLibVLCMediaPlayer); + libvlc_media_player_release(mLibVLCMediaPlayer); + libvlc_release(mLibVLC); +} + +//////////////////////////////////////////////////////////////////////////////// +// *virtual* +void MediaPluginLibVLC::setDirty(int left, int top, int right, int bottom) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); + + message.setValueS32("left", left); + message.setValueS32("top", top); + message.setValueS32("right", right); + message.setValueS32("bottom", bottom); + + message.setValueReal("current_time", mCurTime); + message.setValueReal("duration", mDuration); + message.setValueReal("current_rate", 1.0f); + + sendMessage(message); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr) +{ + MediaPluginLibVLC* parent = (MediaPluginLibVLC*)ptr; + if (parent == 0) + { + return; + } + + switch (event->type) + { + case libvlc_MediaPlayerOpening: + parent->setStatus(STATUS_LOADING); + break; + + case libvlc_MediaPlayerPlaying: + parent->mDuration = (float)(libvlc_media_get_duration(parent->mLibVLCMedia)) / 1000.0f; + parent->setStatus(STATUS_PLAYING); + break; + + case libvlc_MediaPlayerPaused: + parent->setStatus(STATUS_PAUSED); + break; + + case libvlc_MediaPlayerStopped: + parent->setStatus(STATUS_DONE); + break; + + case libvlc_MediaPlayerEndReached: + parent->setStatus(STATUS_DONE); + break; + + case libvlc_MediaPlayerEncounteredError: + parent->setStatus(STATUS_ERROR); + break; + + case libvlc_MediaPlayerTimeChanged: + parent->mCurTime = (float)libvlc_media_player_get_time(parent->mLibVLCMediaPlayer) / 1000.0f; + break; + + case libvlc_MediaPlayerPositionChanged: + break; + + case libvlc_MediaPlayerLengthChanged: + parent->mDuration = (float)libvlc_media_get_duration(parent->mLibVLCMedia) / 1000.0f; + break; + + case libvlc_MediaPlayerTitleChanged: + { + char* title = libvlc_media_get_meta(parent->mLibVLCMedia, libvlc_meta_Title); + if (title) + { + parent->updateTitle(title); + } + } + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::playMedia() +{ + if (mURL.length() == 0) + { + return; + } + + if (mLibVLCMediaPlayer) + { + // stop listening to events while we reset things + libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer); + if (em) + { + libvlc_event_detach(em, libvlc_MediaPlayerOpening, eventCallbacks, NULL); + libvlc_event_detach(em, libvlc_MediaPlayerPlaying, eventCallbacks, NULL); + libvlc_event_detach(em, libvlc_MediaPlayerPaused, eventCallbacks, NULL); + libvlc_event_detach(em, libvlc_MediaPlayerStopped, eventCallbacks, NULL); + libvlc_event_detach(em, libvlc_MediaPlayerEndReached, eventCallbacks, NULL); + libvlc_event_detach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, NULL); + libvlc_event_detach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, NULL); + libvlc_event_detach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, NULL); + libvlc_event_detach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, NULL); + libvlc_event_detach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, NULL); + }; + + libvlc_media_player_stop(mLibVLCMediaPlayer); + libvlc_media_player_release(mLibVLCMediaPlayer); + + mLibVLCMediaPlayer = 0; + } + + if (mLibVLCMedia) + { + libvlc_media_release(mLibVLCMedia); + + mLibVLCMedia = 0; + } + + mLibVLCMedia = libvlc_media_new_location(mLibVLC, mURL.c_str()); + if (!mLibVLCMedia) + { + mLibVLCMediaPlayer = 0; + setStatus(STATUS_ERROR); + return; + } + + mLibVLCMediaPlayer = libvlc_media_player_new_from_media(mLibVLCMedia); + if (!mLibVLCMediaPlayer) + { + setStatus(STATUS_ERROR); + return; + } + + // listen to events + libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer); + if (em) + { + libvlc_event_attach(em, libvlc_MediaPlayerOpening, eventCallbacks, this); + libvlc_event_attach(em, libvlc_MediaPlayerPlaying, eventCallbacks, this); + libvlc_event_attach(em, libvlc_MediaPlayerPaused, eventCallbacks, this); + libvlc_event_attach(em, libvlc_MediaPlayerStopped, eventCallbacks, this); + libvlc_event_attach(em, libvlc_MediaPlayerEndReached, eventCallbacks, this); + libvlc_event_attach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, this); + libvlc_event_attach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, this); + libvlc_event_attach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, this); + libvlc_event_attach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, this); + libvlc_event_attach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, this); + } + + mLibVLCCallbackContext.parent = this; + mLibVLCCallbackContext.texture_pixels = mPixels; + mLibVLCCallbackContext.mp = mLibVLCMediaPlayer; + + // Send a "navigate begin" event. + // This is really a browser message but the QuickTime plugin did it and + // the media system relies on this message to update internal state so we must send it too + // Note: see "navigate_complete" message below too + // https://jira.secondlife.com/browse/MAINT-6528 + LLPluginMessage message_begin(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); + message_begin.setValue("uri", mURL); + message_begin.setValueBoolean("history_back_available", false); + message_begin.setValueBoolean("history_forward_available", false); + sendMessage(message_begin); + + // volume level gets set before VLC is initialized (thanks media system) so we have to record + // it in mCurVolume and set it again here so that volume levels are correctly initialized + setVolume(mCurVolume); + + setStatus(STATUS_LOADED); + + libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext); + libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth); + + // note this relies on the "set_loop" message arriving before the "start" (play) one + // but that appears to always be the case + if (mIsLooping) + { + libvlc_media_add_option(mLibVLCMedia, "input-repeat=-1"); + } + + libvlc_media_player_play(mLibVLCMediaPlayer); + + // send a "location_changed" message - this informs the media system + // that a new URL is the 'current' one and is used extensively. + // Again, this is really a browser message but we will use it here. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); + message.setValue("uri", mURL); + sendMessage(message); + + // Send a "navigate complete" event. + // This is really a browser message but the QuickTime plugin did it and + // the media system relies on this message to update internal state so we must send it too + // Note: see "navigate_begin" message above too + // https://jira.secondlife.com/browse/MAINT-6528 + LLPluginMessage message_complete(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); + message_complete.setValue("uri", mURL); + message_complete.setValueS32("result_code", 200); + message_complete.setValue("result_string", "OK"); + sendMessage(message_complete); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::updateTitle(const char* title) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", title); + sendMessage(message); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::setVolume(const F64 volume) +{ + mCurVolume = volume; + + if (mLibVLCMediaPlayer) + { + int result = libvlc_audio_set_volume(mLibVLCMediaPlayer, (int)(volume * 100)); + if (result != 0) + { + // volume wasn't set but not much to be done here + } + } + else + { + // volume change was requested but VLC wasn't ready. + // that's okay thought because we saved the value in mCurVolume and + // the next volume change after the VLC system is initilzied will set it + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::receiveMessage(const char* message_string) +{ + LLPluginMessage message_in; + + if (message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if (message_name == "init") + { + initVLC(); + + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + + std::ostringstream s; + s << "LibVLC plugin "; + s << LIBVLC_VERSION_MAJOR; + s << "."; + s << LIBVLC_VERSION_MINOR; + s << "."; + s << LIBVLC_VERSION_REVISION; + + message.setValue("plugin_version", s.str()); + sendMessage(message); + } + else if (message_name == "idle") + { + } + else if (message_name == "cleanup") + { + resetVLC(); + } + else if (message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if (message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if (iter != mSharedSegments.end()) + { + if (mPixels == iter->second.mAddress) + { + libvlc_media_player_stop(mLibVLCMediaPlayer); + libvlc_media_player_release(mLibVLCMediaPlayer); + mLibVLCMediaPlayer = 0; + + mPixels = NULL; + mTextureSegmentName.clear(); + } + mSharedSegments.erase(iter); + } + else + { + //std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { + //std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if (message_name == "init") + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + message.setValueS32("default_width", 1024); + message.setValueS32("default_height", 1024); + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGB); + message.setValueU32("format", GL_BGRA_EXT); + message.setValueU32("type", GL_UNSIGNED_BYTE); + message.setValueBoolean("coords_opengl", true); + sendMessage(message); + } + else if (message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + if (!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if (iter != mSharedSegments.end()) + { + mPixels = (unsigned char*)iter->second.mAddress; + mWidth = width; + mHeight = height; + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + playMedia(); + }; + }; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + } + else if (message_name == "load_uri") + { + mURL = message_in.getValue("uri"); + playMedia(); + } + } + else + if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if (message_name == "stop") + { + if (mLibVLCMediaPlayer) + { + libvlc_media_player_stop(mLibVLCMediaPlayer); + } + } + else if (message_name == "start") + { + if (mLibVLCMediaPlayer) + { + libvlc_media_player_play(mLibVLCMediaPlayer); + } + } + else if (message_name == "pause") + { + if (mLibVLCMediaPlayer) + { + libvlc_media_player_pause(mLibVLCMediaPlayer); + } + } + else if (message_name == "seek") + { + if (mDuration > 0) + { + F64 normalized_offset = message_in.getValueReal("time") / mDuration; + libvlc_media_player_set_position(mLibVLCMediaPlayer, normalized_offset); + } + } + else if (message_name == "set_loop") + { + mIsLooping = true; + } + else if (message_name == "set_volume") + { + // volume comes in 0 -> 1.0 + F64 volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool MediaPluginLibVLC::init() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", "LibVLC Plugin"); + sendMessage(message); + + return true; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, + void* host_user_data, + LLPluginInstance::sendMessageFunction *plugin_send_func, + void **plugin_user_data) +{ + MediaPluginLibVLC* self = new MediaPluginLibVLC(host_send_func, host_user_data); + *plugin_send_func = MediaPluginLibVLC::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} diff --git a/indra/media_plugins/quicktime/CMakeLists.txt b/indra/media_plugins/quicktime/CMakeLists.txt index c5615145be..58391007ff 100644..100755 --- a/indra/media_plugins/quicktime/CMakeLists.txt +++ b/indra/media_plugins/quicktime/CMakeLists.txt @@ -14,7 +14,6 @@ include(PluginAPI) include(MediaPluginBase) include(OpenGL) include(QuickTimePlugin) -include(Boost) include_directories( ${LLPLUGIN_INCLUDE_DIRS} @@ -54,12 +53,17 @@ target_link_libraries(media_plugin_quicktime ${PLUGIN_API_WINDOWS_LIBRARIES} ) +add_dependencies(media_plugin_quicktime + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + if (WINDOWS) set_target_properties( media_plugin_quicktime PROPERTIES - LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT" - LINK_FLAGS_DEBUG "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMTD" + LINK_FLAGS "/MANIFEST:NO" ) endif (WINDOWS) diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index 7ef5a0fe44..b43598e4a5 100644..100755 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -837,9 +837,7 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) else if(message_name == "cleanup") { // TODO: clean up here - LLPluginMessage message("base", "goodbye"); - sendMessage(message); - } + } else if(message_name == "shm_added") { SharedSegmentInfo info; @@ -921,6 +919,9 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) #endif message.setValueS32("depth", mDepth); message.setValueU32("internalformat", GL_RGB); + + // note this apparently only has an effect when media is opened in 2D browser. + // see https://jira.secondlife.com/browse/BUG-18252 - media flipped in 2D so flipping it back. message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. message.setValueBoolean("allow_downsample", true); sendMessage(message); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 195363fb75..d6d7d2c563 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -535,6 +535,7 @@ set(viewer_SOURCE_FILES llsidepaneliteminfo.cpp llsidepaneltaskinfo.cpp llsidetraypanelcontainer.cpp + llskinningutil.cpp llsky.cpp llslurl.cpp llsnapshotlivepreview.cpp @@ -1141,6 +1142,7 @@ set(viewer_HEADER_FILES llsidepaneliteminfo.h llsidepaneltaskinfo.h llsidetraypanelcontainer.h + llskinningutil.h llsky.h llslurl.h llsnapshotlivepreview.h @@ -1755,6 +1757,7 @@ if (WINDOWS) SLPlugin media_plugin_quicktime media_plugin_cef + media_plugin_libvlc winmm_shim windows-crash-logger ) @@ -1970,6 +1973,7 @@ if (LINUX) linux-crash-logger SLPlugin media_plugin_gstreamer010 + media_plugin_libvlc llcommon ) @@ -2077,7 +2081,7 @@ if (DARWIN) ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_cef mac-crash-logger) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_libvlc media_plugin_cef mac-crash-logger) add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger) if (ENABLE_SIGNING) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 7919852fe1..6b244dcd69 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -4.0.9 +5.0.1 diff --git a/indra/newview/app_settings/anim.ini b/indra/newview/app_settings/anim.ini index 63c84e544d..c24d2749ef 100644 --- a/indra/newview/app_settings/anim.ini +++ b/indra/newview/app_settings/anim.ini @@ -1,87 +1,2 @@ Translations 1.0 -[hip] - relativepos = firstkey - relativerot = firstkey - outname = mPelvis - frame = 0 1 0, 0 0 1, 1 0 0 - -[abdomen] - outname = mTorso - frame = 0 1 0, 0 0 1, 1 0 0 - -[chest] - outname = mChest - frame = 0 1 0, 0 0 1, 1 0 0 - -[neckDummy] - ignore = true - frame = 0 1 0, 0 0 1, 1 0 0 - -[neck] - outname = mNeck - frame = 0 1 0, 0 0 1, 1 0 0 - -[head] - outname = mHead - frame = 0 1 0, 0 0 1, 1 0 0 - -[figureHair] - ignore = true - frame = 0 1 0, 0 0 1, 1 0 0 - -[lCollar] - outname = mCollarLeft - frame = 0 1 0, 0 0 1, 1 0 0 - -[lShldr] - outname = mShoulderLeft - frame = 0 1 0, 0 0 1, 1 0 0 - -[lForeArm] - outname = mElbowLeft - frame = 0 1 0, 0 0 1, 1 0 0 - -[lHand] - outname = mWristLeft - frame = 0 1 0, 0 0 1, 1 0 0 - -[rCollar] - outname = mCollarRight - frame = 0 1 0, 0 0 1, 1 0 0 - -[rShldr] - outname = mShoulderRight - frame = 0 1 0, 0 0 1, 1 0 0 - -[rForeArm] - outname = mElbowRight - frame = 0 1 0, 0 0 1, 1 0 0 - -[rHand] - outname = mWristRight - frame = 0 1 0, 0 0 1, 1 0 0 - -[lThigh] - outname = mHipLeft - frame = 0 1 0, 0 0 1, 1 0 0 - -[lShin] - outname = mKneeLeft - frame = 0 1 0, 0 0 1, 1 0 0 - -[lFoot] - outname = mAnkleLeft - frame = 0 1 0, 0 0 1, 1 0 0 - -[rThigh] - outname = mHipRight - frame = 0 1 0, 0 0 1, 1 0 0 - -[rShin] - outname = mKneeRight - frame = 0 1 0, 0 0 1, 1 0 0 - -[rFoot] - outname = mAnkleRight - frame = 0 1 0, 0 0 1, 1 0 0
\ No newline at end of file diff --git a/indra/newview/app_settings/keywords_lsl_default.xml b/indra/newview/app_settings/keywords_lsl_default.xml index ddd287faf4..d641883d5a 100644 --- a/indra/newview/app_settings/keywords_lsl_default.xml +++ b/indra/newview/app_settings/keywords_lsl_default.xml @@ -528,7 +528,7 @@ <key>type</key> <string>integer</string> <key>value</key> - <integer>27</integer> + <integer>26</integer> <key>tooltip</key> <string>Attach to the avatar's lower upper leg.</string> </map> @@ -678,6 +678,141 @@ <key>tooltip</key> <string>Attach to the avatar's right upper leg.</string> </map> + <key>ATTACH_LHAND_RING1</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>41</integer> + <key>tooltip</key> + <string>Attach to the avatar's left ring finger.</string> + </map> + <key>ATTACH_RHAND_RING1</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>42</integer> + <key>tooltip</key> + <string>Attach to the avatar's right ring finger.</string> + </map> + <key>ATTACH_TAIL_BASE</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>43</integer> + <key>tooltip</key> + <string>Attach to the avatar's tail base.</string> + </map> + <key>ATTACH_TAIL_TIP</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>44</integer> + <key>tooltip</key> + <string>Attach to the avatar's tail tip.</string> + </map> + <key>ATTACH_LWING</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>45</integer> + <key>tooltip</key> + <string>Attach to the avatar's left wing.</string> + </map> + <key>ATTACH_RWING</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>46</integer> + <key>tooltip</key> + <string>Attach to the avatar's right wing.</string> + </map> + <key>ATTACH_FACE_JAW</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>47</integer> + <key>tooltip</key> + <string>Attach to the avatar's jaw.</string> + </map> + <key>ATTACH_FACE_LEAR</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>48</integer> + <key>tooltip</key> + <string>Attach to the avatar's left ear (extended).</string> + </map> + <key>ATTACH_FACE_REAR</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>49</integer> + <key>tooltip</key> + <string>Attach to the avatar's right ear (extended).</string> + </map> + <key>ATTACH_FACE_LEYE</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>50</integer> + <key>tooltip</key> + <string>Attach to the avatar's left eye (extended).</string> + </map> + <key>ATTACH_FACE_REYE</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>51</integer> + <key>tooltip</key> + <string>Attach to the avatar's right eye (extended).</string> + </map> + <key>ATTACH_FACE_TONGUE</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>52</integer> + <key>tooltip</key> + <string>Attach to the avatar's tongue.</string> + </map> + <key>ATTACH_GROIN</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>53</integer> + <key>tooltip</key> + <string>Attach to the avatar's groin.</string> + </map> + <key>ATTACH_HIND_LFOOT</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>54</integer> + <key>tooltip</key> + <string>Attach to the avatar's left hind foot.</string> + </map> + <key>ATTACH_HIND_RFOOT</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>55</integer> + <key>tooltip</key> + <string>Attach to the avatar's right hind foot.</string> + </map> <key>AVOID_CHARACTERS</key> <map> <key>type</key> @@ -809,7 +944,7 @@ <key>type</key> <string>integer</string> <key>value</key> - <integer>6</integer> + <integer>5</integer> <key>tooltip</key> <string/> </map> @@ -818,7 +953,7 @@ <key>type</key> <string>integer</string> <key>value</key> - <integer>22</integer> + <integer>21</integer> <key>tooltip</key> <string/> </map> @@ -872,7 +1007,7 @@ <key>type</key> <string>integer</string> <key>value</key> - <integer>2048</integer> + <string>0x800</string> <key>tooltip</key> <string/> </map> @@ -1463,9 +1598,9 @@ <key>type</key> <string>float</string> <key>value</key> - <real>0.01745329</real> + <real>0.017453293</real> <key>tooltip</key> - <string>0.01745329 - Number of radians per degree. + <string>0.017453293 - Number of radians per degree. You can use this to convert degrees to radians by multiplying the degrees by this number.</string> </map> <key>DENSITY</key> @@ -1482,7 +1617,7 @@ <key>type</key> <string>string</string> <key>value</key> - <string>0x0A0x0A0x0A</string> + <string>\\n\\n\\n</string> <key>tooltip</key> <string>Indicates the last line of a notecard was read.</string> </map> @@ -2299,7 +2434,7 @@ <key>NULL_KEY</key> <map> <key>type</key> - <string>key</string> + <string>string</string> <key>value</key> <uuid>00000000-0000-0000-0000-000000000000</uuid> <key>tooltip</key> @@ -2395,6 +2530,15 @@ <key>tooltip</key> <string>Gets the object's name.</string> </map> + <key>OBJECT_OMEGA</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>29</integer> + <key>tooltip</key> + <string>Gets an object's angular velocity.</string> + </map> <key>OBJECT_OWNER</key> <map> <key>type</key> @@ -2404,6 +2548,15 @@ <key>tooltip</key> <string>Gets an object's owner's key. If id is group owned, a NULL_KEY is returned.</string> </map> + <key>OBJECT_PRIM_COUNT</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>30</integer> + <key>tooltip</key> + <string>Gets the prim count of the object. The script and target object must be owned by the same owner</string> + </map> <key>OBJECT_PATHFINDING_TYPE</key> <map> <key>type</key> @@ -2494,6 +2647,15 @@ <key>tooltip</key> <string/> </map> + <key>OBJECT_REZZER_KEY</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>32</integer> + <key>tooltip</key> + <string/> + </map> <key>OBJECT_ROOT</key> <map> <key>type</key> @@ -2566,6 +2728,15 @@ <key>tooltip</key> <string>Returns boolean, detailing if temporary is enabled or disabled on the object.</string> </map> + <key>OBJECT_TOTAL_INVENTORY_COUNT</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>31</integer> + <key>tooltip</key> + <string>Gets the total inventory count of the object. The script and target object must be owned by the same owner</string> + </map> <key>OBJECT_TOTAL_SCRIPT_COUNT</key> <map> <key>type</key> @@ -3052,6 +3223,33 @@ <key>tooltip</key> <string/> </map> + <key>PASS_ALWAYS</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <string>1</string> + <key>tooltip</key> + <string>Always pass the event.</string> + </map> + <key>PASS_NEVER</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <string>2</string> + <key>tooltip</key> + <string>Always pass the event.</string> + </map> + <key>PASS_IF_NOT_HANDLED</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <string>0</string> + <key>tooltip</key> + <string>Pass the event if there is no script handling the event in the prim.</string> + </map> <key>PASSIVE</key> <map> <key>type</key> @@ -4387,6 +4585,24 @@ <key>tooltip</key> <string/> </map> + <key>PSYS_PART_BF_ONE_MINUS_SOURCE_COLOR</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>5</integer> + <key>tooltip</key> + <string/> + </map> + <key>PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA</key> + <map> + <key>type</key> + <string>integer</string> + <key>value</key> + <integer>9</integer> + <key>tooltip</key> + <string/> + </map> <key>PSYS_PART_BF_SOURCE_ALPHA</key> <map> <key>type</key> @@ -4536,7 +4752,7 @@ <key>type</key> <string>integer</string> <key>value</key> - <integer>19</integer> + <integer>7</integer> <key>tooltip</key> <string>Age in seconds of a particle at which it dies.</string> </map> @@ -5061,7 +5277,7 @@ <key>type</key> <string>integer</string> <key>value</key> - <integer>2</integer> + <integer>0</integer> <key>tooltip</key> <string/> </map> @@ -5295,7 +5511,7 @@ <key>type</key> <string>integer</string> <key>value</key> - <integer>64</integer> + <string>0x40</string> <key>tooltip</key> <string>Controls whether the object can be grabbed.\nA grab is the default action when in third person, and is available as the hand tool in build mode. This is useful for physical objects that you don't want other people to be able to trivially disturb. The default is FALSE</string> </map> @@ -5304,7 +5520,7 @@ <key>type</key> <string>integer</string> <key>value</key> - <integer>1024</integer> + <string>0x400</string> <key>tooltip</key> <string>Prevent click-and-drag movement on all prims in the object.</string> </map> @@ -5500,7 +5716,7 @@ <key>TEXTURE_BLANK</key> <map> <key>type</key> - <string>key</string> + <string>string</string> <key>value</key> <uuid>5748decc-f629-461c-9a36-a35a221fe21f</uuid> <key>tooltip</key> @@ -5509,7 +5725,7 @@ <key>TEXTURE_DEFAULT</key> <map> <key>type</key> - <string>key</string> + <string>string</string> <key>value</key> <uuid>89556747-24cb-43ed-920b-47caed15465f</uuid> <key>tooltip</key> @@ -5518,7 +5734,7 @@ <key>TEXTURE_MEDIA</key> <map> <key>type</key> - <string>key</string> + <string>string</string> <key>value</key> <uuid>8b5fec65-8d8d-9dc5-cda8-8fdf2716e361</uuid> <key>tooltip</key> @@ -5527,7 +5743,7 @@ <key>TEXTURE_PLYWOOD</key> <map> <key>type</key> - <string>key</string> + <string>string</string> <key>value</key> <uuid>89556747-24cb-43ed-920b-47caed15465f</uuid> <key>tooltip</key> @@ -5536,7 +5752,7 @@ <key>TEXTURE_TRANSPARENT</key> <map> <key>type</key> - <string>key</string> + <string>string</string> <key>value</key> <uuid>8dcd4a48-2d37-4909-9f78-f7a9eb4ef903</uuid> <key>tooltip</key> @@ -5956,7 +6172,7 @@ <key>type</key> <string>integer</string> <key>value</key> - <integer>35</integer> + <integer>31</integer> <key>tooltip</key> <string>The timescale for exponential decay of the linear motors magnitude.</string> </map> @@ -6204,15 +6420,6 @@ <key>tooltip</key> <string>An attempted write data to the key-value store failed due to the data quota being met.</string> </map> - <key>LSL_XP_ERROR_REQUEST_PERM_TIMEOUT</key> - <map> - <key>type</key> - <string>integer</string> - <key>value</key> - <integer>18</integer> - <key>tooltip</key> - <string>The request for experience permissions was ignored and timed out.</string> - </map> <key>XP_ERROR_RETRY_UPDATE</key> <map> <key>type</key> @@ -6562,30 +6769,43 @@ <key>experience_permissions</key> <map> <key>arguments</key> - <map> - <key>agent_id</key> - <map> + <array> + <map> + <key>agent_id</key> + <map> <key>type</key> <string>key</string> <key>tooltip</key> <string>ID of the agent approving permission for the Experience.</string> - </map> - </map> + </map> + </map> + </array> </map> <key>experience_permissions_denied</key> <map> <key>arguments</key> - <map> - <key>agent_id</key> - <map> + <array> + <map> + <key>agent_id</key> + <map> <key>type</key> <string>key</string> <key>tooltip</key> <string>ID of the agent denying permission for the Experience.</string> - </map> - </map> + </map> + </map> + <map> + <key>Reason</key> + <map> + <key>type</key> + <string>integer</string> + <key>tooltip</key> + <string>One of the XP_ERROR_... constants describing the reason why the Experience permissions were denied for the agent.</string> + </map> + </map> + </array> <key>tooltip</key> - <string>One of the XP_ERROR_... constants describing the reason why the Experience permissions were denied for the agent.</string> + <string>Describes why the Experience permissions were denied for the agent.</string> </map> <key>http_request</key> <map> @@ -7281,15 +7501,17 @@ <key>return</key> <string>integer</string> <key>arguments</key> - <map> - <key>AgentID</key> - <map> + <array> + <map> + <key>AgentID</key> + <map> <key>type</key> <string>key</string> <key>tooltip</key> <string></string> - </map> - </map> + </map> + </map> + </array> <key>tooltip</key> <string> Returns TRUE if the agent is in the Experience and the Experience can run in the current location. @@ -8035,7 +8257,8 @@ <key>return</key> <string>key</string> <key>arguments</key> - <map> + <array> + <map> <key>Key</key> <map> <key>type</key> @@ -8043,6 +8266,8 @@ <key>tooltip</key> <string></string> </map> + </map> + <map> <key>Value</key> <map> <key>type</key> @@ -8050,7 +8275,8 @@ <key>tooltip</key> <string></string> </map> - </map> + </map> + </array> <key>tooltip</key> <string> Starts an asychronous transaction to create a key-value pair. Will fail with XP_ERROR_STORAGE_EXCEPTION if the key already exists. The dataserver callback will be executed with the key returned from this call and a string describing the result. The result is a two element commma-delimited list. The first item is an integer specifying if the transaction succeeded (1) or not (0). In the failure case, the second item will be an integer corresponding to one of the XP_ERROR_... constants. In the success case the second item will be the value passed to the function. @@ -8148,15 +8374,17 @@ <key>return</key> <string>key</string> <key>arguments</key> - <map> - <key>Key</key> - <map> + <array> + <map> + <key>Key</key> + <map> <key>type</key> <string>string</string> <key>tooltip</key> <string></string> - </map> - </map> + </map> + </map> + </array> <key>tooltip</key> <string> Starts an asychronous transaction to delete a key-value pair. The dataserver callback will be executed with the key returned from this call and a string describing the result. The result is a two element commma-delimited list. The first item is an integer specifying if the transaction succeeded (1) or not (0). In the failure case, the second item will be an integer corresponding to one of the XP_ERROR_... constants. In the success case the second item will be the value associated with the key. @@ -9549,15 +9777,17 @@ <key>return</key> <string>list</string> <key>arguments</key> - <map> - <key>ExperienceID</key> - <map> + <array> + <map> + <key>ExperienceID</key> + <map> <key>type</key> <string>key</string> <key>tooltip</key> <string>May be NULL_KEY to retrieve the details for the script's Experience</string> - </map> - </map> + </map> + </map> + </array> <key>tooltip</key> <string> Returns a list with the following Experience properties: [Experience Name, Owner ID, Group ID, Experience ID, State, State Message]. State is an integer corresponding to one of the constants XP_ERROR_... and State Message is the string returned by llGetExperienceErrorMessage for that integer. @@ -9572,15 +9802,17 @@ <key>return</key> <string>string</string> <key>arguments</key> - <map> - <key>Error</key> - <map> + <array> + <map> + <key>Error</key> + <map> <key>type</key> <string>integer</string> <key>tooltip</key> <string>An Experience error code to translate.</string> - </map> - </map> + </map> + </map> + </array> <key>tooltip</key> <string> Returns a string describing the error code passed or the string corresponding with XP_ERROR_UNKNOWN_ERROR if the value is not a valid Experience error code. @@ -9930,7 +10162,7 @@ <key>Parameters</key> <map> <key>type</key> - <string>integer</string> + <string>list</string> <key>tooltip</key> <string>A list of PRIM_* property constants to return values of.</string> </map> @@ -10021,7 +10253,7 @@ <key>Parameters</key> <map> <key>type</key> - <string>integer</string> + <string>list</string> <key>tooltip</key> <string>PRIM_* flags.</string> </map> @@ -10782,7 +11014,7 @@ <key>sleep</key> <real>0.0</real> <key>return</key> - <string>void</string> + <string>float</string> <key>arguments</key> <undef/> <key>tooltip</key> @@ -11390,7 +11622,7 @@ <key>sleep</key> <real>0.0</real> <key>return</key> - <string>void</string> + <string>integer</string> <key>arguments</key> <array> <map> @@ -11937,22 +12169,26 @@ <key>return</key> <string>key</string> <key>arguments</key> - <map> - <key>First</key> - <map> + <array> + <map> + <key>First</key> + <map> <key>type</key> - <string>string</string> + <string>integer</string> <key>tooltip</key> <string>Index of the first key to return.</string> - </map> - <key>Count</key> - <map> + </map> + </map> + <map> + <key>Count</key> + <map> <key>type</key> - <string>string</string> + <string>integer</string> <key>tooltip</key> <string>The number of keys to return.</string> - </map> - </map> + </map> + </map> + </array> <key>tooltip</key> <string> Starts an asychronous transaction the request a number of keys from the data store. The dataserver callback will be executed with the key returned from this call and a string describing the result. The result is commma-delimited list. The first item is an integer specifying if the transaction succeeded (1) or not (0). In the failure case, the second item will be an integer corresponding to one of the XP_ERROR_... constants. The error XP_ERROR_KEY_NOT_FOUND is returned if First is greater than or equal to the number of keys in the data store. In the success case the subsequent items will be the keys requested. The number of keys returned may be less than requested if the return value is too large or if there is not enough keys remaining. The order keys are returned is not guaranteed but is stable between subsequent calls as long as no keys are added or removed. Because the keys are returned in a comma-delimited list it is not recommended to use commas in key names if this function is used. @@ -11981,7 +12217,7 @@ <key>Rules</key> <map> <key>type</key> - <string>integer</string> + <string>list</string> <key>tooltip</key> <string>Particle system rules list in the format [ rule1, data1, rule2, data2 . . . ruleN, dataN ]</string> </map> @@ -13142,6 +13378,15 @@ </map> </map> <map> + <key>Bounce</key> + <map> + <key>type</key> + <string>integer</string> + <key>tooltip</key> + <string/> + </map> + </map> + <map> <key>Texture</key> <map> <key>type</key> @@ -13159,6 +13404,15 @@ <string/> </map> </map> + <map> + <key>Bounce_Offset</key> + <map> + <key>type</key> + <string>float</string> + <key>tooltip</key> + <string/> + </map> + </map> </array> <key>tooltip</key> <string>Make a fountain of particles. Deprecated: Use llParticleSystem instead.\nMake a fountain of particles using texture from the objects inventory. Deprecated: Use llParticleSystem instead.</string> @@ -13959,7 +14213,7 @@ <key>sleep</key> <real>0.0</real> <key>return</key> - <string>void</string> + <string>float</string> <key>arguments</key> <array> <map> @@ -14098,7 +14352,8 @@ <key>return</key> <string>key</string> <key>arguments</key> - <map> + <array> + <map> <key>Key</key> <map> <key>type</key> @@ -14106,7 +14361,8 @@ <key>tooltip</key> <string></string> </map> - </map> + </map> + </array> <key>tooltip</key> <string> Starts an asychronous transaction to retrieve the value associated with the key given. Will fail with XP_ERROR_KEY_NOT_FOUND if the key does not exist. The dataserver callback will be executed with the key returned from this call and a string describing the result. The result is a two element commma-delimited list. The first item is an integer specifying if the transaction succeeded (1) or not (0). In the failure case, the second item will be an integer corresponding to one of the XP_ERROR_... constants. In the success case the second item will be the value associated with the key. @@ -14148,7 +14404,7 @@ <key>Text</key> <map> <key>type</key> - <string>integer</string> + <string>string</string> <key>tooltip</key> <string>Message to be transmitted.</string> </map> @@ -14541,22 +14797,26 @@ <key>return</key> <string>void</string> <key>arguments</key> - <map> - <key>AvatarID</key> - <map> + <array> + <map> + <key>AgentID</key> + <map> <key>type</key> <string>key</string> <key>tooltip</key> <string/> - </map> - <key>unused</key> - <map> + </map> + </map> + <map> + <key>unused</key> + <map> <key>type</key> <string>string</string> <key>tooltip</key> <string>Not used, should be ""</string> - </map> - </map> + </map> + </map> + </array> <key>tooltip</key> <string> Ask the agent for permission to participate in an experience. This request is similar to llRequestPermissions with the following permissions: PERMISSION_TAKE_CONTROLS, PERMISSION_TRIGGER_ANIMATION, PERMISSION_ATTACH, PERMISSION_TRACK_CAMERA, PERMISSION_CONTROL_CAMERA and PERMISSION_TELEPORT. However, unlike llRequestPermissions the decision to allow or block the request is persistent and applies to all scripts using the experience grid wide. Subsequent calls to llRequestExperiencePermissions from scripts in the experience will receive the same response automatically with no user interaction. One of experience_permissions or experience_permissions_denied will be generated in response to this call. Outstanding permission requests will be lost if the script is derezzed, moved to another region or reset. @@ -17363,7 +17623,7 @@ <key>ParameterValue</key> <map> <key>type</key> - <string>float</string> + <string>rotation</string> <key>tooltip</key> <string/> </map> @@ -17418,7 +17678,7 @@ <key>ParameterValue</key> <map> <key>type</key> - <string>float</string> + <string>vector</string> <key>tooltip</key> <string/> </map> @@ -18487,36 +18747,44 @@ <key>return</key> <string>key</string> <key>arguments</key> - <map> - <key>Key</key> - <map> + <array> + <map> + <key>Key</key> + <map> <key>type</key> <string>string</string> <key>tooltip</key> <string></string> - </map> - <key>Value</key> - <map> + </map> + </map> + <map> + <key>Value</key> + <map> <key>type</key> <string>string</string> <key>tooltip</key> <string></string> - </map> - <key>Checked</key> - <map> + </map> + </map> + <map> + <key>Checked</key> + <map> <key>type</key> <string>integer</string> <key>tooltip</key> <string></string> - </map> - <key>OriginalValue</key> - <map> + </map> + </map> + <map> + <key>OriginalValue</key> + <map> <key>type</key> <string>string</string> <key>tooltip</key> <string></string> - </map> - </map> + </map> + </map> + </array> <key>tooltip</key> <string> Starts an asychronous transaction to update the value associated with the key given. The dataserver callback will be executed with the key returned from this call and a string describing the result. The result is a two element commma-delimited list. The first item is an integer specifying if the transaction succeeded (1) or not (0). In the failure case, the second item will be an integer corresponding to one of the XP_ERROR_... constants. In the success case the second item will be the value associated with the key. If Checked is 1 the existing value in the data store must match the OriginalValue passed or XP_ERROR_RETRY_UPDATE will be returned. If Checked is 0 the key will be created if necessary. @@ -18868,31 +19136,8 @@ <key>tooltip</key> <string>Returns the largest multiplicative uniform scale factor that can be successfully applied (via llScaleByFactor()) to the object without violating prim size or linkability rules.</string> </map> - <key>llScaleByFactor</key> - <map> - <key>energy</key> - <real>10.0</real> - <key>sleep</key> - <real>0.0</real> - <key>return</key> - <string>float</string> - <key>arguments</key> - <array> - <map> - <key>Factor</key> - <map> - <key>type</key> - <string>float</string> - <key>tooltip</key> - <string/> - </map> - </map> - </array> - <key>tooltip</key> - <string>Tries to uniformly scale the object by a multiplicative factor. Returns TRUE on success or FALSE on failure.</string> - </map> </map> <key>llsd-lsl-syntax-version</key> - <integer>2</integer> + <integer>2</integer><!-- increment only when the file format changes, not just the content --> </map> </llsd> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2d3c885522..6621b9e269 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2205,6 +2205,17 @@ <key>Value</key> <string /> </map> + <key>DebugAvatarJoints</key> + <map> + <key>Comment</key> + <string>List of joints to emit additional debugging info about.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string /> + </map> <key>DebugAvatarRezTime</key> <map> <key>Comment</key> @@ -3525,6 +3536,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>IncludeEnhancedSkeleton</key> + <map> + <key>Comment</key> + <string>Include extended skeleton joints when rendering skinned meshes.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>MinObjectsForUnlinkConfirm</key> <map> <key>Comment</key> @@ -4515,28 +4537,6 @@ <key>Value</key> <string>http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD]</string> </map> - <key>WebProfileURL</key> - <map> - <key>Comment</key> - <string>URL for Web Profiles</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>https://my.secondlife.com/[AGENT_NAME]</string> - </map> - <key>WebProfileNonProductionURL</key> - <map> - <key>Comment</key> - <string>URL for Web Profiles on Non-Production grids</string> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>https://my-demo.secondlife.com/[AGENT_NAME]</string> - </map> <key>HighResSnapshot</key> <map> <key>Comment</key> @@ -4881,7 +4881,7 @@ <key>InventoryTrashMaxCapacity</key> <map> <key>Comment</key> - <string>Maximum capacity of the Trash folder. User will ve offered to clean it up when exceeded.</string> + <string>Maximum capacity of the Trash folder. User will be offered to clean it up when exceeded.</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -6429,7 +6429,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>1</integer> + <integer>0</integer> </map> <key>MeshUploadLogXML</key> <map> @@ -7951,6 +7951,17 @@ <key>Value</key> <integer>100000</integer> </map> + <key>PrimTextMaxDrawDistance</key> + <map> + <key>Comment</key> + <string>Maximum draw distance beyond which PRIM_TEXT won't be rendered</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>64.0</real> + </map> <key>ProbeHardwareOnStartup</key> <map> <key>Comment</key> @@ -10103,6 +10114,17 @@ <key>Value</key> <integer>10</integer> </map> + <key>ComplexityChangesPopUpDelay</key> + <map> + <key>Comment</key> + <string>Delay before viewer will show avatar complexity notice again</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>300</integer> + </map> <key>RenderAvatarMaxComplexity</key> <map> <key>Comment</key> @@ -10115,6 +10137,50 @@ <key>Value</key> <integer>0</integer> </map> + <key>RenderHUDObjectsWarning</key> + <map> + <key>Comment</key> + <string>Viewer will warn user about HUD containing to many objects if objects count is above this value</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>1000</integer> + </map> + <key>RenderHUDTexturesWarning</key> + <map> + <key>Comment</key> + <string>Viewer will warn user about HUD containing to many textures if texture count is above this value</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>200</integer> + </map> + <key>RenderHUDOversizedTexturesWarning</key> + <map> + <key>Comment</key> + <string>How many textures with size 1024 * 1024 or bigger HUD can contain before notifying user</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>6</integer> + </map> + <key>RenderHUDTexturesMemoryWarning</key> + <map> + <key>Comment</key> + <string>Viewer will warn user about HUD textures using memory above this value (in bytes)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>32000000</integer> + </map> <key>RenderAutoMuteSurfaceAreaLimit</key> <map> <key>Comment</key> @@ -12803,6 +12869,17 @@ <key>Value</key> <real>1.0</real> </map> + <key>LastSystemUIScaleFactor</key> + <map> + <key>Comment</key> + <string>Size of system UI during last run. On Windows 100% (96 DPI) system setting is 1.0 UI size</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.0</real> + </map> <key>UIScrollbarSize</key> <map> <key>Comment</key> @@ -13298,6 +13375,17 @@ <key>Value</key> <string>1</string> </map> + <key>UpdaterShowReleaseNotes</key> + <map> + <key>Comment</key> + <string>Enables displaying of the Release notes in a web floater after update.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>UploadBakedTexOld</key> <map> <key>Comment</key> @@ -14486,6 +14574,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>LogWearableAssetSave</key> + <map> + <key>Comment</key> + <string>Save copy of saved wearables to log dir</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>LogTextureDownloadsToViewerLog</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl index 3060307b21..90bf2851c9 100644 --- a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl +++ b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl @@ -24,8 +24,7 @@ ATTRIBUTE vec4 weight4; -uniform mat3 matrixPalette[52]; -uniform vec3 translationPalette[52]; +uniform mat3x4 matrixPalette[MAX_JOINTS_PER_MESH_OBJECT]; mat4 getObjectSkinnedTransform() { @@ -34,8 +33,8 @@ mat4 getObjectSkinnedTransform() vec4 w = fract(weight4); vec4 index = floor(weight4); - index = min(index, vec4(51.0)); - index = max(index, vec4( 0.0)); + index = min(index, vec4(MAX_JOINTS_PER_MESH_OBJECT-1)); + index = max(index, vec4( 0.0)); w *= 1.0/(w.x+w.y+w.z+w.w); @@ -43,16 +42,16 @@ mat4 getObjectSkinnedTransform() int i2 = int(index.y); int i3 = int(index.z); int i4 = int(index.w); - - mat3 mat = matrixPalette[i1]*w.x; - mat += matrixPalette[i2]*w.y; - mat += matrixPalette[i3]*w.z; - mat += matrixPalette[i4]*w.w; - vec3 trans = translationPalette[i1]*w.x; - trans += translationPalette[i2]*w.y; - trans += translationPalette[i3]*w.z; - trans += translationPalette[i4]*w.w; + mat3 mat = mat3(matrixPalette[i1])*w.x; + mat += mat3(matrixPalette[i2])*w.y; + mat += mat3(matrixPalette[i3])*w.z; + mat += mat3(matrixPalette[i4])*w.w; + + vec3 trans = vec3(matrixPalette[i1][0].w,matrixPalette[i1][1].w,matrixPalette[i1][2].w)*w.x; + trans += vec3(matrixPalette[i2][0].w,matrixPalette[i2][1].w,matrixPalette[i2][2].w)*w.y; + trans += vec3(matrixPalette[i3][0].w,matrixPalette[i3][1].w,matrixPalette[i3][2].w)*w.z; + trans += vec3(matrixPalette[i4][0].w,matrixPalette[i4][1].w,matrixPalette[i4][2].w)*w.w; mat4 ret; @@ -65,10 +64,8 @@ mat4 getObjectSkinnedTransform() #ifdef IS_AMD_CARD // If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage awawy which leads to unfun crashes and artifacts. - mat3 dummy1 = matrixPalette[0]; - vec3 dummy2 = translationPalette[0]; - mat3 dummy3 = matrixPalette[51]; - vec3 dummy4 = translationPalette[51]; + mat3x4 dummy1 = matrixPalette[0]; + mat3x4 dummy2 = matrixPalette[MAX_JOINTS_PER_MESH_OBJECT-1]; #endif } diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 7f7eaed38a..90f06746c9 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="US-ASCII" standalone="yes"?> <linden_avatar - version="1.0" wearable_definition_version="22"> + version="2.0" wearable_definition_version="22"> <!-- The wearable_definition_version is checked during asset upload. --> <!-- If you increment it, check indra/lib/python/indra/assetutil.py. --> <skeleton @@ -11,6 +11,7 @@ pie_slice="2" name="Chest" joint="mChest" + location="ATTACH_CHEST" position="0.15 0 -0.1" rotation="0 90 90" visible_in_first_person="true" /> @@ -21,6 +22,7 @@ pie_slice="2" name="Skull" joint="mHead" + location="ATTACH_HEAD" position="0 0 0.15" rotation="0 0 90" visible_in_first_person="false" /> @@ -31,6 +33,7 @@ pie_slice="3" name="Left Shoulder" joint="mCollarLeft" + location="ATTACH_LSHOULDER" position="0 0 0.08" rotation="0 0 0" visible_in_first_person="true" /> @@ -41,6 +44,7 @@ pie_slice="1" name="Right Shoulder" joint="mCollarRight" + location="ATTACH_RSHOULDER" position="0 0 0.08" rotation="0 0 0" visible_in_first_person="true"/> @@ -50,6 +54,7 @@ group="4" name="Left Hand" joint="mWristLeft" + location="ATTACH_LHAND" position="0 0.08 -0.02" rotation="0 0 0" visible_in_first_person="true" @@ -60,6 +65,7 @@ group="0" name="Right Hand" joint="mWristRight" + location="ATTACH_RHAND" position="0 -0.08 -0.02" rotation="0 0 0" visible_in_first_person="true" @@ -71,6 +77,7 @@ pie_slice="6" name="Left Foot" joint="mFootLeft" + location="ATTACH_LFOOT" position="0 0.0 0.0" rotation="0 0 0" visible_in_first_person="true"/> @@ -81,6 +88,7 @@ pie_slice="6" name="Right Foot" joint="mFootRight" + location="ATTACH_RFOOT" position="0 0.0 0.0" rotation="0 0 0" visible_in_first_person="true"/> @@ -91,6 +99,7 @@ pie_slice="7" name="Spine" joint="mChest" + location="ATTACH_BACK" position="-0.15 0 -0.1" rotation="0 -90 90" visible_in_first_person="true" /> @@ -101,6 +110,7 @@ pie_slice="6" name="Pelvis" joint="mPelvis" + location="ATTACH_PELVIS" position="0 0 -0.15" rotation="0 0 0" visible_in_first_person="true" /> @@ -111,6 +121,7 @@ pie_slice="6" name="Mouth" joint="mHead" + location="ATTACH_MOUTH" position="0.12 0 0.001" rotation="0 0 0" visible_in_first_person="false"/> @@ -121,6 +132,7 @@ pie_slice="7" name="Chin" joint="mHead" + location="ATTACH_CHIN" position="0.12 0 -0.04" rotation="0 0 0" visible_in_first_person="false" /> @@ -131,6 +143,7 @@ pie_slice="4" name="Left Ear" joint="mHead" + location="ATTACH_LEAR" position="0.015 0.08 0.017" rotation="0 0 0" visible_in_first_person="false" /> @@ -141,6 +154,7 @@ pie_slice="0" name="Right Ear" joint="mHead" + location="ATTACH_REAR" position="0.015 -0.08 0.017" rotation="0 0 0" visible_in_first_person="false" /> @@ -151,6 +165,7 @@ pie_slice="3" name="Left Eyeball" joint="mEyeLeft" + location="ATTACH_LEYE" position="0 0 0" rotation="0 0 0" visible_in_first_person="false"/> @@ -161,6 +176,7 @@ pie_slice="1" name="Right Eyeball" joint="mEyeRight" + location="ATTACH_REYE" position="0 0 0" rotation="0 0 0" visible_in_first_person="false" /> @@ -171,6 +187,7 @@ pie_slice="5" name="Nose" joint="mHead" + location="ATTACH_NOSE" position="0.1 0 0.05" rotation="0 0 0" visible_in_first_person="false"/> @@ -181,6 +198,7 @@ pie_slice="0" name="R Upper Arm" joint="mShoulderRight" + location="ATTACH_RUARM" position="0.01 -0.13 0.01" rotation="0 0 0" visible_in_first_person="true" /> @@ -191,6 +209,7 @@ pie_slice="7" name="R Forearm" joint="mElbowRight" + location="ATTACH_RLARM" position="0 -0.12 0" rotation="0 0 0" visible_in_first_person="true"/> @@ -201,6 +220,7 @@ pie_slice="4" name="L Upper Arm" joint="mShoulderLeft" + location="ATTACH_LUARM" position="0.01 0.15 -0.01" rotation="0 0 0" visible_in_first_person="true" /> @@ -211,6 +231,7 @@ pie_slice="5" name="L Forearm" joint="mElbowLeft" + location="ATTACH_LLARM" position="0 0.113 0" rotation="0 0 0" visible_in_first_person="true" /> @@ -221,6 +242,7 @@ pie_slice="1" name="Right Hip" joint="mHipRight" + location="ATTACH_RHIP" position="0 0 0" rotation="0 0 0" visible_in_first_person="true" /> @@ -231,6 +253,7 @@ pie_slice="0" name="R Upper Leg" joint="mHipRight" + location="ATTACH_RULEG" position="-0.017 0.041 -0.310" rotation="0 0 0" visible_in_first_person="true" /> @@ -241,6 +264,7 @@ pie_slice="7" name="R Lower Leg" joint="mKneeRight" + location="ATTACH_RLLEG" position="-0.044 -0.007 -0.262" rotation="0 0 0" visible_in_first_person="true" /> @@ -251,6 +275,7 @@ pie_slice="3" name="Left Hip" joint="mHipLeft" + location="ATTACH_LHIP" position="0 0 0" rotation="0 0 0" visible_in_first_person="true" /> @@ -261,6 +286,7 @@ pie_slice="4" name="L Upper Leg" joint="mHipLeft" + location="ATTACH_LULEG" position="-0.019 -0.034 -0.310" rotation="0 0 0" visible_in_first_person="true"/> @@ -271,6 +297,7 @@ pie_slice="5" name="L Lower Leg" joint="mKneeLeft" + location="ATTACH_LLLEG" position="-0.044 -0.007 -0.261" rotation="0 0 0" visible_in_first_person="true" /> @@ -281,6 +308,7 @@ pie_slice="5" name="Stomach" joint="mPelvis" + location="ATTACH_BELLY" position="0.092 0.0 0.088" rotation="0 0 0" visible_in_first_person="true" /> @@ -291,6 +319,7 @@ pie_slice="3" name="Left Pec" joint="mTorso" + location="ATTACH_LEFT_PEC" position="0.104 0.082 0.247" rotation="0 0 0" visible_in_first_person="true" /> @@ -301,15 +330,17 @@ pie_slice="1" name="Right Pec" joint="mTorso" + location="ATTACH_RIGHT_PEC" position="0.104 -0.082 0.247" rotation="0 0 0" visible_in_first_person="true" /> <attachment_point id="31" - group="8" + group="9" name="Center 2" joint="mScreen" + location="ATTACH_HUD_CENTER_2" position="0 0 0" rotation="0 0 0" hud="true" @@ -318,9 +349,10 @@ <attachment_point id="32" - group="8" + group="9" name="Top Right" joint="mScreen" + location="ATTACH_HUD_TOP_RIGHT" position="0 -0.5 0.5" rotation="0 0 0" hud="true" @@ -329,9 +361,10 @@ <attachment_point id="33" - group="8" + group="9" name="Top" joint="mScreen" + location="ATTACH_HUD_TOP_CENTER" position="0 0 0.5" rotation="0 0 0" hud="true" @@ -340,9 +373,10 @@ <attachment_point id="34" - group="8" + group="9" name="Top Left" joint="mScreen" + location="ATTACH_HUD_TOP_LEFT" position="0 0.5 0.5" rotation="0 0 0" hud="true" @@ -351,9 +385,10 @@ <attachment_point id="35" - group="8" + group="9" name="Center" joint="mScreen" + location="ATTACH_HUD_CENTER_1" position="0 0 0" rotation="0 0 0" hud="true" @@ -362,9 +397,10 @@ <attachment_point id="36" - group="8" + group="9" name="Bottom Left" joint="mScreen" + location="ATTACH_HUD_BOTTOM_LEFT" position="0 0.5 -0.5" rotation="0 0 0" hud="true" @@ -373,9 +409,10 @@ <attachment_point id="37" - group="8" + group="9" name="Bottom" joint="mScreen" + location="ATTACH_HUD_BOTTOM" position="0 0 -0.5" rotation="0 0 0" hud="true" @@ -384,9 +421,10 @@ <attachment_point id="38" - group="8" + group="9" name="Bottom Right" joint="mScreen" + location="ATTACH_HUD_BOTTOM_RIGHT" position="0 -0.5 -0.5" rotation="0 0 0" hud="true" @@ -399,6 +437,7 @@ pie_slice="1" name="Neck" joint="mNeck" + location="ATTACH_NECK" position="0 0 0" rotation="0 0 0" visible_in_first_person="true" /> @@ -409,10 +448,180 @@ pie_slice="2" name="Avatar Center" joint="mRoot" + location="ATTACH_AVATAR_CENTER" position="0 0 0" rotation="0 0 0" visible_in_first_person="true" /> - + + <!-- BENTO ADDITIONS --> + + <attachment_point + id="41" + group="8" + pie_slice="0" + name="Left Ring Finger" + joint="mHandRing1Left" + location="ATTACH_LHAND_RING1" + position="-0.006 0.019 -0.002" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="42" + group="8" + pie_slice="1" + name="Right Ring Finger" + joint="mHandRing1Right" + location="ATTACH_RHAND_RING1" + position="-0.006 -0.019 -0.002" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="43" + group="8" + pie_slice="2" + name="Tail Base" + joint="mTail1" + location="ATTACH_TAIL_BASE" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="44" + group="8" + pie_slice="3" + name="Tail Tip" + joint="mTail6" + location="ATTACH_TAIL_TIP" + position="-0.025 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="45" + group="8" + pie_slice="4" + name="Left Wing" + joint="mWing4Left" + location="ATTACH_LWING" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="46" + group="8" + pie_slice="5" + name="Right Wing" + joint="mWing4Right" + location="ATTACH_RWING" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="47" + group="8" + pie_slice="6" + name="Jaw" + joint="mFaceJaw" + location="ATTACH_FACE_JAW" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="48" + group="8" + pie_slice="7" + name="Alt Left Ear" + joint="mFaceEar1Left" + location="ATTACH_FACE_LEAR" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="49" + group="8" + pie_slice="8" + name="Alt Right Ear" + joint="mFaceEar1Right" + location="ATTACH_FACE_REAR" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="50" + group="8" + pie_slice="9" + name="Alt Left Eye" + joint="mFaceEyeAltLeft" + location="ATTACH_FACE_LEYE" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="51" + group="8" + pie_slice="10" + name="Alt Right Eye" + joint="mFaceEyeAltRight" + location="ATTACH_FACE_REYE" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="52" + group="8" + pie_slice="11" + name="Tongue" + joint="mFaceTongueTip" + location="ATTACH_FACE_TONGUE" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="53" + group="8" + pie_slice="12" + name="Groin" + joint="mGroin" + location="ATTACH_GROIN" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="54" + group="8" + pie_slice="13" + name="Left Hind Foot" + joint="mHindLimb4Left" + location="ATTACH_HIND_LFOOT" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <attachment_point + id="55" + group="8" + pie_slice="14" + name="Right Hind Foot" + joint="mHindLimb4Right" + location="ATTACH_HIND_RFOOT" + position="0.000 0.000 0.000" + rotation="0 0 0" + visible_in_first_person="true"/> + + <!-- END BENTO --> + <param id="32" group="1" @@ -460,8 +669,12 @@ scale="0 0 .05" /> <bone - name="mPelvis" - scale="0 0 0" /> + name="mSpine3" + scale="0 0 .05" /> + + <bone + name="mSpine4" + scale="0 0 .05" /> <bone name="mHipLeft" @@ -478,6 +691,29 @@ <bone name="mKneeRight" scale=".05 .05 .1" /> + + <bone + name="mHindLimb1Left" + scale=".05 .05 0" /> + + <bone + name="mHindLimb1Right" + scale=".05 .05 0" /> + + <bone + name="mHindLimb2Left" + scale=".05 .05 .1" /> + + <bone + name="mHindLimb2Right" + scale=".05 .05 .1" /> + + <bone name="mWingsRoot" scale="0 0 0" offset="0 0 0" /> + + <bone name="mWing1Right" scale="0 0 0" offset="-0.05 0 0" /> + + <bone name="mWing1Left" scale="0 0 0" offset="-0.05 0 0" /> + </param_skeleton> </param> @@ -533,8 +769,12 @@ scale="0 0 0.05" /> <bone - name="mPelvis" - scale="0 0 0" /> + name="mSpine3" + scale="0 0 0.05" /> + + <bone + name="mSpine4" + scale="0 0 0.05" /> <bone name="mHipLeft" @@ -551,6 +791,96 @@ <bone name="mKneeRight" scale="0 0 0.1" /> + + <bone + name="mHindLimb1Left" + scale="0 0 0.1" /> + + <bone + name="mHindLimb1Right" + scale="0 0 0.1" /> + + <bone + name="mHindLimb2Left" + scale="0 0 0.1" /> + + <bone + name="mHindLimb2Right" + scale="0 0 0.1" /> + + <bone + name="mWing1Left" + scale="0 0 0" + offset="0 0 0" /> + <bone + name="mWing2Left" + scale="0 0 0" + offset="-0.015 0.015 0" /> + <bone + name="mWing3Left" + scale="0 0 0" + offset="-0.025 0.025 0" /> + <bone + name="mWing4Left" + scale="0 0 0" + offset="-0.03 0.03 0" /> + <bone + name="mWing4FanLeft" + scale="0 0 0" + offset="-0.03 0.03 0" /> + + <bone + name="mWing1Right" + scale="0 0 0" + offset="0 0 0" /> + <bone + name="mWing2Right" + scale="0 0 0" + offset="-0.015 -0.015 0" /> + <bone + name="mWing3Right" + scale="0 0 0" + offset="-0.025 -0.025 0" /> + <bone + name="mWing4Right" + scale="0 0 0" + offset="-0.03 -0.03 0" /> + <bone + name="mWing4FanRight" + scale="0 0 0" + offset="-0.03 -0.03 0" /> + + <bone + name="mTail1" + scale ="0 0 0" + offset="-0.02 0 0" /> + + <bone + name="mTail2" + scale ="0 0 0" + offset="-0.02 0 0" /> + + <bone + name="mTail3" + scale ="0 0 0" + offset="-0.02 0 0" /> + + <bone + name="mTail4" + scale ="0 0 0" + offset="-0.02 0 0" /> + + <bone + name="mTail5" + scale ="0 0 0" + offset="-0.02 0 0" /> + + <bone + name="mTail6" + scale ="0 0 0" + offset="-0.02 0 0" /> + + </param_skeleton> </param> @@ -606,10 +936,26 @@ scale="0.1 0.1 0" /> <bone + name="mSpine3" + scale="0.1 0.1 0" /> + + <bone + name="mSpine4" + scale="0.1 0.1 0" /> + + <bone name="mPelvis" scale="0.1 0.1 0" /> <bone + name="mSpine1" + scale="0.1 0.1 0" /> + + <bone + name="mSpine2" + scale="0.1 0.1 0" /> + + <bone name="mHipLeft" scale="0.13 0.13 0" /> @@ -624,6 +970,37 @@ <bone name="mKneeRight" scale="0.12 0.12 0" /> + + <bone + name="mHindLimbsRoot" + scale="0.1 0.1 0" /> + + <bone + name="mHindLimb1Left" + scale="0.13 0.13 0" /> + + <bone + name="mHindLimb1Right" + scale="0.13 0.13 0" /> + + <bone + name="mHindLimb2Left" + scale="0.12 0.12 0" /> + + <bone + name="mHindLimb2Right" + scale="0.12 0.12 0" /> + + <bone name="mTail1" scale="0.05 0.1 0.1" /> + <bone name="mTail2" scale="0.05 0.1 0.1" /> + <bone name="mTail3" scale="0.05 0.1 0.1" /> + <bone name="mTail4" scale="0.05 0.1 0.1" /> + <bone name="mTail5" scale="0.05 0.1 0.1" /> + <bone name="mTail6" scale="0.05 0.1 0.1" /> + + <bone name="mWing1Right" scale="0.0 0.0 0.0" offset="-0.01 -0.01 0" /> + <bone name="mWing1Left" scale="0.0 0.0 0.0" offset="-0.01 0.01 0" /> + </param_skeleton> </param> @@ -662,6 +1039,17 @@ <bone name="mChest" scale="0.02 0.08 0" /> + + <bone + name="mWing1Right" + scale="0.0 0.0 0.0" + offset="0 -0.02 0" /> + + <bone + name="mWing1Left" + scale="0.0 0.0 0.0" + offset="0 0.02 0" /> + </param_skeleton> </param> @@ -669,7 +1057,7 @@ id="37" group="0" name="Hip Width" - label="Hip Width" + label="Hip Width" wearable="shape" edit_group="shape_legs" edit_group_order="3" @@ -685,6 +1073,14 @@ scale="0 0.1 0" /> <bone + name="mSpine1" + scale="0 0.1 0" /> + + <bone + name="mSpine2" + scale="0 0.1 0" /> + + <bone name="mHipLeft" scale="0 0 0" offset="0 .004 0" /> @@ -693,6 +1089,25 @@ name="mHipRight" scale="0 0 0" offset="0 -.004 0" /> + + <bone + name="mHindLimbsRoot" + scale="0 0.1 0" /> + + <bone + name="mHindLimb1Left" + scale="0 0 0" + offset="0 .004 0" /> + + <bone + name="mHindLimb1Right" + scale="0 0 0" + offset="0 -.004 0" /> + + <bone name="mTail1" scale="0.0 0.05 0" /> + <bone name="mTail2" scale="0.0 0.02 0" /> + <bone name="mTail3" scale="0.0 0.01 0" /> + </param_skeleton> </param> @@ -712,7 +1127,19 @@ <bone name="mPelvis" scale="0 0 0.3" /> - </param_skeleton> + + <bone + name="mHindLimbsRoot" + scale="0 0 0.3" /> + + <bone + name="mSpine1" + scale="0 0 0.3" /> + + <bone + name="mSpine2" + scale="0 0 0.3" /> + </param_skeleton> </param> <param @@ -733,10 +1160,26 @@ scale="0 0 .3" /> <bone + name="mSpine3" + scale="0 0 .3" /> + + <bone + name="mSpine4" + scale="0 0 .3" /> + + <bone name="mPelvis" scale="0 0 .1" /> <bone + name="mSpine1" + scale="0 0 .1" /> + + <bone + name="mSpine2" + scale="0 0 .1" /> + + <bone name="mHipLeft" scale="0 0 -.1" /> @@ -751,6 +1194,26 @@ <bone name="mKneeLeft" scale="0 0 -.05" /> + + <bone + name="mHindLimbsRoot" + scale="0 0 .1" /> + + <bone + name="mHindLimb1Left" + scale="0 0 -.1" /> + + <bone + name="mHindLimb1Right" + scale="0 0 -.1" /> + + <bone + name="mHindLimb2Right" + scale="0 0 -.05" /> + + <bone + name="mHindLimb2Left" + scale="0 0 -.05" /> </param_skeleton> </param> @@ -774,6 +1237,78 @@ name="mEyeRight" scale="0 0 0" offset="0 -.009 0" /> + + <bone + name="mFaceEyeAltLeft" + scale="0 0 0 " + offset="0 .0090 0" /> + + <bone + name="mFaceEyeAltRight" + scale="0 0 0 " + offset="0 -.0090 0" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 0 " + offset="0 .0090 0" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 0 " + offset="0 -.0090 0" /> + + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0 " + offset="0 .0090 0" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0 " + offset="0 -.0090 0" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0 " + offset="0 .0090 0" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0 " + offset="0 -.0090 0" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0 " + offset="0 .0090 0" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0 " + offset="0 -.0090 0" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0 " + offset="0 .005 0" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0 " + offset="0 -.005 0" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0 " + offset="0 .008 0" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0 " + offset="0 -.008 0" /> + </param_skeleton> </param> @@ -797,6 +1332,156 @@ name="mEyeRight" scale="0 0 0" offset="0 0 -.004" /> + + <bone + name="mFaceEyeAltLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyeAltRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceNoseRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceNoseLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEar1Left" + scale="0 0 0" + offset="0 0 .004" /> + <bone + name="mFaceEar1Right" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceLipUpperLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceLipUpperRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceLipLowerLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceLipLowerRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceLipCornerRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceLipCornerLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceCheekLowerLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceCheekLowerRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceCheekUpperLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceCheekUpperRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="0 0 -.004" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="0 0 0.004" /> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0" + offset="0 0 -.004" /> + </param_skeleton> </param> @@ -820,9 +1505,10 @@ name="mEyeRight" scale="0 0 0" offset=".016 0 0" /> + </param_skeleton> </param> - + <param id="768" group="1" @@ -843,6 +1529,80 @@ name="mEyeRight" scale="0 0 0" offset=".005 0 0" /> + + <bone + name="mFaceEyeAltLeft" + scale="0 0 0" + offset=".005 0 0" /> + + <bone + name="mFaceEyeAltRight" + scale="0 0 0" + offset=".005 0 0" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 0 " + offset=".005 0 0" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 0 " + offset=".005 0 0" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0 " + offset=".005 0 0" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0 " + offset=".005 0 0" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0 " + offset=".005 0 0" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0 " + offset=".005 0 0" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0 " + offset=".002 0 0" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0 " + offset=".002 0 0" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0 " + offset=".001 0 0" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0 " + offset=".001 0 0" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0 " + offset=".0013 0 0" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0 " + offset=".0013 0 0" /> + + + + </param_skeleton> </param> @@ -850,7 +1610,7 @@ id="655" group="1" name="Head Size" - label="Head Size" + label="Head Size" wearable="shape" edit_group="shape_head" label_min="Small Head" @@ -859,6 +1619,36 @@ value_min="-.25" value_max=".10"> <param_skeleton> + + <bone + name = "mFaceTeethLower" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceTeethUpper" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceEyecornerInnerLeft" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceEyecornerInnerRight" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceNoseBridge" + scale = "1 1 1" + offset = "0 0 0" /> + + <bone + name = "mFaceNoseBase" + scale = "1 1 1" + offset = "0 0 0" /> <bone name="mSkull" scale="1 1 1" @@ -870,6 +1660,11 @@ offset="0 0 0" /> <bone + name="mFaceRoot" + scale="1 1 1" + offset="0 0 0" /> + + <bone name="mEyeLeft" scale="1 1 1" offset="0 0 0" /> @@ -878,6 +1673,181 @@ name="mEyeRight" scale="1 1 1" offset="0 0 0" /> + + <bone + name="mFaceEyeAltLeft" + scale="1 1 1" + offset="0 0 -0.001" /> + + <bone + name="mFaceEyeAltRight" + scale="1 1 1" + offset="0 0 -0.001" /> + + <bone + name="mFaceForeheadLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceForeheadCenter" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceForeheadRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceNoseLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceNoseCenter" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceNoseRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceCheekLowerLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceCheekUpperLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceCheekLowerRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceCheekUpperRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceTongueBase" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceTongueTip" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceJaw" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceJawShaper" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceChin" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceLipUpperLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceLipUpperCenter" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceLipUpperRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceLipCornerLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceLipCornerRight" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceLipLowerLeft" + scale="1 1 1" + offset="0 0 0" /> + + <bone + name="mFaceLipLowerCenter" + scale="1 1 1" + offset="0 0 0" /> + <bone + name="mFaceLipLowerRight" + scale="1 1 1" + offset="0 0 0" /> + </param_skeleton> </param> @@ -901,6 +1871,17 @@ name="mFootLeft" scale="0 0 0" offset="0 0 -.08" /> + + <bone + name="mHindLimb4Left" + scale="0 0 0" + offset="0 0 -.08" /> + + <bone + name="mHindLimb4Right" + scale="0 0 0" + offset="0 0 -.08" /> + </param_skeleton> </param> @@ -924,6 +1905,17 @@ name="mFootLeft" scale="0 0 0" offset="0 0 -.07" /> + + <bone + name="mHindLimb4Left" + scale="0 0 0" + offset="0 0 -.07" /> + + <bone + name="mHindLimb4Right" + scale="0 0 0" + offset="0 0 -.07" /> + </param_skeleton> </param> @@ -951,6 +1943,47 @@ name="mWristLeft" scale="1 1 1" offset="0 0 0" /> + + <bone name = "mHandThumb1Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandThumb2Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandThumb3Right" scale = "1 1 1" offset = "0 0 0" /> + + <bone name = "mHandIndex1Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandIndex2Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandIndex3Right" scale = "1 1 1" offset = "0 0 0" /> + + <bone name = "mHandMiddle1Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandMiddle2Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandMiddle3Right" scale = "1 1 1" offset = "0 0 0" /> + + <bone name = "mHandRing1Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandRing2Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandRing3Right" scale = "1 1 1" offset = "0 0 0" /> + + <bone name = "mHandPinky1Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandPinky2Right" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandPinky3Right" scale = "1 1 1" offset = "0 0 0" /> + + <bone name = "mHandThumb1Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandThumb2Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandThumb3Left" scale = "1 1 1" offset = "0 0 0" /> + + <bone name = "mHandIndex1Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandIndex2Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandIndex3Left" scale = "1 1 1" offset = "0 0 0" /> + + <bone name = "mHandMiddle1Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandMiddle2Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandMiddle3Left" scale = "1 1 1" offset = "0 0 0" /> + + <bone name = "mHandRing1Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandRing2Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandRing3Left" scale = "1 1 1" offset = "0 0 0" /> + + <bone name = "mHandPinky1Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandPinky2Left" scale = "1 1 1" offset = "0 0 0" /> + <bone name = "mHandPinky3Left" scale = "1 1 1" offset = "0 0 0" /> + </param_skeleton> </param> @@ -988,6 +2021,7 @@ value_min="-1" value_max="1"> <param_skeleton> + <bone name="mEyeLeft" scale="0 0 0" @@ -997,6 +2031,48 @@ name="mEyeRight" scale="0 0 0" offset="-.005 0 0" /> + + +<bone + name="mFaceEyeAltLeft" + scale="0 0 0" + offset="-.005 0 0" /> + + <bone + name="mFaceEyeAltRight" + scale="0 0 0" + offset="-.005 0 0" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0.3 0.7" + offset=" 0 0 0" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0.3 0.7" + offset="0 0 0" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0.3 0.7" + offset=" 0 0 0" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0.3 0.7" + offset=" 0 0 0" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="-0.005 -0.008 0.0" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="-0.005 0.008 0.0" /> + </param_skeleton> </param> @@ -1028,6 +2104,22 @@ <bone name="mKneeLeft" scale="0 0 .2" /> + + <bone + name="mHindLimb1Left" + scale="0 0 .2" /> + + <bone + name="mHindLimb1Right" + scale="0 0 .2" /> + + <bone + name="mHindLimb2Right" + scale="0 0 .2" /> + + <bone + name="mHindLimb2Left" + scale="0 0 .2" /> </param_skeleton> </param> @@ -1084,7 +2176,8 @@ scale="0 0 .5" /> </param_skeleton> </param> - <param + + <param id="11001" group="0" name="Hover" @@ -1099,12 +2192,2265 @@ camera_distance="2.5"> <param_skeleton /> </param> + + <param + id="30002" + group="1" + name="Nose_Big_Out" + value_min="-0.8" + value_max="2.5"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + offset = "0.0 0.0 0.0" + scale = "0.50 0.3 0.1" /> + <bone + name = "mFaceNoseLeft" + offset = "0 0 0" + scale = "0.0 0.3 0.0" /> + <bone + name = "mFaceNoseRight" + offset = "0 0 0" + scale = "0.0 0.3 0.0" /> + <bone + name = "mFaceNoseBridge" + offset = "0.006 0.0 0.0" + scale = "0.10 0.1 0.0" /> + + </param_skeleton> + </param> + + <param + id="30004" + group="1" + name="Broad_Nostrils" + value_min="-.5" + value_max="1"> + <param_skeleton> + <bone + name = "mFaceNoseLeft" + offset = "0 0.005 0" + scale = "0.0 0.0 0.0" /> + <bone + name = "mFaceNoseRight" + offset = "0 -0.005 0" + scale = "0.0 0.0 0.0" /> + </param_skeleton> + </param> + + <param + id="30020" + group="1" + name="Bulbous_Nose" + value_min="-.5" + value_max="1.5" + > + <param_skeleton> + <bone + name = "mFaceNoseCenter" + offset = "0.0 0.0 0.0" + scale = "0.2 0.4 0.2" /> + <bone + name = "mFaceNoseLeft" + scale = "0 0.3 0" + offset = "0 0.0015 0" + /> + <bone + name = "mFaceNoseRight" + scale = "0 0.3 0" + offset = "0 -0.0015 0" + /> + + </param_skeleton> + </param> + + <param + id="30517" + group="1" + name="Wide_Nose" + value_min="-.5" + value_max="1"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + offset = "0 0 0" + scale = "0.10 0.85 0.0" /> + <bone + name = "mFaceNoseLeft" + scale = "0 0 0" + offset = "0.001 0.013 0"/> + <bone + name = "mFaceNoseRight" + scale = "0 0 0" + offset = "0.001 -0.013 0" /> + </param_skeleton> + </param> + + <param + id="30656" + group="1" + name="Crooked_Nose" + value_min="-2" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 0.009 0.0" /> + + <bone + name = "mFaceNoseBase" + scale = "0.0 0.00 0.0" + offset = "0.0 0.007 0.0" /> + + <bone + name = "mFaceNoseLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.005 0.0"/> + + <bone + name = "mFaceNoseRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.005 0.0" /> + + <bone + name = "mFaceLipCornerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.001 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.002 0.0" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.002 0.0" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.001 0.0" /> + + <bone + name = "mFaceEyebrowInnerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.0008 0.0" /> + + <bone + name = "mFaceEyebrowInnerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.0008 0.0" /> + + <bone + name = "mFaceNoseBridge" + scale = "0.0 0.00 0.0" + offset = "0.0 0.004 0.0" /> + + <bone + name = "mFaceTeethUpper" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceEyecornerInnerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.001 0.0" /> + + <bone + name = "mFaceEyecornerInnerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.001 0.0" /> + + </param_skeleton> + </param> + + <param + id="30155" + group="1" + name="Lip Width" + value_min="-0.9" + value_max="1.3" + value_default="0"> + <param_skeleton> + <bone + name = "mFaceLipCornerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.005 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.005 0.0" /> + + </param_skeleton> + </param> + + <param + id="30653" + group="1" + name="Tall_Lips" + value_min="-1" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceLipCornerLeft" + scale = "0.2 0.00 0.2" + offset = "-0.008 0.00 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.2 0.00 0.2" + offset = "-0.009 0.00 0.0025" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.2 0.00 0.2" + offset = "-0.009 0.00 0.0025" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.2 0.00 0.2" + offset = "-0.009 0.00 0.0025" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.2 0.00 0.2" + offset = "-0.008 0.00 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.2 0.00 0.2" + offset = "-0.008 0.00 -0.0015" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0.2 0.00 0.2" + offset = "-0.008 0.00 -0.0025" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.2 0.00 0.2" + offset = "-0.008 0.00 -0.0015" /> + + </param_skeleton> + </param> + + <param + id="30505" + group="1" + name="Lip_Thickness" + value_min="0" + value_max="0.7"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.2 0.00 -0.6" + offset = "-0.012 0.00 -0.005" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.2 0.00 -0.6" + offset = "-0.015 0.00 -0.005" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.2 0.00 -0.6" + offset = "-0.012 0.00 -0.005" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.008" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.008" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.2 0.00 -0.6" + offset = "-0.01 0.00 0.008" /> + + </param_skeleton> + </param> + + <param + id="31505" + group="1" + name="Lip_Thickness" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0.2 0.00 0.1" + offset = "0.005 0.00 0.0" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0.2 0.00 0.4" + offset = "0.004 0.00 0.004" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0.2 0.00 0.4" + offset = "0.004 0.00 0.004" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0.2 0.00 0.4" + offset = "0.004 0.00 0.004" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.2 0.00 0.1" + offset = "0.005 0.00 0.0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0.2 0.00 0.3" + offset = "0.006 0.00 -0.003" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0.2 0.00 0.3" + offset = "0.006 0.00 -0.003" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0.2 0.00 0.3" + offset = "0.006 0.00 -0.003" /> + + </param_skeleton> + </param> + + <param + id="30797" + group="1" + name="Fat_Upper_Lip" + value_min="0" + value_max="1.5"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "-0.002 0.00 0.001" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0 0 0" + offset = "-0.002 0.00 0.001" /> + + <bone + name = "mFaceLipUpperLeft" + scale = " 0.1 0 0.6" + offset = "-0.004 0.00 0.006" /> + + <bone + name = "mFaceLipUpperCenter" + scale = " 0.1 0 0.4" + offset = "-0.004 0.00 0.003" /> + + <bone + name = "mFaceLipUpperRight" + scale = " 0.1 0 0.6" + offset = "-0.004 0.00 0.006" /> + + <bone + name = "mFaceLipLowerLeft" + scale = " 0 0 0" + offset = "-0.002 0.00 0.001" /> + + <bone + name = "mFaceLipLowerCenter" + scale = " 0 0 0" + offset = "-0.002 0.00 0.001" /> + + <bone + name = "mFaceLipLowerRight" + scale = " 0 0 0" + offset = "-0.002 0.00 0.001" /> + + </param_skeleton> + </param> + + <param + id="30798" + group="1" + name="Fat_Lower_Lip" + value_min="0" + value_max="1.5"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "-0.002 0.00 -0.002" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0 0 0" + offset = "-0.002 0.00 -0.002" /> + + <bone + name = "mFaceLipUpperLeft" + scale = " 0 0 0" + offset = "-0.002 0.00 -0.003" /> + + <bone + name = "mFaceLipUpperCenter" + scale = " 0 0 0" + offset = "-0.002 0.00 -0.003" /> + + <bone + name = "mFaceLipUpperRight" + scale = " 0 0 0" + offset = "-0.002 0.00 -0.003" /> + + <bone + name = "mFaceLipLowerLeft" + scale = " 0.1 0 0.25" + offset = "-0.005 0.00 -0.004" /> + + <bone + name = "mFaceLipLowerCenter" + scale = " 0.1 0 0.25" + offset = "-0.005 0.00 -0.004" /> + + <bone + name = "mFaceLipLowerRight" + scale = " 0.1 0 0.25" + offset = "-0.005 0.00 -0.004" /> + + </param_skeleton> + </param> + + <param + id="30506" + group="1" + name="Mouth_Height" + value_min="-2" + value_max="2"> + <param_skeleton> + + <bone + name = "mFaceTeethUpper" + scale = "0.0 0.00 0.0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceTeethLower" + scale = "0.0 0.00 0.0" + offset = "0 0 -0.006" /> + + <bone + name = "mFaceNoseBase" + scale = "0.0 0.00 0.0" + offset = "0 0 -0.001" /> + + </param_skeleton> + </param> + + <param + id="30658" + group="1" + name="Frown_Mouth" + value_min="0" + value_max="1.4"> + <param_skeleton> + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "0 0 -0.005" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0 0 0" + offset = "0 0 -0.005" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0 0 0" + offset = "0 0 0" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0 0 0" + offset = "0 0 0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0 0 0" + offset = "0 0 0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0 0 0" + offset = "0 0 0.001" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0 0 0" + offset = "0 0 0.002" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0 0 0" + offset = "0 0 0.001" /> + </param_skeleton> + </param> + + <param + id="30657" + group="1" + name="Smile_Mouth" + value_min="0" + value_max="1.4"> + <param_skeleton> + + <bone + name = "mFaceLipCornerLeft" + scale = "0 0 0" + offset = "0 0.005 0.002" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0 0 0" + offset = "0 -0.005 0.002" /> + + <bone + name = "mFaceLipUpperLeft" + scale = "0 0 0" + offset = "0 0.002 0" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0 0 0" + offset = "0 0 -0.0005" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0 0 0" + offset = "0 -0.002 0" /> + + <bone + name = "mFaceLipLowerLeft" + scale = "0 0 0" + offset = "0 0.001 0" /> + + <bone + name = "mFaceLipLowerCenter" + scale = "0 0 0" + offset = "0 0 -0.001" /> + + <bone + name = "mFaceLipLowerRight" + scale = "0 0 0" + offset = "0 -0.001 0" /> + + </param_skeleton> + </param> + +<param + id="30764" + group="1" + name="Lip_Cleft_Deep" + value_min="-1" + value_max="1.2"> + <param_skeleton> + + <bone + name = "mFaceLipUpperLeft" + scale = "0 0 0.3" + offset = "0 0 0.003" /> + + <bone + name = "mFaceLipUpperCenter" + scale = "0 0 -0.1" + offset = "0 0 -0.001" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0 0 0.3" + offset = "0 0 0.003" /> + + </param_skeleton> + </param> + +<param + id="30025" + group="1" + name="Wide_Lip_Cleft" + value_min="-.8" + value_max="1.5"> + <param_skeleton> + + <bone + name = "mFaceLipUpperLeft" + scale = "0 0.1 0" + offset = "0 0.0 0" /> + + <bone + name = "mFaceLipUpperRight" + scale = "0 0.1 0" + offset = "0 0.0 0" /> + + <bone + name = "mFaceLipCornerRight" + scale = "0.0 0 0" + offset = "0 0.001 0" /> + + <bone + name = "mFaceLipCornerLeft" + scale = "0.0 0 0" + offset = "0 -0.001 0" /> + + </param_skeleton> + </param> + + <param + id="31663" + group="1" + name="Shift_Mouth" + value_min="0" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0" /> + + <bone + name = "mFaceNoseBase" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.004 0.0" /> + + <bone + name = "mFaceNoseLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0"/> + + <bone + name = "mFaceNoseRight" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.003 0.0" /> + + <bone + name = "mFaceTeethUpper" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.006 0.0" /> + + <bone + name = "mFaceTeethLower" + scale = "0.0 0.00 0.0" + offset = "0.0 -0.006 0.0" /> + + + + </param_skeleton> + </param> + + <param + id="32663" + group="1" + name="Shift_Mouth" + value_min="0" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceNoseBase" + scale = "0.0 0.00 0.0" + offset = "0.0 0.004 0.0" /> + + <bone + name = "mFaceNoseLeft" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0"/> + + <bone + name = "mFaceNoseRight" + scale = "0.0 0.00 0.0" + offset = "0.0 0.003 0.0" /> + + <bone + name = "mFaceTeethUpper" + scale = "0.0 0.00 0.0" + offset = "0.0 0.006 0.0" /> + + <bone + name = "mFaceTeethLower" + scale = "0.0 0.00 0.0" + offset = "0.0 0.006 0.0" /> + + + </param_skeleton> + </param> + + <param + id="30035" + group="1" + name="Big_Ears" + value_min="-1" + value_max="2"> + <param_skeleton> + <bone + name = "mFaceEar1Left" + scale = "0.55 0.55 0.55" + offset = "0.0 -0.002 0.001" /> + <bone + name = "mFaceEar1Right" + scale = "0.55 0.55 0.55" + offset = "0.0 0.002 0.001" /> + </param_skeleton> + </param> + + <param + id="30015" + group="1" + name="Ears_Out" + value_min="-.5" + value_max="1.5"> + <param_skeleton> + <!-- Place Holder. Can't do this unless we get rotation offset --> + <bone + name = "mFaceEar1Left" + offset = "0.0 -0.0 0.0" + scale = "0.0 0.0 0.0" /> + <bone + name = "mFaceEar1Right" + offset = "0.0 0.0 0.0" + scale = "0.0 0.0 0.0" /> + </param_skeleton> + </param> + + <param + id="30796" + group="1" + name="Pointy_Ears" + value_min="-.4" + value_max="3"> + <param_skeleton> + <bone + name = "mFaceEar2Left" + offset = "-0.0149 0.001 0.016" + scale = "0.0 0.0 0.0" /> + <bone + name = "mFaceEar2Right" + offset = "-0.0149 -0.001 0.016" + scale = "0.0 0.0 0.0" /> + </param_skeleton> + </param> + + <param + id="30185" + group="1" + name="Deep_Chin" + value_min="-1" + value_max="1"> + <!-- used for the chin depth slider --> + <param_skeleton> + <bone + name = "mFaceChin" + offset = "0.0 0.00 -0.025" + scale = "0.0 0.0 0.0" /> + </param_skeleton> + </param> + <param + id="40185" + group="1" + name="Deep_Chin" + value_min="-1" + value_max="1"> + <!-- used for the head shape slider --> + <param_skeleton> + <bone + name = "mFaceChin" + offset = "0.0 0.00 -0.02" + scale = "0.0 0.0 0.0" /> + </param_skeleton> + </param> + + <param + id="30760" + group="1" + name="Jaw_Angle" + value_min="-1.2" + value_max="2" + value_default="0"> + <param_skeleton> + <bone + name = "mFaceJawShaper" + offset = "0.0 0.00 0.03" + scale = "0.0 0.0 0.0" /> + </param_skeleton> + </param> + + + <param + id="30665" + group="1" + name="Jaw_Jut" + value_min="-2" + value_max="2"> + <param_skeleton> + + <bone + name = "mFaceTeethLower" + offset = "0.008 0 0" + scale = "0.0 0.0 0.0" /> + + <bone + name = "mFaceChin" + offset = "0.008 0.00 0" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + <param + id="30006" + group="1" + name="Bulbous_Nose_Tip" + value_min="-1" + value_max="1.5"> + <param_skeleton> + <bone + name = "mFaceNoseCenter" + offset = "0.0 0.00 0.0" + scale = "0.1 0.1 0.1" /> + + </param_skeleton> + </param> + + <param + id="30007" + group="1" + name="Weak_Chin" + value_min="-.5" + value_max=".5"> + <param_skeleton> + <bone + name = "mFaceChin" + offset = "-0.06 0.00 0.01" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + <param + id="40007" + group="1" + name="Weak_Chin" + value_min="-.5" + value_max=".5"> + <param_skeleton> + <bone + name = "mFaceChin" + offset = "-0.025 0.00 0.005" + scale = "0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + <param + id="30008" + group="1" + name="Double_Chin" + value_min="-.5" + value_max="1.5"> + <param_skeleton> + <bone + name = "mFaceJawShaper" + offset = "0 0 0" + scale = "0.0 0.125 0.5" /> + </param_skeleton> + </param> + + + <param + id="30024" + group="1" + name="Wide_Eyes" + value_min="-1.5" + value_max="2"> + <param_skeleton> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0.1 0.2" + offset=" 0 0 0" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0.1 0.2" + offset=" 0 0 0" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0.1 0.2" + offset=" 0 0 0" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0.1 0.2" + offset=" 0 0 0" /> + + <bone + name="mFaceEyeAltLeft" + scale="0 0 0" + offset="0 0 0" /> + + <bone + name="mFaceEyeAltRight" + scale="0 0 0" + offset="0 0 0" /> + + </param_skeleton> + </param> + + <param + id="30650" + group="1" + name="Eyelid_Corner_Up" + value_min="-1.3" + value_max="1.2"> + <param_skeleton> + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0" + offset="0 0 .004" /> + </param_skeleton> + </param> + + <param + id="30880" + group="1" + name="Eyelid_Inner_Corner_Up" + value_min="-1.3" + value_max="1.2"> + <param_skeleton> + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="0 0 .004" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="0 0 .004" /> + </param_skeleton> + </param> + + <param + id="30765" + group="1" + name="Puffy_Lower_Lids" + value_min="-.3" + value_max="2.5"> + <param_skeleton> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0.05 0.05 0.05" + offset="0 0 0" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0.05 0.05 0.05" + offset="0 0 0" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0.05 0.05 0.05" + offset="0 0 0" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0.05 0.05 0.05" + offset="0 0 0" /> + + </param_skeleton> + </param> + + <param + id="31629" + group="1" + name="Forehead Angle" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0.08" + offset="0.02 0 0" /> + + <bone + name="mFaceForeheadCenter" + scale="0.01 0 0.08" + offset="0.002 0 0" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0.08" + offset="0.02 0 0" /> + + </param_skeleton> + </param> + + <param + id="41629" + group="1" + name="Forehead Angle" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0.08" + offset="0.02 0 0" /> + + <bone + name="mFaceForeheadCenter" + scale="0.01 0 0.08" + offset="0.002 0 0" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0.08" + offset="0.02 0 0" /> + + </param_skeleton> + </param> + + <param + id="30647" + group="1" + name="Squash_Stretch_Head" + value_min="-0.5" + value_max="1" + value_default="0"> + <param_skeleton> + + <bone + name="mFaceRoot" + scale="0 -0.1 0.1" + offset="0 0 0" /> + + <bone + name="mFaceChin" + scale="0 -0.1 0.5" + offset="0 0 -0.005" /> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="0 0 -0.006" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0" + offset="0 -0.0053 -0.0047" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0" + offset="0 -0.0045 -0.0053" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0" + offset="0 -0.00225 -0.0048" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0" + offset="0 0.0053 -0.0047" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0" + offset="0 0.0045 -0.0053" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0" + offset="0 0.00225 -0.0048" /> + + <bone + name="mFaceEyeAltRight" + scale="0 0 0" + offset="0 -0.0042 -0.0035" /> + + <bone + name="mFaceEyeAltLeft" + scale="0 0 0" + offset="0 0.0042 -0.0035" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0" + offset="0 -0.0039 -0.0032" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="0 0.0039 -0.0032" /> + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 0" + offset="0 -0.0039 -0.0032" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 0" + offset="0 0.0039 -0.0032" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="0 -0.00225 -0.0032" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="0 0.00225 -0.0032" /> + + <bone + name="mFaceNoseBridge" + scale="0 0 0" + offset="0 0 -0.002" /> + + <bone + name="mFaceNoseRight" + scale="0 0 0" + offset="0 -0.002 0" /> + + <bone + name="mFaceNoseLeft" + scale="0 0 0" + offset="0 0.002 0" /> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset="0 0 0.002" /> + + <bone + name="mFaceCheekUpperRight" + scale="0 0 0" + offset="0 -0.003 0" /> + + <bone + name="mFaceCheekUpperLeft" + scale="0 0 0" + offset="0 0.003 0" /> + + <bone + name="mFaceCheekLowerRight" + scale="0 0 0" + offset="0 -0.003 0.0032" /> + + <bone + name="mFaceCheekLowerLeft" + scale="0 0 0" + offset="0 0.003 0.0032" /> + + <bone + name="mFaceTeethUpper" + scale="0 0 0" + offset="0 0 0.0032" /> + <bone + name="mFaceTeethLower" + scale="0 0 0" + offset="0 0 0.0016" /> + + </param_skeleton> + </param> + + <param + id="32629" + group="1" + name="Forehead Angle" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="-0.001 0 0.001" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0" + offset="0 0 0.002" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0" + offset="0 0 0.002" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0" + offset="0 0 0.003" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0" + offset="0 0 0.003" /> + + </param_skeleton> + </param> + + <param + id="42629" + group="1" + name="Forehead Angle" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="-0.001 0 0.001" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0" + offset="0 0 0.002" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0" + offset="0 0 0.002" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0" + offset="0 0 0.003" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0" + offset="0 0 0.003" /> + + </param_skeleton> + </param> + + <param + id="30001" + group="1" + name="Big_Brow" + value_min="-.3" + value_max="2"> + <param_skeleton> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="0.007 0 0.001" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0.1 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0.1 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0.1 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0.1 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0" + offset="0.004 0 0" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0" + offset="0.004 0 0" /> + + </param_skeleton> + </param> + + <param + id="30011" + group="1" + name="Noble_Nose_Bridge" + value_min="-.5" + value_max="1.5"> + <param_skeleton> + + <bone + name="mFaceNoseBridge" + scale="0.15 0.01 0.7" + offset="0.009 0 -0.006" /> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="0.001 0 0" /> + + </param_skeleton> + </param> + + <param + id="30758" + group="1" + name="Lower_Bridge_Nose" + value_min="-1.5" + value_max="1.5"> + <param_skeleton> + + <bone + name="mFaceNoseBridge" + scale="0 0 0.2" + offset="0.0025 0 -0.001" /> + + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset="0.004 0 0.001" /> + + </param_skeleton> + </param> + + <param + id="30027" + group="1" + name="Wide_Nose_Bridge" + value_min="-1.3" + value_max="1.2"> + <param_skeleton> + + <bone + name="mFaceNoseBridge" + scale="0 0.4 0" + offset="0 0 0" /> + + </param_skeleton> + </param> + + <param + id="30759" + group="1" + name="Low_Septum_Nose" + value_min="-1" + value_max="1.5" + value_default="0.5"> + <param_skeleton> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset="0 0 -0.004" /> + + </param_skeleton> + + </param> + + + <param + id="30010" + group="1" + name="Sunken_Cheeks" + value_min="-1.5" + value_max="3"> + <param_skeleton> + + <bone + name="mFaceCheekLowerLeft" + scale="0 -0.12 0" + offset="0.0 0.0 0" /> + <bone + name="mFaceCheekLowerRight" + scale="0 -0.12 0" + offset="0 0 0" /> + + </param_skeleton> + </param> + + <param + id="30017" + group="1" + name="Square_Jaw" + value_min="-0.5" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceChin" + scale="0.0 0.5 0.0" + offset="0.0 0.0 0.0" /> + + </param_skeleton> + </param> + + <param + id="40017" + group="1" + name="Square_Jaw" + value_min="-0.5" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceJaw" + scale="0.0 0.5 0.0" + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceJawShaper" + scale="0.0 0.5 0.0" + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceLipLowerRight" + scale="0.0 0.0 0.0" + offset="0.0 0.0038 0.0" /> + + <bone + name="mFaceLipLowerLeft" + scale="0.0 0.0 0.0" + offset="0.0 -0.0038 0.0" /> + + </param_skeleton> + </param> + + + <param + id="30018" + group="1" + name="Puffy_Upper_Cheeks" + value_min="-1.5" + value_max="2.5"> + <param_skeleton> + + <bone + name="mFaceCheekUpperLeft" + scale="0.15 0.1 0.1" + offset="0.002 0 0.0015" /> + + <bone + name="mFaceCheekUpperRight" + scale="0.15 0.1 0.1" + offset="0.002 0 0.0015" /> + + </param_skeleton> + </param> + + <param + id="30021" + group="1" + name="Upper_Eyelid_Fold" + value_min="-0.2" + value_max="1.3"> + <param_skeleton> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="0 0 -.006" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0" + offset="0 0 -.006" /> + + </param_skeleton> + </param> + + <param + id="30023" + group="1" + name="Baggy_Eyes" + value_min="-.5" + value_max="1.5"> + <param_skeleton> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 .5" + offset="0 0 -.001" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 .5" + offset="0 0 -.001" /> + + </param_skeleton> + </param> + + <param + id="30014" + group="1" + name="High_Cheek_Bones" + value_min="-.5" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceCheekUpperLeft" + scale="0 0 0" + offset="0 0 0.02" /> + + <bone + name="mFaceCheekUpperRight" + scale="0 0 0" + offset="0 0 0.02" /> + + </param_skeleton> + </param> + + <param + id="30019" + group="1" + name="Upturned_Nose_Tip" + value_min="-1.5" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset="0.001 0 -0.0015" /> + + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset="-0.002 0 0.004" /> + + <bone + name="mFaceNoseRight" + scale="0 0 0" + offset="0.001 0 -0.002" /> + + <bone + name="mFaceNoseLeft" + scale="0 0 0" + offset="0.001 0 -0.002" /> + + </param_skeleton> + </param> + + <param + id="30879" + group="1" + sex="male" + name="Male_Package" + value_min="-.5" + value_max="2"> + <param_skeleton> + + <bone + name = "mGroin" + offset = "0.0 0.0 0.0" + scale = ".5 .25 .1" /> + + </param_skeleton> + </param> + + <param + id="30193" + group="1" + name="Square_Head" + value_min="-1" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceChin" + scale="0.0 -0.2 0.0" + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceRoot" + scale="0.0 0 0.0" + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceCheekLowerRight" + scale="0.0 -0.2 0.0" + offset="0.0 0 0.0" /> + + <bone + name="mFaceCheekLowerLeft" + scale="0.0 -0.2 0.0" + offset="0.0 0 0.0" /> + + <bone + name="mFaceForeheadRight" + scale="0.0 -1.0 0.0" + offset="0.0 0.01 -0.01" /> + + <bone + name="mFaceForeheadLeft" + scale="0.0 -1.0 0.0" + offset="0.0 -0.01 -0.01" /> + + <bone + name="mFaceJawShaper" + scale="0.0 -0.3 0.0" + offset="0.0 0 0" /> + + </param_skeleton> + </param> + + <param + id="30646" + group="1" + name="Egg_Head" + value_min="-1.3" + value_max="1" + value_default="0"> + <param_skeleton> + + <bone + name="mFaceRoot" + scale="0 -0.07 0.07" + offset="0 0 -0.005" /> + + <bone + name="mFaceForeheadLeft" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name="mFaceForeheadCenter" + scale="0 0 0" + offset="-0.001 0 0.001" /> + + <bone + name="mFaceForeheadRight" + scale="0 0 0.2" + offset="-0.01 0 -0.01" /> + + <bone + name = "mFaceChin" + offset = "0.015 0.00 0.005" + scale = "0.0 0.0 0.0" /> + + <bone + name="mFaceEyeAltRight" + scale="0 0 0" + offset="0 -0.0033 0.0025" /> + + <bone + name="mFaceEyeAltLeft" + scale="0 0 0" + offset="0 0.0033 0.0025" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 0" + offset="0 -0.0033 0.0025" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0" + offset="0 -0.0033 0.002" /> + + <bone + name="mFaceEyecornerInnerRight" + scale="0 0 0" + offset="0 -0.0017 0.0025" /> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0" + offset="0 -0.004 0.0014" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0" + offset="0 -0.00377 0.00061" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0" + offset="0 -0.00225 0.001" /> + + + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 0" + offset="0 0.0033 0.0025" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="0 0.0033 0.002" /> + + <bone + name="mFaceEyecornerInnerLeft" + scale="0 0 0" + offset="0 0.0017 0.0025" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0" + offset="0 0.004 0.0014" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0" + offset="0 0.00377 0.00061" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0" + offset="0 0.00225 0.001" /> + + <bone + name="mFaceLipLowerRight" + scale="0 0 0" + offset="0 0 0" /> + <bone + name="mFaceLipLowerCenter" + scale="0 0 0" + offset="0 0 0" /> + <bone + name="mFaceLipLowerLeft" + scale="0 0 0" + offset="0 0 0" /> + + <bone + name="mFaceTeethUpper" + scale="0 0 0" + offset="0 0 0.0075" /> + + <bone + name="mFaceTeethLower" + scale="0 0 0" + offset="0 0 0.0061" /> + + <bone + name="mFaceTongueBase" + scale="0 0 0" + offset="0 0 -0.00" /> + + <bone + name="mFaceCheekLowerRight" + scale="0 0 0" + offset="0 0 0.0085" /> + + <bone + name="mFaceCheekLowerLeft" + scale="0 0 0" + offset="0 0 0.0085" /> + + <bone + name="mFaceCheekUpperRight" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceCheekUpperLeft" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseRight" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseLeft" + scale="0 0 0" + offset="0 0 0.005" /> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset="0 0 0.006" /> + + <bone + name="mFaceJawShaper" + scale="0 0.2 0" + offset="0 0 0" /> + + </param_skeleton> + </param> + + <param + id="30689" + group="1" + name="EyeBone_Big_Eyes" + value_min="-1.1" + value_max="1.1"> + <param_skeleton> + + <!-- Experimental: Added Scale to the System eyes. From first look this affects only custom meshes. + | The result is: Custom eyes now scale in the same way as system eyes do + | Revert by setting scale to scale="0 0 0" for mEyeLeft and mEyeRight + --> + <bone + name="mEyeLeft" + scale="0.248 0.25 0.25" + offset="0 0 0" /> + + <bone + name="mEyeRight" + scale="0.248 0.25 0.25" + offset="0 0 0" /> + + <bone + name="mFaceEyeAltLeft" + scale="0.248 0.25 0.25" + offset="0 0 0" /> + + <bone + name="mFaceEyeAltRight" + scale="0.248 0.25 0.25" + offset="0 0 0" /> + + </param_skeleton> + </param> + + <param + id="30772" + group="1" + name="EyeBone_Head_Elongate" + value_min="-1" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceRoot" + scale="0.25 0 0" + offset="0 0 0" /> + + <bone + name="mFaceEyeLidUpperLeft" + scale="0 0 0" + offset="-0.0038 0 0" /> + + <bone + name="mFaceEyeLidUpperRight" + scale="0 0 0" + offset="-0.0038 0 0" /> + + <bone + name="mFaceEyeLidLowerLeft" + scale="0 0 0" + offset="-0.0038 0 0" /> + + <bone + name="mFaceEyeLidLowerRight" + scale="0 0 0" + offset="-0.0038 0 0" /> + + <bone + name="mFaceNoseCenter" + scale="0 0 0" + offset=".01 0 0" /> + + <bone + name="mFaceNoseRight" + scale="0 0 0" + offset=".005 0 0" /> + + <bone + name="mFaceNoseLeft" + scale="0 0 0" + offset=".005 0 0" /> + + <bone + name="mFaceNoseBase" + scale="0 0 0" + offset=".005 0 0" /> + + <bone + name="mFaceLipUpperLeft" + scale="0 0 0" + offset="0.005 0 0" /> + + <bone + name="mFaceLipUpperCenter" + scale="0 0 0" + offset="0.005 0 0" /> + + <bone + name="mFaceLipUpperRight" + scale="0 0 0" + offset="0.005 0 0" /> + + <bone + name="mFaceLipCornerRight" + scale="0 0 0" + offset="0.005 0 0" /> + + <bone + name="mFaceLipCornerLeft" + scale="0 0 0" + offset="0.005 0 0" /> + + <bone + name="mFaceLipLowerLeft" + scale="0 0 0" + offset="0.01 0 0" /> + + <bone + name="mFaceLipLowerCenter" + scale="0 0 0" + offset="0.01 0 0" /> + + <bone + name="mFaceLipLowerRight" + scale="0 0 0" + offset="0.01 0 0" /> + + + <bone + name="mFaceCheekLowerLeft" + scale="0 0 0" + offset="0.007 0 0" /> + + <bone + name="mFaceCheekLowerRight" + scale="0 0 0" + offset="0.007 0 0" /> + + <bone + name="mFaceChin" + scale="0 0 0" + offset="0.014 0 0" /> + + <bone + name="mFaceTeethUpper" + scale="0.28 0 0" + offset="0 0 0" /> + <bone + name="mFaceTeethLower" + scale="0.28 0 0" + offset="0 0 0" /> + + <bone + name="mFaceTongueBase" + scale="0.3 0 0" + offset="0 0 0" /> + + <bone + name="mFaceTongueTip" + scale="0 0 0" + offset="0.004 0 0" /> + + </param_skeleton> + </param> + + <param + id="31772" + group="1" + name="EyeBone_Head_Elongate" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceEyeAltLeft" + scale="0 0 0" + offset="0.0058 0 0" /> + + <bone + name="mFaceEyeAltRight" + scale="0 0 0" + offset="0.0058 0 0" /> + + </param_skeleton> + </param> + + <param + id="32772" + group="1" + name="EyeBone_Head_Elongate" + value_min="0" + value_max="1"> + <param_skeleton> + + <bone + name="mFaceEyeAltLeft" + scale="0 0 0" + offset="-0.0032 0 0" /> + + <bone + name="mFaceEyeAltRight" + scale="0 0 0" + offset="-0.0032 0 0" /> + + </param_skeleton> + </param> + + + <!-- Eye Brow sliders --> + + <param + id="30119" + group="1" + name="Eyebrow Size" + value_min="0" + value_max="1" + value_default="0.5"> + + <param_skeleton> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0.5" + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0.5" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0.5" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0.5" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0.5" + offset="0 0 0" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0.5" + offset="0 0 0" /> + + </param_skeleton> + </param> + + <param + id="30031" + group="1" + name="Arced_Eyebrows" + value_min="0" + value_max="2" + value_default=".5"> + + <param_skeleton> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0 " + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0 " + offset="0.0 0.0 0.005" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0 " + offset="0.0 0.0 0.001" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0 " + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0 " + offset="0.0 0.0 0.005" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0 " + offset="0.0 0.0 0.001" /> + + </param_skeleton> + </param> + + <param + id="30757" + group="1" + name="Lower_Eyebrows" + value_min="-4" + value_max="2" + value_default="-1"> + + <param_skeleton> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0 " + offset="0.0 0.0 -0.001" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0 " + offset="0.0 0.0 -0.002" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0 " + offset="0.0 0.0 -0.001" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0 " + offset="0.0 0.0 -0.001" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0 " + offset="0.0 0.0 -0.002" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0 " + offset="0.0 0.0 -0.001" /> + + </param_skeleton> + </param> + + <param + id="30016" + group="1" + name="Pointy_Eyebrows" + value_min="-.5" + value_max="3"> + + <param_skeleton> + + <bone + name="mFaceEyebrowOuterRight" + scale="0 0 0 " + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceEyebrowCenterRight" + scale="0 0 0 " + offset="0.0 -0.001 0.0035" /> + + <bone + name="mFaceEyebrowInnerRight" + scale="0 0 0 " + offset="0.0 0.0 -0.002" /> + + <bone + name="mFaceEyebrowOuterLeft" + scale="0 0 0 " + offset="0.0 0.0 0.0" /> + + <bone + name="mFaceEyebrowCenterLeft" + scale="0 0 0 " + offset="0.0 0.001 0.0035" /> + + <bone + name="mFaceEyebrowInnerLeft" + scale="0 0 0 " + offset="0.0 0.0 -0.002" /> + + </param_skeleton> + </param> + </skeleton> <mesh type="hairMesh" - lod="0" + lod="0" file_name="avatar_hair.llm" min_pixel_width="320"> <!-- begin morph targets --> @@ -1113,7 +4459,7 @@ group="1" name="Hair_Volume" label="Hair Volume" - show_simple="true" + show_simple="true" wearable="hair" clothing_morph="true" edit_group="hair_style" @@ -1920,95 +5266,184 @@ ############# --> <param - id="1" - group="0" + id="20001" + group="1" name="Big_Brow" - label="Brow Size" - wearable="shape" - edit_group="shape_head" - edit_group_order="7" - label_min="Small" - label_max="Large" value_min="-.3" - value_max="2" - camera_elevation=".1" - camera_distance=".4" - camera_angle="45"> + value_max="2"> <param_morph /> </param> <param - id="2" - group="0" + id="20002" + group="1" name="Nose_Big_Out" - label="Nose Size" - wearable="shape" - edit_group="shape_nose" - edit_group_order="1" - label_min="Small" - label_max="Large" - show_simple="true" value_min="-0.8" - value_max="2.5" - camera_elevation=".1" - camera_distance=".35" - camera_angle="50"> + value_max="2.5"> <param_morph /> </param> <param - id="4" - group="0" + id="20517" + group="1" + name="Wide_Nose" + value_min="-.5" + value_max="1"> + <param_morph /> + </param> + + <param + id="20020" + group="1" + name="Bulbous_Nose" + value_min="-.5" + value_max="1.5"> + <param_morph /> + </param> + + <param + id="20656" + group="1" + name="Crooked_Nose" + value_min="-2" + value_max="2"> + <param_morph /> + </param> + + <param + id="20004" + group="1" name="Broad_Nostrils" - label="Nostril Width" - wearable="shape" - edit_group="shape_nose" - edit_group_order="3" - label_min="Narrow" - label_max="Broad" value_min="-.5" - value_max="1" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="1"> <param_morph /> </param> <param - id="759" - group="0" - name="Low_Septum_Nose" - label="Nostril Division" - wearable="shape" - edit_group="shape_nose" - edit_group_order="3.5" - label_min="High" - label_max="Low" + id="20653" + group="1" + name="Tall_Lips" value_min="-1" - value_max="1.5" - value_default="0.5" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="2"> + <param_morph /> + </param> + + <param + id="20506" + group="1" + name="Mouth_Height" + value_min="-2" + value_max="2"> <param_morph /> </param> + + <param + id="20764" + group="1" + name="Lip_Cleft_Deep" + value_min="-.5" + value_max="1.2"> + <param_morph/> + </param> <param - id="517" - group="0" - name="Wide_Nose" - label="Nose Width" - wearable="shape" - edit_group="shape_nose" - edit_group_order="2" - label_min="Narrow" - label_max="Wide" - show_simple="true" + id="20025" + group="1" + name="Wide_Lip_Cleft" + value_min="-.8" + value_max="1.5"> + <param_morph/> + </param> + + <param + id="20663" + group="1" + name="Shift_Mouth" + value_min="-2" + value_max="2" + value_default="0"> + <param_morph /> + </param> + + <param + id="20035" + group="1" + name="Big_Ears" + value_min="-1" + value_max="2"> + <param_morph/> + </param> + + <param + id="20015" + group="1" + name="Ears_Out" value_min="-.5" - value_max="1" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="1.5"> + <param_morph/> + </param> + + <param + id="20796" + group="1" + name="Pointy_Ears" + value_min="-.4" + value_max="3"> + <param_morph /> + </param> + + <param + id="20185" + group="1" + name="Deep_Chin" + value_min="-1" + value_max="1"> + <param_morph /> + </param> + + <param + id="20665" + group="1" + name="Jaw_Jut" + value_min="-2" + value_max="2"> + <param_morph /> + </param> + + <param + id="20024" + group="1" + name="Wide_Eyes" + value_min="-1.5" + value_max="2"> + <param_morph /> + </param> + + <param + id="20650" + group="1" + name="Eyelid_Corner_Up" + value_min="-1.3" + value_max="1.2"> + <param_morph /> + </param> + + <param + id="20765" + group="1" + name="Puffy_Lower_Lids" + value_min="-.3" + value_max="2.5"> + <param_morph /> + </param> + + <param + id="20759" + group="1" + name="Low_Septum_Nose" + value_min="-1" + value_max="1.5" + value_default="0.5"> <param_morph /> </param> @@ -2031,111 +5466,56 @@ </param> <param - id="6" - group="0" + id="20006" + group="1" name="Bulbous_Nose_Tip" - label="Nose Tip Shape" - wearable="shape" - edit_group="shape_nose" - edit_group_order="8" - label_min="Pointy" - label_max="Bulbous" value_min="-.3" - value_max="1" - camera_elevation=".1" - camera_distance=".35" - camera_angle="15"> + value_max="1"> <param_morph /> </param> <param - id="7" - group="0" + id="20007" + group="1" name="Weak_Chin" - label="Chin Angle" - wearable="shape" - edit_group="shape_chin" - edit_group_order="1" - label_min="Chin Out" - label_max="Chin In" value_min="-.5" - value_max=".5" - camera_elevation=".1" - camera_distance=".4" - camera_angle="45"> + value_max=".5"> <param_morph /> </param> <param - id="8" - group="0" + id="20008" + group="1" name="Double_Chin" - label="Chin-Neck" - wearable="shape" - edit_group="shape_chin" - edit_group_order="8" - label_min="Tight Chin" - label_max="Double Chin" value_min="-.5" - value_max="1.5" - camera_elevation="-.1" - camera_distance=".3" - camera_angle="60"> + value_max="1.5"> <param_morph /> </param> <param - id="10" - group="0" + id="20010" + group="1" name="Sunken_Cheeks" - label="Lower Cheeks" - wearable="shape" - edit_group="shape_head" - edit_group_order="9" - label_min="Well-Fed" - label_max="Sunken" - show_simple="true" value_min="-1.5" - value_max="3" - camera_elevation=".1" - camera_distance=".4" - camera_angle="5"> + value_max="3"> <param_morph /> </param> <param - id="11" - group="0" + id="20011" + group="1" name="Noble_Nose_Bridge" - label="Upper Bridge" - wearable="shape" - edit_group="shape_nose" - edit_group_order="5" - label_min="Low" - label_max="High" value_min="-.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".35" - camera_angle="70"> + value_max="1.5"> <param_morph /> </param> <param - id="758" - group="0" + id="20758" + group="1" name="Lower_Bridge_Nose" - label="Lower Bridge" - wearable="shape" - edit_group="shape_nose" - edit_group_order="5.5" - label_min="Low" - label_max="High" value_min="-1.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".35" - camera_angle="70"> + value_max="1.5"> <param_morph /> </param> @@ -2175,38 +5555,11 @@ </param> <param - id="14" - group="0" + id="20014" + group="1" name="High_Cheek_Bones" - label="Cheek Bones" - wearable="shape" - edit_group="shape_head" - edit_group_order="10" - label_min="Low" - label_max="High" - value_min="-.5" - value_max="1" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> - <param_morph /> - </param> - - <param - id="15" - group="0" - name="Ears_Out" - label="Ear Angle" - wearable="shape" - edit_group="shape_ears" - edit_group_order="2" - label_min="In" - label_max="Out" value_min="-.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="1"> <param_morph /> </param> @@ -2229,91 +5582,38 @@ </param> <param - id="17" - group="0" + id="20017" + group="1" name="Square_Jaw" - label="Jaw Shape" - wearable="shape" - edit_group="shape_chin" - edit_group_order="2" - label_min="Pointy" - label_max="Square" value_min="-.5" - value_max="1" - camera_distance=".3" - camera_elevation=".04" - camera_angle="-20"> + value_max="1"> <param_morph /> </param> <param - id="18" - group="0" + id="20018" + group="1" name="Puffy_Upper_Cheeks" - label="Upper Cheeks" - wearable="shape" - edit_group="shape_head" - edit_group_order="8" - label_min="Thin" - label_max="Puffy" value_min="-1.5" - value_max="2.5" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="2.5"> <param_morph /> </param> <param - id="19" - group="0" + id="20019" + group="1" name="Upturned_Nose_Tip" - label="Nose Tip Angle" - wearable="shape" - edit_group="shape_nose" - edit_group_order="7" - label_min="Downturned" - label_max="Upturned" value_min="-1.5" - value_max="1" - camera_elevation=".1" - camera_distance=".35" - camera_angle="15"> - <param_morph /> - </param> - - <param - id="20" - group="0" - name="Bulbous_Nose" - label="Nose Thickness" - wearable="shape" - edit_group="shape_nose" - edit_group_order="4" - label_min="Thin Nose" - label_max="Bulbous Nose" - show_simple="true" - value_min="-.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".3"> + value_max="1"> <param_morph /> </param> - + <param - id="21" - group="0" + id="20021" + group="1" name="Upper_Eyelid_Fold" - label="Upper Eyelid Fold" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="5" - label_min="Uncreased" - label_max="Creased" value_min="-0.2" - value_max="1.3" - camera_elevation=".1" - camera_distance=".35"> + value_max="1.3"> <param_morph /> </param> @@ -2336,88 +5636,11 @@ </param> <param - id="23" - group="0" + id="20023" + group="1" name="Baggy_Eyes" - label="Eye Bags" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="6" - label_min="Smooth" - label_max="Baggy" value_min="-.5" - value_max="1.5" - camera_elevation=".1" - camera_distance=".35"> - <param_morph /> - </param> - - <param - id="765" - group="0" - name="Puffy_Lower_Lids" - label="Puffy Eyelids" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="6.1" - label_min="Flat" - label_max="Puffy" - value_min="-.3" - value_max="2.5" - camera_elevation=".1" - camera_distance=".35"> - <param_morph /> - </param> - - <param - id="24" - group="0" - name="Wide_Eyes" - label="Eye Opening" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="1.1" - label_min="Narrow" - label_max="Wide" - value_min="-1.5" - value_max="2" - show_simple="true" - camera_elevation=".1" - camera_distance=".35"> - <param_morph /> - </param> - - <param - id="25" - group="0" - name="Wide_Lip_Cleft" - label="Lip Cleft" - wearable="shape" - edit_group="shape_mouth" - edit_group_order="6" - label_min="Narrow" - label_max="Wide" - value_min="-.8" - value_max="1.5" - camera_elevation="0" - camera_distance=".28"> - <param_morph /> - </param> - - <param - id="764" - group="0" - name="Lip_Cleft_Deep" - label="Lip Cleft Depth" - wearable="shape" - edit_group="shape_mouth" - edit_group_order="5.8" - label_min="Shallow" - label_max="Deep" - value_min="-.5" - value_max="1.2" - camera_elevation="0" - camera_distance=".28"> + value_max="1.5"> <param_morph /> </param> @@ -2433,20 +5656,11 @@ </param> <param - id="27" - group="0" + id="20027" + group="1" name="Wide_Nose_Bridge" - label="Bridge Width" - wearable="shape" - edit_group="shape_nose" - edit_group_order="6" - label_min="Narrow" - label_max="Wide" value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".3" - camera_angle="-20"> + value_max="1.2"> <param_morph /> </param> @@ -2517,60 +5731,6 @@ </param> <param - id="35" - group="0" - name="Big_Ears" - label="Ear Size" - wearable="shape" - edit_group="shape_ears" - edit_group_order="1" - label_min="Small" - label_max="Large" - value_min="-1" - value_max="2" - camera_elevation=".1" - camera_distance=".3" - camera_angle="45"> - <param_morph /> - </param> - - <param - id="796" - group="0" - name="Pointy_Ears" - label="Ear Tips" - wearable="shape" - edit_group="shape_ears" - edit_group_order="4" - label_min="Flat" - label_max="Pointy" - value_min="-.4" - value_max="3" - camera_elevation=".1" - camera_distance=".3" - camera_angle="45"> - <param_morph /> - </param> - - <param - id="185" - group="0" - name="Deep_Chin" - label="Chin Depth" - wearable="shape" - edit_group="shape_chin" - edit_group_order="3" - label_min="Shallow" - label_max="Deep" - value_min="-1" - value_max="1" - camera_elevation=".1" - camera_distance=".4" - camera_angle="30"> - <param_morph /> - </param> - - <param id="186" group="1" name="Egg_Head" @@ -2667,24 +5827,6 @@ </param> <param - id="506" - group="0" - name="Mouth_Height" - wearable="shape" - label="Mouth Position" - show_simple="true" - edit_group="shape_mouth" - edit_group_order="4" - label_min="High" - label_max="Low" - value_min="-2" - value_max="2" - camera_distance=".3" - camera_elevation=".04"> - <param_morph /> - </param> - - <param id="633" group="1" name="Fat_Head" @@ -2726,76 +5868,14 @@ </param> <param - id="650" - group="0" - name="Eyelid_Corner_Up" - label="Outer Eye Corner" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="4" - label_min="Corner Down" - label_max="Corner Up" - value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".30"> - <param_morph /> - </param> - - <param - id="880" - group="0" + id="20880" + group="1" name="Eyelid_Inner_Corner_Up" - label="Inner Eye Corner" - wearable="shape" - edit_group="shape_eyes" - edit_group_order="4.2" - label_min="Corner Down" - label_max="Corner Up" value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".30"> + value_max="1.2"> <param_morph /> </param> - - <param - id="653" - group="0" - name="Tall_Lips" - wearable="shape" - label="Lip Fullness" - show_simple="true" - edit_group="shape_mouth" - edit_group_order="2" - label_min="Less Full" - label_max="More Full" - value_min="-1" - value_max="2" - camera_distance=".3" - camera_elevation=".04"> - <param_morph /> - </param> - - <param - id="656" - group="0" - name="Crooked_Nose" - wearable="shape" - label="Crooked Nose" - edit_group="shape_nose" - edit_group_order="9" - label_min="Nose Left" - label_max="Nose Right" - value_min="-2" - value_max="2" - camera_distance=".3" - camera_elevation=".04" - camera_angle="-20"> - <param_morph /> - </param> - <param id="657" group="1" @@ -2899,25 +5979,6 @@ </param> <param - id="663" - group="0" - name="Shift_Mouth" - wearable="shape" - label="Shift Mouth" - edit_group="shape_mouth" - edit_group_order="7" - label_min="Shift Left" - label_max="Shift Right" - value_min="-2" - value_max="2" - value_default="0" - camera_distance=".35" - camera_elevation=".04" - camera_angle="-20"> - <param_morph /> - </param> - - <param id="664" group="0" name="Pop_Eye" @@ -2936,40 +5997,12 @@ </param> <param - id="760" - group="0" + id="20760" + group="1" name="Jaw_Angle" - wearable="shape" - label="Jaw Angle" - edit_group="shape_chin" - edit_group_order="3.5" - label_min="Low Jaw" - label_max="High Jaw" value_min="-1.2" value_max="2" - value_default="0" - camera_distance=".5" - camera_elevation=".04" - camera_angle="70"> - <param_morph /> - </param> - - <param - id="665" - group="0" - name="Jaw_Jut" - wearable="shape" - label="Jaw Jut" - edit_group="shape_chin" - edit_group_order="4" - label_min="Overbite" - label_max="Underbite" - value_min="-2" - value_max="2" - value_default="0" - camera_distance=".5" - camera_elevation=".04" - camera_angle="70"> + value_default="0"> <param_morph /> </param> @@ -3413,41 +6446,6 @@ <param shared="1" - id="21" - group="0" - name="Upper_Eyelid_Fold" - label="Upper Eyelid Fold" - wearable="shape" - edit_group="shape_eyes" - label_min="Uncreased" - label_max="Creased" - value_min="-0.2" - value_max="1.3" - camera_elevation=".1" - camera_distance=".35"> - <param_morph /> - </param> - - <param - shared="1" - id="24" - group="0" - name="Wide_Eyes" - label="Eye Opening" - wearable="shape" - edit_group="shape_eyes" - label_min="Narrow" - label_max="Wide" - show_simple="true" - value_min="-1.5" - value_max="2" - camera_elevation=".1" - camera_distance=".3"> - <param_morph /> - </param> - - <param - shared="1" id="186" group="1" name="Egg_Head" @@ -3515,41 +6513,6 @@ <param shared="1" - id="650" - group="0" - name="Eyelid_Corner_Up" - label="Outer Eye Corner" - wearable="shape" - edit_group="shape_eyes" - label_min="Corner Down" - label_max="Corner Up" - value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".3"> - <param_morph /> - </param> - - - <param - shared="1" - id="880" - group="0" - name="Eyelid_Inner_Corner_Up" - label="Inner Eye Corner" - wearable="shape" - edit_group="shape_eyes" - label_min="Corner Down" - label_max="Corner Up" - value_min="-1.3" - value_max="1.2" - camera_elevation=".1" - camera_distance=".3"> - <param_morph /> - </param> - - <param - shared="1" id="686" group="1" name="Head_Eyes_Big" @@ -3560,7 +6523,7 @@ label_max="Anime Eyes" value_min="-2" value_max="2" - show_simple="true" + show_simple="true" value_default="0"> <param_morph /> </param> @@ -3582,6 +6545,46 @@ <param_morph /> </param> + <param + shared="1" + id="20021" + group="1" + name="Upper_Eyelid_Fold" + value_min="-0.2" + value_max="1.3"> + <param_morph /> + </param> + + <param + shared="1" + id="20024" + group="1" + name="Wide_Eyes" + value_min="-1.5" + value_max="2"> + <param_morph /> + </param> + + <param + shared="1" + id="20650" + group="1" + name="Eyelid_Corner_Up" + value_min="-1.3" + value_max="1.2"> + <param_morph /> + </param> + + <param + shared="1" + id="20880" + group="1" + name="Eyelid_Inner_Corner_Up" + value_min="-1.3" + value_max="1.2"> + <param_morph /> + </param> + <!-- ############## # Facial Expression morphs @@ -3882,7 +6885,7 @@ <volume_morph name="RIGHT_PEC" scale="-0.05 0.0 0.0" - pos="-0.01 -0.01 -0.02"/> + pos="-0.01 0.01 -0.02"/> </param_morph> </param> @@ -3908,7 +6911,7 @@ <volume_morph name="RIGHT_PEC" scale="-0.051 0.0 0.0" - pos="-0.02 -0.01 -0.03"/> + pos="-0.02 0.01 -0.03"/> </param_morph> </param> @@ -3917,7 +6920,51 @@ group="1" name="Muscular_Torso" label="Torso Muscles" - show_simple="true" + sex="male" + show_simple="true" + wearable="shape" + edit_group="shape_torso" + label_min="Regular" + label_max="Muscular" + value_min="0" + value_max="1.4" + camera_elevation=".3" + camera_distance="1.2"> + <param_morph> + <volume_morph + name="L_CLAVICLE" + scale="0.02 0.0 0.005" + pos="0.0 0 0.005"/> + <volume_morph + name="L_UPPER_ARM" + scale="0.015 0.0 0.005" + pos="0.015 0 0"/> + <volume_morph + name="L_LOWER_ARM" + scale="0.005 0.0 0.005" + pos="0.005 0 0"/> + <volume_morph + name="R_CLAVICLE" + scale="0.02 0.0 0.005" + pos="0.0 0 0.005"/> + <volume_morph + name="R_UPPER_ARM" + scale="0.015 0.0 0.005" + pos="0.015 0 0"/> + <volume_morph + name="R_LOWER_ARM" + scale="0.005 0.0 0.005" + pos="0.005 0 0"/> + </param_morph> + </param> + + <param + id="107" + group="1" + name="Muscular_Torso" + label="Torso Muscles" + sex="female" + show_simple="true" wearable="shape" edit_group="shape_torso" label_min="Regular" @@ -5030,21 +8077,12 @@ </param> <param - id="879" - group="0" + id="20879" + group="1" sex="male" name="Male_Package" - label="Package" - wearable="shape" - edit_group="shape_legs" - edit_group_order="4.6" - label_min="Coin Purse" - label_max="Duffle Bag" - value_default="0" value_min="-.5" - value_max="2" - camera_angle="60" - camera_distance=".6"> + value_max="2"> <param_morph /> </param> @@ -9384,6 +12422,825 @@ render_pass="bump"> <driver_parameters> <param + id="2" + group="0" + name="Nose_Big_Out" + label="Nose Size" + wearable="shape" + edit_group="shape_nose" + edit_group_order="1" + label_min="Small" + label_max="Large" + show_simple="true" + value_min="-0.8" + value_max="2.5" + camera_elevation=".1" + camera_distance=".35" + camera_angle="50"> + <param_driver> + <driven + id="20002" /> + <driven + id="30002" /> + </param_driver> + </param> + + <param + id="4" + group="0" + name="Broad_Nostrils" + label="Nostril Width" + wearable="shape" + edit_group="shape_nose" + edit_group_order="3" + label_min="Narrow" + label_max="Broad" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20004" /> + <driven + id="30004" /> + </param_driver> + </param> + + <param + id="517" + group="0" + name="Wide_Nose" + label="Nose Width" + wearable="shape" + edit_group="shape_nose" + edit_group_order="2" + label_min="Narrow" + label_max="Wide" + show_simple="true" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20517" /> + <driven + id="30517" /> + </param_driver> + </param> + + <param + id="20" + group="0" + name="Bulbous_Nose" + label="Nose Thickness" + wearable="shape" + edit_group="shape_nose" + edit_group_order="4" + label_min="Thin Nose" + label_max="Bulbous Nose" + show_simple="true" + value_min="-.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".3"> + <param_driver> + <driven + id="20020" /> + <driven + id="30020" /> + </param_driver> + </param> + + <param + id="656" + group="0" + name="Crooked_Nose" + wearable="shape" + label="Crooked Nose" + edit_group="shape_nose" + edit_group_order="9" + label_min="Nose Left" + label_max="Nose Right" + value_min="-2" + value_max="2" + camera_distance=".3" + camera_elevation=".04" + camera_angle="-20"> + <param_driver> + <driven + id="20656" /> + <driven + id="30656" /> + </param_driver> + </param> + + <param + id="653" + group="0" + name="Tall_Lips" + wearable="shape" + label="Lip Fullness" + show_simple="true" + edit_group="shape_mouth" + edit_group_order="2" + label_min="Less Full" + label_max="More Full" + value_min="-1" + value_max="2" + camera_distance=".3" + camera_elevation=".04"> + <param_driver> + <driven + id="20653" /> + <driven + id="30653" /> + </param_driver> + </param> + + <param + id="506" + group="0" + name="Mouth_Height" + wearable="shape" + label="Mouth Position" + show_simple="true" + edit_group="shape_mouth" + edit_group_order="4" + label_min="High" + label_max="Low" + value_min="-2" + value_max="2" + camera_distance=".3" + camera_elevation=".04"> + <param_driver> + <driven + id="20506" /> + <driven + id="30506" /> + </param_driver> + </param> + + <param + id="764" + group="0" + name="Lip_Cleft_Deep" + label="Lip Cleft Depth" + wearable="shape" + edit_group="shape_mouth" + edit_group_order="5.8" + label_min="Shallow" + label_max="Deep" + value_min="-.5" + value_max="1.2" + camera_elevation="0" + camera_distance=".28"> + <param_driver> + <driven + id="20764" /> + <driven + id="30764" /> + </param_driver> + </param> + + <param + id="25" + group="0" + name="Wide_Lip_Cleft" + label="Lip Cleft" + wearable="shape" + edit_group="shape_mouth" + edit_group_order="6" + label_min="Narrow" + label_max="Wide" + value_min="-.8" + value_max="1.5" + camera_elevation="0" + camera_distance=".28"> + <param_driver> + <driven + id="20025" /> + <driven + id="30025" /> + </param_driver> + </param> + + <param + id="663" + group="0" + name="Shift_Mouth" + wearable="shape" + label="Shift Mouth" + edit_group="shape_mouth" + edit_group_order="7" + label_min="Shift Left" + label_max="Shift Right" + value_min="-2" + value_max="2" + value_default="0" + camera_distance=".35" + camera_elevation=".04" + camera_angle="-20"> + <param_driver> + <driven + id="20663" /> + + <driven + id="31663" + min1="-2" + max1="-2" + max2="-2" + min2="0" /> + <driven + id="32663" + min1="0" + max1="2" + max2="2" + min2="2" /> + </param_driver> + </param> + + <param + id="35" + group="0" + name="Big_Ears" + label="Ear Size" + wearable="shape" + edit_group="shape_ears" + edit_group_order="1" + label_min="Small" + label_max="Large" + value_min="-1" + value_max="2" + camera_elevation=".1" + camera_distance=".3" + camera_angle="45"> + <param_driver> + <driven + id="20035" /> + <driven + id="30035" /> + </param_driver> + </param> + + <param + id="15" + group="0" + name="Ears_Out" + label="Ear Angle" + wearable="shape" + edit_group="shape_ears" + edit_group_order="2" + label_min="In" + label_max="Out" + value_min="-.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20015" /> + <driven + id="30015" /> + </param_driver> + </param> + + <param + id="796" + group="0" + name="Pointy_Ears" + label="Ear Tips" + wearable="shape" + edit_group="shape_ears" + edit_group_order="4" + label_min="Flat" + label_max="Pointy" + value_min="-.4" + value_max="3" + camera_elevation=".1" + camera_distance=".3" + camera_angle="45"> + <param_driver> + <driven + id="20796" /> + <driven + id="30796" /> + </param_driver> + </param> + + <param + id="185" + group="0" + name="Deep_Chin" + label="Chin Depth" + wearable="shape" + edit_group="shape_chin" + edit_group_order="3" + label_min="Shallow" + label_max="Deep" + value_min="-1" + value_max="1" + camera_elevation=".1" + camera_distance=".4" + camera_angle="30"> + <param_driver> + <driven + id="20185" /> + <driven + id="30185" /> + </param_driver> + </param> + + <param + id="760" + group="0" + name="Jaw_Angle" + wearable="shape" + label="Jaw Angle" + edit_group="shape_chin" + edit_group_order="3.5" + label_min="Low Jaw" + label_max="High Jaw" + value_min="-1.2" + value_max="2" + value_default="0" + camera_distance=".5" + camera_elevation=".04" + camera_angle="70"> + <param_driver> + <driven + id="20760" /> + <driven + id="30760" /> + </param_driver> + </param> + + + <param + id="665" + group="0" + name="Jaw_Jut" + wearable="shape" + label="Jaw Jut" + edit_group="shape_chin" + edit_group_order="4" + label_min="Overbite" + label_max="Underbite" + value_min="-2" + value_max="2" + value_default="0" + camera_distance=".5" + camera_elevation=".04" + camera_angle="70"> + <param_driver> + <driven + id="20665" /> + <driven + id="30665" /> + </param_driver> + </param> + + <param + id="6" + group="0" + name="Bulbous_Nose_Tip" + label="Nose Tip Shape" + wearable="shape" + edit_group="shape_nose" + edit_group_order="8" + label_min="Pointy" + label_max="Bulbous" + value_min="-.3" + value_max="1" + camera_elevation=".1" + camera_distance=".35" + camera_angle="15"> + <param_driver> + <driven + id="20006" /> + <driven + id="30006" /> + </param_driver> + </param> + + <param + id="7" + group="0" + name="Weak_Chin" + label="Chin Angle" + wearable="shape" + edit_group="shape_chin" + edit_group_order="1" + label_min="Chin Out" + label_max="Chin In" + value_min="-.5" + value_max=".5" + camera_elevation=".1" + camera_distance=".4" + camera_angle="45"> + <param_driver> + <driven + id="20007" /> + <driven + id="30007" /> + </param_driver> + </param> + + <param + id="8" + group="0" + name="Double_Chin" + label="Chin-Neck" + wearable="shape" + edit_group="shape_chin" + edit_group_order="8" + label_min="Tight Chin" + label_max="Double Chin" + value_min="-.5" + value_max="1.5" + camera_elevation="-.1" + camera_distance=".3" + camera_angle="60"> + <param_driver> + <driven + id="20008" /> + <driven + id="30008" /> + </param_driver> + </param> + + + <param + id="24" + group="0" + name="Wide_Eyes" + label="Eye Opening" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="1.1" + label_min="Narrow" + label_max="Wide" + value_min="-1.5" + value_max="2" + show_simple="true" + camera_elevation=".1" + camera_distance=".35"> + <param_driver> + <driven + id="20024" /> + <driven + id="30024" /> + </param_driver> + </param> + + <param + id="650" + group="0" + name="Eyelid_Corner_Up" + label="Outer Eye Corner" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="4" + label_min="Corner Down" + label_max="Corner Up" + value_min="-1.3" + value_max="1.2" + camera_elevation=".1" + camera_distance=".30"> + <param_driver> + <driven + id="20650" /> + <driven + id="30650" /> + </param_driver> + </param> + + <param + id="880" + group="0" + name="Eyelid_Inner_Corner_Up" + label="Inner Eye Corner" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="4.2" + label_min="Corner Down" + label_max="Corner Up" + value_min="-1.3" + value_max="1.2" + camera_elevation=".1" + camera_distance=".30"> + <param_driver> + <driven + id="20880" /> + <driven + id="30880" /> + </param_driver> + </param> + + <param + id="21" + group="0" + name="Upper_Eyelid_Fold" + label="Upper Eyelid Fold" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="5" + label_min="Uncreased" + label_max="Creased" + value_min="-0.2" + value_max="1.3" + camera_elevation=".1" + camera_distance=".35"> + <param_driver> + <driven + id="20021" /> + <driven + id="30021" /> + </param_driver> + </param> + + <param + id="23" + group="0" + name="Baggy_Eyes" + label="Eye Bags" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="6" + label_min="Smooth" + label_max="Baggy" + value_min="-.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".35"> + <param_driver> + <driven + id="20023" /> + <driven + id="30023" /> + </param_driver> + </param> + + <param + id="765" + group="0" + name="Puffy_Lower_Lids" + label="Puffy Eyelids" + wearable="shape" + edit_group="shape_eyes" + edit_group_order="6.1" + label_min="Flat" + label_max="Puffy" + value_min="-.3" + value_max="2.5" + camera_elevation=".1" + camera_distance=".35"> + <param_driver> + <driven + id="20765" /> + <driven + id="30765" /> + </param_driver> + </param> + + <param + id="1" + group="0" + name="Big_Brow" + label="Brow Size" + wearable="shape" + edit_group="shape_head" + edit_group_order="7" + label_min="Small" + label_max="Large" + value_min="-.3" + value_max="2" + camera_elevation=".1" + camera_distance=".4" + camera_angle="45"> + <param_driver> + <driven + id="20001" /> + <driven + id="30001" /> + </param_driver> + </param> + + <param + id="11" + group="0" + name="Noble_Nose_Bridge" + label="Upper Bridge" + wearable="shape" + edit_group="shape_nose" + edit_group_order="5" + label_min="Low" + label_max="High" + value_min="-.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".35" + camera_angle="70"> + <param_driver> + <driven + id="20011" /> + <driven + id="30011" /> + </param_driver> + </param> + + <param + id="758" + group="0" + name="Lower_Bridge_Nose" + label="Lower Bridge" + wearable="shape" + edit_group="shape_nose" + edit_group_order="5.5" + label_min="Low" + label_max="High" + value_min="-1.5" + value_max="1.5" + camera_elevation=".1" + camera_distance=".35" + camera_angle="70"> + <param_driver> + <driven + id="20758" /> + <driven + id="30758" /> + </param_driver> + </param> + + <param + id="27" + group="0" + name="Wide_Nose_Bridge" + label="Bridge Width" + wearable="shape" + edit_group="shape_nose" + edit_group_order="6" + label_min="Narrow" + label_max="Wide" + value_min="-1.3" + value_max="1.2" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20027" /> + <driven + id="30027" /> + </param_driver> + </param> + + <param + id="759" + group="0" + name="Low_Septum_Nose" + label="Nostril Division" + wearable="shape" + edit_group="shape_nose" + edit_group_order="3.5" + label_min="High" + label_max="Low" + value_min="-1" + value_max="1.5" + value_default="0.5" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20759" /> + <driven + id="30759" /> + </param_driver> + </param> + + + <param + id="10" + group="0" + name="Sunken_Cheeks" + label="Lower Cheeks" + wearable="shape" + edit_group="shape_head" + edit_group_order="9" + label_min="Well-Fed" + label_max="Sunken" + show_simple="true" + value_min="-1.5" + value_max="3" + camera_elevation=".1" + camera_distance=".4" + camera_angle="5"> + <param_driver> + <driven + id="20010" /> + <driven + id="30010" /> + </param_driver> + </param> + + <param + id="17" + group="0" + name="Square_Jaw" + label="Jaw Shape" + wearable="shape" + edit_group="shape_chin" + edit_group_order="2" + label_min="Pointy" + label_max="Square" + value_min="-.5" + value_max="1" + camera_distance=".3" + camera_elevation=".04" + camera_angle="-20"> + <param_driver> + <driven + id="20017" /> + <driven + id="30017" /> + </param_driver> + </param> + + <param + id="18" + group="0" + name="Puffy_Upper_Cheeks" + label="Upper Cheeks" + wearable="shape" + edit_group="shape_head" + edit_group_order="8" + label_min="Thin" + label_max="Puffy" + value_min="-1.5" + value_max="2.5" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20018" /> + <driven + id="30018" /> + </param_driver> + </param> + + <param + id="14" + group="0" + name="High_Cheek_Bones" + label="Cheek Bones" + wearable="shape" + edit_group="shape_head" + edit_group_order="10" + label_min="Low" + label_max="High" + value_min="-.5" + value_max="1" + camera_elevation=".1" + camera_distance=".3" + camera_angle="-20"> + <param_driver> + <driven + id="20014" /> + <driven + id="30014" /> + </param_driver> + </param> + + <param + id="19" + group="0" + name="Upturned_Nose_Tip" + label="Nose Tip Angle" + wearable="shape" + edit_group="shape_nose" + edit_group_order="7" + label_min="Downturned" + label_max="Upturned" + value_min="-1.5" + value_max="1" + camera_elevation=".1" + camera_distance=".35" + camera_angle="15"> + <param_driver> + <driven + id="20019" /> + <driven + id="30019" /> + </param_driver> + </param> + + <param id="828" group="0" name="Loose Upper Clothing" @@ -9807,6 +13664,20 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + <driven + id="30505" + min1="0" + max1="0" + max2="0" + min2=".5" /> + <driven + id="31505" + min1=".5" + max1="1" + max2="1" + min2="1" /> + </param_driver> </param> @@ -9817,8 +13688,8 @@ render_pass="bump"> edit_group="shape_mouth" edit_group_order="3.2" name="Lip Ratio" - label="Lip Ratio" - show_simple="true" + label="Lip Ratio" + show_simple="true" label_min="More Upper Lip" label_max="More Lower Lip" value_min="0" @@ -9841,6 +13712,21 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + <driven + id="30797" + min1="0" + max1="0" + max2="0" + min2=".5" /> + + <driven + id="30798" + min1=".5" + max1="1" + max2="1" + min2="1" /> + </param_driver> </param> @@ -9866,6 +13752,10 @@ render_pass="bump"> <driven id="30" /> + + <driven + id="30155" /> + </param_driver> </param> @@ -10076,6 +13966,10 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + <driven + id="30193"/> + </param_driver> </param> @@ -10366,8 +14260,8 @@ render_pass="bump"> edit_group="hair_style" edit_group_order="16" name="Hair Tilt" - label_min="Hair Tilted Left" - label_max="Hair Tilted Right" + label_min="Left" + label_max="Right" value_min="0" value_max="1" value_default=".5" @@ -10548,6 +14442,21 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + <driven + id="31629" + min1="0" + max1="0" + max2="0" + min2=".5" /> + + <driven + id="32629" + min1=".5" + max1="1" + max2="1" + min2="1" /> + </param_driver> </param> @@ -10574,6 +14483,14 @@ render_pass="bump"> <driven id="186" /> + + <driven + min1="-1.3" + max1="-1.3" + max2="-1.3" + min2="1" + id="30646" /> + </param_driver> </param> @@ -10600,6 +14517,10 @@ render_pass="bump"> <driven id="187" /> + + <driven + id="30647" /> + </param_driver> </param> @@ -10630,7 +14551,7 @@ render_pass="bump"> min2=".5" /> <driven - id="106" + id="107" min1=".5" max1="1" max2="1" @@ -10759,7 +14680,22 @@ render_pass="bump"> max1="1" max2="1" min2="1" /> + + <driven + id="30658" + min1="0" + max1="0" + max2="0" + min2=".5" /> + + <driven + id="30657" + min1=".5" + max1="1" + max2="1" + min2="1" /> </param_driver> + </param> <param @@ -10812,6 +14748,24 @@ render_pass="bump"> <driven id="772" /> + + <driven + id="30772" /> + + <driven + min1="0" + max1="0" + max2="0" + min2="0.45" + id="31772" /> + + <driven + min1="0.5" + max1="1" + max2="1" + min2="1" + id="32772" /> + </param_driver> </param> @@ -10822,7 +14776,7 @@ render_pass="bump"> edit_group="shape_head" edit_group_order="1" name="Head Size" - label="Head Size" + label="Head Size" label_min="Small Head" label_max="Big Head" show_simple="true" @@ -10856,16 +14810,17 @@ render_pass="bump"> edit_group="shape_eyes" edit_group_order="1" name="Eye Size" - label="Eye Size" + label="Eye Size" label_min="Beady Eyes" label_max="Anime Eyes" value_min="0" value_max="1" value_default=".5" - show_simple="true" + show_simple="true" camera_elevation=".1" camera_distance=".35"> <param_driver> + <driven id="686" /> @@ -10883,6 +14838,10 @@ render_pass="bump"> <driven id="689" /> + + <driven + id="30689" /> + </param_driver> </param> @@ -11169,6 +15128,31 @@ render_pass="bump"> </param> <param + id="879" + group="0" + sex="male" + name="Male_Package" + label="Package" + wearable="shape" + edit_group="shape_legs" + edit_group_order="4.6" + label_min="Coin Purse" + label_max="Duffle Bag" + value_default="0" + value_min="-.5" + value_max="2" + camera_angle="60" + camera_distance=".6"> + <param_driver> + <driven + id="20879" /> + + <driven + id="30879" /> + </param_driver> + </param> + + <param id="841" group="0" name="Bowed_Legs" @@ -11302,6 +15286,10 @@ render_pass="bump"> <driven id="1001" /> + + <driven + id="30119" /> + </param_driver> </param> @@ -11766,6 +15754,8 @@ render_pass="bump"> <param_driver> <driven id="870" /> + <driven + id="30016"/> </param_driver> </param> @@ -11789,6 +15779,8 @@ render_pass="bump"> <param_driver> <driven id="871" /> + <driven + id="30757"/> </param_driver> </param> @@ -11811,6 +15803,8 @@ render_pass="bump"> <param_driver> <driven id="872" /> + <driven + id="30031"/> </param_driver> </param> diff --git a/indra/newview/character/avatar_skeleton.xml b/indra/newview/character/avatar_skeleton.xml index 6b07bbc1d3..2241a12545 100644 --- a/indra/newview/character/avatar_skeleton.xml +++ b/indra/newview/character/avatar_skeleton.xml @@ -1,81 +1,232 @@ -<?xml version="1.0" encoding="US-ASCII" standalone="yes"?> -<linden_skeleton version="1.0" num_bones="53" num_collision_volumes="26"> -<bone name="mPelvis" pos="0.000 0.000 1.067" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.000000 1.067015"> - <collision_volume name="PELVIS" pos = "-0.01 0 -0.02" rot="0.000000 8.00000 0.000000" scale="0.12 0.16 0.17"/> - <collision_volume name="BUTT" pos = "-0.06 0 -0.1" rot="0.000000 0.00000 0.000000" scale="0.1 0.1 0.1"/> - <bone name="mTorso" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.000000 0.084073"> - <collision_volume name="BELLY" pos = "0.028 0 0.04" rot="0.000000 8.00000 0.000000" scale="0.09 0.13 0.15"/> - <collision_volume name="LOWER_BACK" pos = "0.0 0.0 0.023" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15"/> - <collision_volume name="LEFT_HANDLE" pos = "0.0 0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05"/> - <collision_volume name="RIGHT_HANDLE" pos = "0.0 -0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05"/> - <bone name="mChest" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.015368 0.000000 0.204877"> - <collision_volume name="CHEST" pos = "0.028 0 0.07" rot="0.000000 -10.00000 0.000000" scale="0.11 0.15 0.2"/> - <collision_volume name="UPPER_BACK" pos = "0.0 0.0 0.017" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15"/> - <collision_volume name="LEFT_PEC" pos = "0.119 0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05"/> - <collision_volume name="RIGHT_PEC" pos = "0.119 -0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05"/> - <bone name="mNeck" pos="-0.010 0.000 0.251" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.009507 0.000000 0.251108"> - <collision_volume name="NECK" pos = "0.0 0 0.02" rot="0.000000 0.000000 0.000000" scale="0.05 0.06 0.08"/> - <bone name="mHead" pos="0.000 -0.000 0.076" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 -0.000000 0.075630"> - <collision_volume name="HEAD" pos = "0.02 0 0.07" rot="0.000000 0.000000 0.000000" scale="0.11 0.09 0.12"/> - <bone name="mSkull" pos="0.000 0.000 0.079" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.000000 0.079000"> - </bone> - <bone name="mEyeRight" pos="0.098 -0.036 0.079" rot="0.000000 0.000000 -0.000000" scale="1.000 1.000 1.000" pivot="0.098466 -0.036000 0.079000"> - </bone> - <bone name="mEyeLeft" pos="0.098 0.036 0.079" rot="0.000000 -0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.098461 0.036000 0.079000"> - </bone> - </bone> - </bone> - <bone name="mCollarLeft" pos="-0.021 0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.020927 0.084665 0.165396"> - <collision_volume name="L_CLAVICLE" pos = "0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05"/> - <bone name="mShoulderLeft" pos="0.000 0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.079000 -0.000000"> - <collision_volume name="L_UPPER_ARM" pos = "0.0 0.12 0.01" rot="-5.000000 0.00000 0.000000" scale="0.05 0.17 0.05"/> - <bone name="mElbowLeft" pos="0.000 0.248 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 0.248000 0.000000"> - <collision_volume name="L_LOWER_ARM" pos = "0.0 0.1 0.0" rot="-3.000000 0.00000 0.000000" scale="0.04 0.14 0.04"/> - <bone name="mWristLeft" pos="-0.000 0.205 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.000000 0.204846 0.000000"> - <collision_volume name="L_HAND" pos = "0.01 0.05 0.0" rot="-3.000000 0.00000 -10.000000" scale="0.05 0.08 0.03"/> - </bone> - </bone> - </bone> - </bone> - <bone name="mCollarRight" pos="-0.021 -0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.020927 -0.085000 0.165396"> - <collision_volume name="R_CLAVICLE" pos = "0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05"/> - <bone name="mShoulderRight" pos="0.000 -0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 -0.079418 -0.000000"> - <collision_volume name="R_UPPER_ARM" pos = "0.0 -0.12 0.01" rot="5.000000 0.00000 0.000000" scale="0.05 0.17 0.05"/> - <bone name="mElbowRight" pos="0.000 -0.248 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.000000 -0.248000 -0.000000"> - <collision_volume name="R_LOWER_ARM" pos = "0.0 -0.1 0.0" rot="3.000000 0.00000 0.000000" scale="0.04 0.14 0.04"/> - <bone name="mWristRight" pos="0.000 -0.205 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.000000 -0.205000 -0.000000"> - <collision_volume name="R_HAND" pos = "0.01 -0.05 0.0" rot="3.000000 0.00000 10.000000" scale="0.05 0.08 0.03"/> - </bone> - </bone> - </bone> - </bone> - </bone> - </bone> - <bone name="mHipRight" pos="0.034 -0.129 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.033620 -0.128806 -0.041086"> - <collision_volume name="R_UPPER_LEG" pos = "-0.02 0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32"/> - <bone name="mKneeRight" pos="-0.001 0.049 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.000780 0.048635 -0.490922"> - <collision_volume name="R_LOWER_LEG" pos = "-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25"/> - <bone name="mAnkleRight" pos="-0.029 0.000 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.028869 0.000000 -0.468494"> - <collision_volume name="R_FOOT" pos = "0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05"/> - <bone name="mFootRight" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.111956 -0.000000 -0.060637"> - <bone name="mToeRight" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.105399 -0.010408 -0.000104"> - </bone> - </bone> - </bone> - </bone> - </bone> - <bone name="mHipLeft" pos="0.034 0.127 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.033757 0.126765 -0.040998"> - <collision_volume name="L_UPPER_LEG" pos = "-0.02 -0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32"/> - <bone name="mKneeLeft" pos="-0.001 -0.046 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.000887 -0.045568 -0.491053"> - <collision_volume name="L_LOWER_LEG" pos = "-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25"/> - <bone name="mAnkleLeft" pos="-0.029 0.001 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="-0.028887 0.001378 -0.468449"> - <collision_volume name="L_FOOT" pos = "0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05"/> - <bone name="mFootLeft" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.111956 -0.000000 -0.060620"> - <bone name="mToeLeft" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" pivot="0.105387 0.008270 0.000871"> - </bone> - </bone> - </bone> - </bone> - </bone> -</bone> -</linden_skeleton>
\ No newline at end of file +<linden_skeleton num_bones="133" num_collision_volumes="26" version="2.0"> + <bone aliases="hip avatar_mPelvis" connected="false" end="0.000 0.000 0.084" group="Torso" name="mPelvis" pivot="0.000000 0.000000 1.067015" pos="0.000 0.000 1.067" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.030 0.000 0.095" group="Collision" name="PELVIS" pos="-0.01 0 -0.02" rot="0.000000 8.00000 0.000000" scale="0.12 0.16 0.17" support="base"/> + <collision_volume end="-0.100 0.000 0.000" group="Collision" name="BUTT" pos="-0.06 0 -0.1" rot="0.000000 0.00000 0.000000" scale="0.1 0.1 0.1" support="base"/> + <bone connected="true" end="0.000 0.000 -0.084" group="Spine" name="mSpine1" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.000 0.000 0.084" group="Spine" name="mSpine2" pivot="0.000000 0.000000 -0.084073" pos="0.000 0.000 -0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"> + <bone aliases="abdomen avatar_mTorso" connected="true" end="-0.015 0.000 0.205" group="Torso" name="mTorso" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.028 0.000 0.094" group="Collision" name="BELLY" pos="0.028 0 0.04" rot="0.000000 8.00000 0.000000" scale="0.09 0.13 0.15" support="base"/> + <collision_volume end="0.000 0.100 0.000" group="Collision" name="LEFT_HANDLE" pos="0.0 0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base"/> + <collision_volume end="0.000 -0.100 0.000" group="Collision" name="RIGHT_HANDLE" pos="0.0 -0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base"/> + <collision_volume end="-0.100 0.000 0.000" group="Collision" name="LOWER_BACK" pos="0.0 0.0 0.023" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15" support="base"/> + <bone connected="true" end="0.015 0.000 -0.205" group="Spine" name="mSpine3" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.015 0.000 0.205" group="Spine" name="mSpine4" pivot="0.015368 0.000000 -0.204877" pos="0.015 0.000 -0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"> + <bone aliases="chest avatar_mChest" connected="true" end="-0.010 0.000 0.250" group="Torso" name="mChest" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="-0.096 0.000 0.152" group="Collision" name="CHEST" pos="0.028 0 0.07" rot="0.000000 -10.00000 0.000000" scale="0.11 0.15 0.2" support="base"/> + <collision_volume end="0.080 0.000 -0.006" group="Collision" name="LEFT_PEC" pos="0.119 0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05" support="base"/> + <collision_volume end="0.080 0.000 -0.006" group="Collision" name="RIGHT_PEC" pos="0.119 -0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05" support="base"/> + <collision_volume end="-0.100 0.000 0.000" group="Collision" name="UPPER_BACK" pos="0.0 0.0 0.017" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15" support="base"/> + <bone aliases="neck avatar_mNeck" connected="true" end="0.000 0.000 0.077" group="Torso" name="mNeck" pivot="-0.009507 0.000000 0.251108" pos="-0.010 0.000 0.251" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 0.000 0.080" group="Collision" name="NECK" pos="0.0 0 0.02" rot="0.000000 0.000000 0.000000" scale="0.05 0.06 0.08" support="base"/> + <bone aliases="head avatar_mHead" connected="true" end="0.000 0.000 0.079" group="Torso" name="mHead" pivot="0.000000 -0.000000 0.075630" pos="0.000 -0.000 0.076" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 0.000 0.100" group="Collision" name="HEAD" pos="0.02 0 0.07" rot="0.000000 0.000000 0.000000" scale="0.11 0.09 0.12" support="base"/> + <bone aliases="figureHair avatar_mSkull" connected="false" end="0.000 0.000 0.033" group="Extra" name="mSkull" pivot="0.000000 0.000000 0.079000" pos="0.000 0.000 0.079" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/> + <bone aliases="avatar_mEyeRight" connected="false" end="0.025 0.000 0.000" group="Extra" name="mEyeRight" pivot="0.098466 -0.036000 0.079000" pos="0.098 -0.036 0.079" rot="0.000000 0.000000 -0.000000" scale="1.000 1.000 1.000" support="base"/> + <bone aliases="avatar_mEyeLeft" connected="false" end="0.025 0.000 0.000" group="Extra" name="mEyeLeft" pivot="0.098461 0.036000 0.079000" pos="0.098 0.036 0.079" rot="0.000000 -0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/> + <bone connected="false" end="0.020 0.000 0.000" group="Face" name="mFaceRoot" pivot="0.025000 0.000000 0.045000" pos="0.025 0.000 0.045" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltRight" pivot="0.073466 -0.036000 0.0339300" pos="0.073 -0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltLeft" pivot="0.073461 0.036000 0.0339300" pos="0.073 0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.024 0.004 0.018" group="Face" name="mFaceForeheadLeft" pivot="0.061 0.035 0.083" pos="0.061 0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.024 -0.004 0.018" group="Face" name="mFaceForeheadRight" pivot="0.061 -0.035 0.083" pos="0.061 -0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.023 0.013 0.000" group="Eyes" name="mFaceEyebrowOuterLeft" pivot="0.064 0.051 0.048" pos="0.064 0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterLeft" pivot="0.070 0.043 0.056" pos="0.070 0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerLeft" pivot="0.075 0.022 0.051" pos="0.075 0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.023 -0.013 0.000" group="Eyes" name="mFaceEyebrowOuterRight" pivot="0.064 -0.051 0.048" pos="0.064 -0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterRight" pivot="0.070 -0.043 0.056" pos="0.070 -0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerRight" pivot="0.075 -0.022 0.051" pos="0.075 -0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="-0.019 0.018 0.025" group="Ears" name="mFaceEar1Left" pivot="0.000 0.080 0.002" pos="0.000 0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Left" pivot="-0.019 0.018 0.025" pos="-0.019 0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + <bone connected="false" end="-0.019 -0.018 0.025" group="Ears" name="mFaceEar1Right" pivot="0.000 -0.080 0.002" pos="0.000 -0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Right" pivot="-0.019 -0.018 0.025" pos="-0.019 -0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + <bone connected="false" end="0.015 0.004 0.000" group="Face" name="mFaceNoseLeft" pivot="0.086 0.015 -0.004" pos="0.086 0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceNoseCenter" pivot="0.102 0.000 0.000" pos="0.102 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.015 -0.004 0.000" group="Face" name="mFaceNoseRight" pivot="0.086 -0.015 -0.004" pos="0.086 -0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.013 0.030 0.000" group="Face" name="mFaceCheekLowerLeft" pivot="0.050 0.034 -0.031" pos="0.050 0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.022 0.015 0.000" group="Face" name="mFaceCheekUpperLeft" pivot="0.070 0.034 -0.005" pos="0.070 0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.013 -0.030 0.000" group="Face" name="mFaceCheekLowerRight" pivot="0.050 -0.034 -0.031" pos="0.050 -0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.022 -0.015 0.000" group="Face" name="mFaceCheekUpperRight" pivot="0.070 -0.034 -0.005" pos="0.070 -0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.059 0.000 -0.039" group="Mouth" name="mFaceJaw" pivot="-0.001 0.000 -0.015" pos="-0.001 0.000 -0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="false" end="0.021 0.000 -0.018" group="Mouth" name="mFaceChin" pivot="0.074 0.000 -0.054" pos="0.074 0.000 -0.054" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethLower" pivot="0.021 0.000 -0.039" pos="0.021 0.000 -0.039" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="false" end="0.034 0.017 0.005" group="Lips" name="mFaceLipLowerLeft" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.034 -0.017 0.005" group="Lips" name="mFaceLipLowerRight" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.040 0.000 0.002" group="Lips" name="mFaceLipLowerCenter" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.022 0.000 0.007" group="Mouth" name="mFaceTongueBase" pivot="0.039 0.000 0.005" pos="0.039 0.000 0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.010 0.000 0.000" group="Mouth" name="mFaceTongueTip" pivot="0.022 0.000 0.007" pos="0.022 0.000 0.007" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + <bone connected="false" end="-0.017 0.000 0.000" group="Face" name="mFaceJawShaper" pivot="0.000 0.000 0.000" pos="0.000 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.036 0.000 0.000" group="Face" name="mFaceForeheadCenter" pivot="0.069 0.000 0.065" pos="0.069 0.000 0.065" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.014 0.000 0.000" group="Nose" name="mFaceNoseBase" pivot="0.094 0.000 -0.016" pos="0.094 0.000 -0.016" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethUpper" pivot="0.020 0.000 -0.030" pos="0.020 0.000 -0.030" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="false" end="0.041 0.015 0.000" group="Lips" name="mFaceLipUpperLeft" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.041 -0.015 0.000" group="Lips" name="mFaceLipUpperRight" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.045 0.051 0.000" group="Lips" name="mFaceLipCornerLeft" pivot="0.028 -0.019 -0.010" pos="0.028 -0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.045 -0.051 0.000" group="Lips" name="mFaceLipCornerRight" pivot="0.028 0.019 -0.010" pos="0.028 0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.043 0.000 0.002" group="Lips" name="mFaceLipUpperCenter" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + <bone connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerLeft" pivot="0.075 0.017 0.032" pos="0.075 0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerRight" pivot="0.075 -0.017 0.032" pos="0.075 -0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="0.015 0.000 0.008" group="Nose" name="mFaceNoseBridge" pivot="0.091 0.000 0.020" pos="0.091 0.000 0.020" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + <bone aliases="lCollar avatar_mCollarLeft" connected="false" end="0.000 0.079 0.000" group="Arms" name="mCollarLeft" pivot="-0.020927 0.084665 0.165396" pos="-0.021 0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 0.100 0.000" group="Collision" name="L_CLAVICLE" pos="0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05" support="base"/> + <bone aliases="lShldr avatar_mShoulderLeft" connected="true" end="0.000 0.247 0.000" group="Arms" name="mShoulderLeft" pivot="0.000000 0.079000 -0.000000" pos="0.000 0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 0.130 -0.003" group="Collision" name="L_UPPER_ARM" pos="0.0 0.12 0.01" rot="-5.000000 0.00000 0.000000" scale="0.05 0.17 0.05" support="base"/> + <bone aliases="lForeArm avatar_mElbowLeft" connected="true" end="0.000 0.205 0.000" group="Arms" name="mElbowLeft" pivot="0.000000 0.248000 0.000000" pos="0.000 0.248 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 0.100 -0.001" group="Collision" name="L_LOWER_ARM" pos="0.0 0.1 0.0" rot="-3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base"/> + <bone aliases="lHand avatar_mWristLeft" connected="true" end="0.000 0.060 0.000" group="Arms" name="mWristLeft" pivot="-0.000000 0.204846 0.000000" pos="-0.000 0.205 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.005 0.049 -0.001" group="Collision" name="L_HAND" pos="0.01 0.05 0.0" rot="-3.000000 0.00000 -10.000000" scale="0.05 0.08 0.03" support="base"/> + <bone connected="false" end="-0.001 0.040 -0.006" group="Hand" name="mHandMiddle1Left" pivot="0.013 0.101 0.015" pos="0.013 0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.001 0.049 -0.008" group="Hand" name="mHandMiddle2Left" pivot="-0.001 0.040 -0.006" pos="-0.001 0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.002 0.033 -0.006" group="Hand" name="mHandMiddle3Left" pivot="-0.001 0.049 -0.008" pos="-0.001 0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + <bone connected="false" end="0.017 0.036 -0.006" group="Hand" name="mHandIndex1Left" pivot="0.038 0.097 0.015" pos="0.038 0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.014 0.032 -0.006" group="Hand" name="mHandIndex2Left" pivot="0.017 0.036 -0.006" pos="0.017 0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.011 0.025 -0.004" group="Hand" name="mHandIndex3Left" pivot="0.014 0.032 -0.006" pos="0.014 0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + <bone connected="false" end="-0.013 0.038 -0.008" group="Hand" name="mHandRing1Left" pivot="-0.010 0.099 0.009" pos="-0.010 0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.013 0.040 -0.009" group="Hand" name="mHandRing2Left" pivot="-0.013 0.038 -0.008" pos="-0.013 0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.010 0.028 -0.006" group="Hand" name="mHandRing3Left" pivot="-0.013 0.040 -0.009" pos="-0.013 0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + <bone connected="false" end="-0.024 0.025 -0.006" group="Hand" name="mHandPinky1Left" pivot="-0.031 0.095 0.003" pos="-0.031 0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.015 0.018 -0.004" group="Hand" name="mHandPinky2Left" pivot="-0.024 0.025 -0.006" pos="-0.024 0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.013 0.016 -0.004" group="Hand" name="mHandPinky3Left" pivot="-0.015 0.018 -0.004" pos="-0.015 0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + <bone connected="false" end="0.028 0.032 0.000" group="Hand" name="mHandThumb1Left" pivot="0.031 0.026 0.004" pos="0.031 0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.023 0.031 0.000" group="Hand" name="mHandThumb2Left" pivot="0.028 0.032 -0.001" pos="0.028 0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.015 0.025 0.000" group="Hand" name="mHandThumb3Left" pivot="0.023 0.031 -0.001" pos="0.023 0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + </bone> + </bone> + </bone> + <bone aliases="rCollar avatar_mCollarRight" connected="false" end="0.000 -0.079 0.000" group="Arms" name="mCollarRight" pivot="-0.020927 -0.085000 0.165396" pos="-0.021 -0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 -0.100 0.000" group="Collision" name="R_CLAVICLE" pos="0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05" support="base"/> + <bone aliases="rShldr avatar_mShoulderRight" connected="true" end="0.000 -0.247 0.000" group="Arms" name="mShoulderRight" pivot="0.000000 -0.079418 -0.000000" pos="0.000 -0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 -0.130 -0.003" group="Collision" name="R_UPPER_ARM" pos="0.0 -0.12 0.01" rot="5.000000 0.00000 0.000000" scale="0.05 0.17 0.05" support="base"/> + <bone aliases="rForeArm avatar_mElbowRight" connected="true" end="0.000 -0.205 0.000" group="Arms" name="mElbowRight" pivot="0.000000 -0.248000 -0.000000" pos="0.000 -0.248 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 -0.100 -0.001" group="Collision" name="R_LOWER_ARM" pos="0.0 -0.1 0.0" rot="3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base"/> + <bone aliases="rHand avatar_mWristRight" connected="true" end="0.000 -0.060 0.000" group="Arms" name="mWristRight" pivot="-0.000000 -0.205000 -0.000000" pos="0.000 -0.205 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.005 -0.049 -0.001" group="Collision" name="R_HAND" pos="0.01 -0.05 0.0" rot="3.000000 0.00000 10.000000" scale="0.05 0.08 0.03" support="base"/> + <bone connected="false" end="-0.001 -0.040 -0.006" group="Hand" name="mHandMiddle1Right" pivot="0.013 -0.101 0.015" pos="0.013 -0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.001 -0.049 -0.008" group="Hand" name="mHandMiddle2Right" pivot="-0.001 -0.040 -0.006" pos="-0.001 -0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.002 -0.033 -0.006" group="Hand" name="mHandMiddle3Right" pivot="-0.001 -0.049 -0.008" pos="-0.001 -0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + <bone connected="false" end="0.017 -0.036 -0.006" group="Hand" name="mHandIndex1Right" pivot="0.038 -0.097 0.015" pos="0.038 -0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.014 -0.032 -0.006" group="Hand" name="mHandIndex2Right" pivot="0.017 -0.036 -0.006" pos="0.017 -0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.011 -0.025 -0.004" group="Hand" name="mHandIndex3Right" pivot="0.014 -0.032 -0.006" pos="0.014 -0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + <bone connected="false" end="-0.013 -0.038 -0.008" group="Hand" name="mHandRing1Right" pivot="-0.010 -0.099 0.009" pos="-0.010 -0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.013 -0.040 -0.009" group="Hand" name="mHandRing2Right" pivot="-0.013 -0.038 -0.008" pos="-0.013 -0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.010 -0.028 -0.006" group="Hand" name="mHandRing3Right" pivot="-0.013 -0.040 -0.009" pos="-0.013 -0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + <bone connected="false" end="-0.024 -0.025 -0.006" group="Hand" name="mHandPinky1Right" pivot="-0.031 -0.095 0.003" pos="-0.031 -0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.015 -0.018 -0.004" group="Hand" name="mHandPinky2Right" pivot="-0.024 -0.025 -0.006" pos="-0.024 -0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.013 -0.016 -0.004" group="Hand" name="mHandPinky3Right" pivot="-0.015 -0.018 -0.004" pos="-0.015 -0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + <bone connected="false" end="0.028 -0.032 0.000" group="Hand" name="mHandThumb1Right" pivot="0.031 -0.026 0.004" pos="0.031 -0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.023 -0.031 0.000" group="Hand" name="mHandThumb2Right" pivot="0.028 -0.032 -0.001" pos="0.028 -0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.015 -0.025 0.000" group="Hand" name="mHandThumb3Right" pivot="0.023 -0.031 -0.001" pos="0.023 -0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + </bone> + </bone> + </bone> + <bone connected="false" end="-0.061 0.000 0.000" group="Wing" name="mWingsRoot" pivot="-0.014 0.000 0.000" pos="-0.014 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="false" end="-0.168 0.169 0.067" group="Wing" name="mWing1Left" pivot="-0.099 0.105 0.181" pos="-0.099 0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.181 0.183 0.000" group="Wing" name="mWing2Left" pivot="-0.168 0.169 0.067" pos="-0.168 0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.171 0.173 0.000" group="Wing" name="mWing3Left" pivot="-0.181 0.183 0.000" pos="-0.181 0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.146 0.132 0.000" group="Wing" name="mWing4Left" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="true" end="-0.068 0.062 -0.159" group="Wing" name="mWing4FanLeft" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + <bone connected="false" end="-0.168 -0.169 0.067" group="Wing" name="mWing1Right" pivot="-0.099 -0.105 0.181" pos="-0.099 -0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.181 -0.183 0.000" group="Wing" name="mWing2Right" pivot="-0.168 -0.169 0.067" pos="-0.168 -0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.171 -0.173 0.000" group="Wing" name="mWing3Right" pivot="-0.181 -0.183 0.000" pos="-0.181 -0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.146 -0.132 0.000" group="Wing" name="mWing4Right" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="true" end="-0.068 -0.062 -0.159" group="Wing" name="mWing4FanRight" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + </bone> + </bone> + </bone> + </bone> + </bone> + </bone> + </bone> + <bone aliases="rThigh avatar_mHipRight" connected="false" end="-0.001 0.049 -0.491" group="Legs" name="mHipRight" pivot="0.033620 -0.128806 -0.041086" pos="0.034 -0.129 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 0.000 -0.200" group="Collision" name="R_UPPER_LEG" pos="-0.02 0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32" support="base"/> + <bone aliases="rShin avatar_mKneeRight" connected="true" end="-0.029 0.000 -0.469" group="Legs" name="mKneeRight" pivot="-0.000780 0.048635 -0.490922" pos="-0.001 0.049 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="-0.010 0.000 -0.150" group="Collision" name="R_LOWER_LEG" pos="-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25" support="base"/> + <bone aliases="rFoot avatar_mAnkleRight" connected="true" end="0.112 0.000 -0.061" group="Legs" name="mAnkleRight" pivot="-0.028869 0.000000 -0.468494" pos="-0.029 0.000 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.089 0.000 -0.026" group="Collision" name="R_FOOT" pos="0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05" support="base"/> + <bone aliases="avatar_mFootRight" connected="true" end="0.105 -0.010 0.000" group="Extra" name="mFootRight" pivot="0.111956 -0.000000 -0.060637" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <bone aliases="avatar_mToeRight" connected="false" end="0.020 0.000 0.000" group="Extra" name="mToeRight" pivot="0.105399 -0.010408 -0.000104" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/> + </bone> + </bone> + </bone> + </bone> + <bone aliases="lThigh avatar_mHipLeft" connected="false" end="-0.001 -0.046 -0.491" group="Legs" name="mHipLeft" pivot="0.033757 0.126765 -0.040998" pos="0.034 0.127 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.000 0.000 -0.200" group="Collision" name="L_UPPER_LEG" pos="-0.02 -0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32" support="base"/> + <bone aliases="lShin avatar_mKneeLeft" connected="true" end="-0.029 0.001 -0.469" group="Legs" name="mKneeLeft" pivot="-0.000887 -0.045568 -0.491053" pos="-0.001 -0.046 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="-0.010 0.000 -0.150" group="Collision" name="L_LOWER_LEG" pos="-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25" support="base"/> + <bone aliases="lFoot avatar_mAnkleLeft" connected="true" end="0.112 0.000 -0.061" group="Legs" name="mAnkleLeft" pivot="-0.028887 0.001378 -0.468449" pos="-0.029 0.001 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <collision_volume end="0.089 0.000 -0.026" group="Collision" name="L_FOOT" pos="0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05" support="base"/> + <bone aliases="avatar_mFootLeft" connected="true" end="0.105 0.008 0.001" group="Extra" name="mFootLeft" pivot="0.111956 -0.000000 -0.060620" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"> + <bone aliases="avatar_mToeLeft" connected="false" end="0.020 0.000 0.000" group="Extra" name="mToeLeft" pivot="0.105387 0.008270 0.000871" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/> + </bone> + </bone> + </bone> + </bone> + <bone connected="false" end="-0.197 0.000 0.000" group="Tail" name="mTail1" pivot="-0.116 0.000 0.047" pos="-0.116 0.000 0.047" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.168 0.000 0.000" group="Tail" name="mTail2" pivot="-0.197 0.000 0.000" pos="-0.197 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.142 0.000 0.000" group="Tail" name="mTail3" pivot="-0.168 0.000 0.000" pos="-0.168 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.112 0.000 0.000" group="Tail" name="mTail4" pivot="-0.142 0.000 0.000" pos="-0.142 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.094 0.000 0.000" group="Tail" name="mTail5" pivot="-0.112 0.000 0.000" pos="-0.112 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.089 0.000 0.000" group="Tail" name="mTail6" pivot="-0.094 0.000 0.000" pos="-0.094 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + </bone> + </bone> + <bone connected="false" end="0.004 0.000 -0.066" group="Groin" name="mGroin" pivot="0.064 0.000 -0.097" pos="0.064 0.000 -0.097" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + <bone connected="false" end="-0.204 0.000 0.000" group="Limb" name="mHindLimbsRoot" pivot="-0.200 0.000 0.084" pos="-0.200 0.000 0.084" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="false" end="0.002 -0.046 -0.491" group="Limb" name="mHindLimb1Left" pivot="-0.204 0.129 -0.125" pos="-0.204 0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.030 -0.003 -0.468" group="Limb" name="mHindLimb2Left" pivot="0.002 -0.046 -0.491" pos="0.002 -0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Left" pivot="-0.030 -0.003 -0.468" pos="-0.030 -0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.105 0.008 0.000" group="Limb" name="mHindLimb4Left" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + <bone connected="false" end="0.002 0.046 -0.491" group="Limb" name="mHindLimb1Right" pivot="-0.204 -0.129 -0.125" pos="-0.204 -0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="-0.030 0.003 -0.468" group="Limb" name="mHindLimb2Right" pivot="0.002 0.046 -0.491" pos="0.002 0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Right" pivot="-0.030 0.003 -0.468" pos="-0.030 0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"> + <bone connected="true" end="0.105 -0.008 0.000" group="Limb" name="mHindLimb4Right" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/> + </bone> + </bone> + </bone> + </bone> + </bone> +</linden_skeleton> diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 92a5413adb..1dddf52961 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -31,6 +31,8 @@ #include "llcoros.h" #include "lleventcoro.h" #include "llcorehttputil.h" +#include "llexception.h" +#include "stringize.h" #include <algorithm> #include <iterator> @@ -154,13 +156,11 @@ void LLAccountingCostManager::accountingCostCoro(std::string url, } while (false); } - catch (std::exception e) - { - LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL; - } catch (...) { - LL_WARNS() << "Caught unknown exception." << LL_ENDL; + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName() + << "('" << url << "')")); + throw; } mPendingObjectQuota.clear(); diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index d933537d2e..66e2d6fa6a 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3895,11 +3895,17 @@ void LLAgent::handleTeleportFinished() mIsMaturityRatingChangingDuringTeleport = false; } - // Init SLM Marketplace connection so we know which UI should be used for the user as a merchant - // Note: Eventually, all merchant will be migrated to the new SLM system and there will be no reason to show the old UI at all. - // Note: Some regions will not support the SLM cap for a while so we need to do that check for each teleport. - // *TODO : Suppress that line from here once the whole grid migrated to SLM and move it to idle_startup() (llstartup.cpp) - check_merchant_status(); + if (mRegionp) + { + if (mRegionp->capabilitiesReceived()) + { + onCapabilitiesReceivedAfterTeleport(); + } + else + { + mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::onCapabilitiesReceivedAfterTeleport)); + } + } } void LLAgent::handleTeleportFailed() @@ -3931,6 +3937,14 @@ void LLAgent::handleTeleportFailed() } } +/*static*/ +void LLAgent::onCapabilitiesReceivedAfterTeleport() +{ + + check_merchant_status(); +} + + void LLAgent::teleportRequest( const U64& region_handle, const LLVector3& pos_local, @@ -4176,6 +4190,8 @@ void LLAgent::setTeleportState(ETeleportState state) void LLAgent::stopCurrentAnimations() { + LL_DEBUGS("Avatar") << "Stopping current animations" << LL_ENDL; + // This function stops all current overriding animations on this // avatar, propagating this change back to the server. if (isAgentAvatarValid()) @@ -4193,6 +4209,7 @@ void LLAgent::stopCurrentAnimations() // don't cancel a ground-sit anim, as viewers // use this animation's status in // determining whether we're sitting. ick. + LL_DEBUGS("Avatar") << "sit or do-not-disturb animation will not be stopped" << LL_ENDL; } else { @@ -4222,8 +4239,7 @@ void LLAgent::stopCurrentAnimations() // re-assert at least the default standing animation, because // viewers get confused by avs with no associated anims. - sendAnimationRequest(ANIM_AGENT_STAND, - ANIM_REQUEST_START); + sendAnimationRequest(ANIM_AGENT_STAND, ANIM_REQUEST_START); } } diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 3a533c2cba..d82ff7a67f 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -676,6 +676,8 @@ private: void handleTeleportFinished(); void handleTeleportFailed(); + static void onCapabilitiesReceivedAfterTeleport(); + //-------------------------------------------------------------------- // Teleport State //-------------------------------------------------------------------- diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index fa16f02c16..e335eabd1a 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -1448,6 +1448,7 @@ void LLAgentCamera::updateCamera() diff.mV[VZ] = 0.f; } + // SL-315 gAgentAvatarp->mPelvisp->setPosition(gAgentAvatarp->mPelvisp->getPosition() + diff); gAgentAvatarp->mRoot->updateWorldMatrixChildren(); @@ -2144,6 +2145,7 @@ void LLAgentCamera::changeCameraToFollow(BOOL animate) if (isAgentAvatarValid()) { + // SL-315 gAgentAvatarp->mPelvisp->setPosition(LLVector3::zero); gAgentAvatarp->startMotion( ANIM_AGENT_BODY_NOISE ); gAgentAvatarp->startMotion( ANIM_AGENT_BREATHE_ROT ); @@ -2184,6 +2186,7 @@ void LLAgentCamera::changeCameraToThirdPerson(BOOL animate) { if (!gAgentAvatarp->isSitting()) { + // SL-315 gAgentAvatarp->mPelvisp->setPosition(LLVector3::zero); } gAgentAvatarp->startMotion(ANIM_AGENT_BODY_NOISE); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index b76a66ab39..170e4063a1 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -62,23 +62,37 @@ using namespace LLAvatarAppearanceDefines; /////////////////////////////////////////////////////////////////////////////// -// Callback to wear and start editing an item that has just been created. -void wear_and_edit_cb(const LLUUID& inv_item) +void set_default_permissions(LLViewerInventoryItem* item) { - if (inv_item.isNull()) return; - - LLViewerInventoryItem* item = gInventory.getItem(inv_item); - if (!item) return; - - LLPermissions perm = item->getPermissions(); + llassert(item); + LLPermissions perm = item->getPermissions(); + if (perm.getMaskNextOwner() != LLFloaterPerms::getNextOwnerPerms("Wearables") + || perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms("Wearables") + || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms("Wearables")) + { perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables")); perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables")); perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables")); + item->setPermissions(perm); item->updateServer(FALSE); - gInventory.updateItem(item); - gInventory.notifyObservers(); + } +} + +// Callback to wear and start editing an item that has just been created. +void wear_and_edit_cb(const LLUUID& inv_item) +{ + if (inv_item.isNull()) return; + + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (!item) return; + + set_default_permissions(item); + + // item was just created, update even if permissions did not changed + gInventory.updateItem(item); + gInventory.notifyObservers(); // Request editing the item after it gets worn. gAgentWearables.requestEditingWearable(inv_item); @@ -94,13 +108,8 @@ void wear_cb(const LLUUID& inv_item) LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (item) { - LLPermissions perm = item->getPermissions(); - perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables")); - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables")); - item->setPermissions(perm); + set_default_permissions(item); - item->updateServer(FALSE); gInventory.updateItem(item); gInventory.notifyObservers(); } @@ -253,6 +262,7 @@ void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& i { LLAppearanceMgr::instance().addCOFItemLink(inv_item, new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription); + editWearable(inv_item); } } @@ -423,7 +433,7 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, // old_wearable may still be referred to by other inventory items. Revert // unsaved changes so other inventory items aren't affected by the changes // that were just saved. - old_wearable->revertValues(); + old_wearable->revertValuesWithoutUpdate(); } void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index) @@ -1364,6 +1374,30 @@ void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array // LL_INFOS() << "remove " << remove_count << " add " << add_count << LL_ENDL; } +std::vector<LLViewerObject*> LLAgentWearables::getTempAttachments() +{ + llvo_vec_t temp_attachs; + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); iter != gAgentAvatarp->mAttachmentPoints.end();) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *objectp = (*attachment_iter); + if (objectp && objectp->isTempAttachment()) + { + temp_attachs.push_back(objectp); + } + } + } + } + return temp_attachs; +} + void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remove) { if (!isAgentAvatarValid()) return; diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 1004482020..b27698fd8f 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -185,6 +185,8 @@ public: static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array); static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); + static llvo_vec_t getTempAttachments(); + //-------------------------------------------------------------------- // Signals //-------------------------------------------------------------------- diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index dbcae57de7..c1f898284a 100644 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -30,6 +30,8 @@ #include "llappviewer.h" #include "llviewercontrol.h" +#include "llexception.h" +#include "stringize.h" #include <openssl/x509_vfy.h> #include <openssl/ssl.h> @@ -551,6 +553,7 @@ LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url, } catch (...) { + LOG_UNHANDLED_EXCEPTION(STRINGIZE("('" << url << "')")); // any other odd error, we just handle as a connect error. result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CONNECT_ERROR); } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index ff5439d610..4d6d7a9d89 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -857,7 +857,7 @@ void LLWearableHoldingPattern::onAllComplete() // attachments, even those that are not being removed. This is // needed to get joint positions all slammed down to their // pre-attachment states. - gAgentAvatarp->clearAttachmentPosOverrides(); + gAgentAvatarp->clearAttachmentOverrides(); if (objects_to_remove.size() || items_to_add.size()) { @@ -880,7 +880,7 @@ void LLWearableHoldingPattern::onAllComplete() ++it) { LLViewerObject *objectp = *it; - gAgentAvatarp->addAttachmentPosOverridesForObject(objectp); + gAgentAvatarp->addAttachmentOverridesForObject(objectp); } // Add new attachments to match those requested. @@ -1875,15 +1875,15 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) return false; } - // Check whether the outfit contains any wearables we aren't wearing already (STORM-702). + // Check whether the outfit contains any wearables LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; - LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); + LLFindWearables is_wearable; gInventory.collectDescendentsIf(outfit_cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, - is_worn); + is_wearable); return items.size() > 0; } @@ -3477,13 +3477,13 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd } else { - if (cofVersion < lastRcv) + if (cofVersion <= lastRcv) { LL_WARNS("Avatar") << "Have already received update for cof version " << lastRcv << " but requesting for " << cofVersion << LL_ENDL; return; } - if (lastReq > cofVersion) + if (lastReq >= cofVersion) { LL_WARNS("Avatar") << "Request already in flight for cof version " << lastReq << " but requesting for " << cofVersion << LL_ENDL; @@ -3503,7 +3503,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd LL_WARNS("Avatar") << "Forcing version failure on COF Baking" << LL_ENDL; } - LL_INFOS() << "Requesting bake for COF version " << cofVersion << LL_ENDL; + LL_INFOS("Avatar") << "Requesting bake for COF version " << cofVersion << LL_ENDL; LLSD postData; if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) @@ -3969,6 +3969,10 @@ void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val) LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL; mAttachmentInvLinkEnabled = val; } +boost::signals2::connection LLAppearanceMgr::setAttachmentsChangedCallback(attachments_changed_callback_t cb) +{ + return mAttachmentsChangeSignal.connect(cb); +} void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg) { @@ -3995,6 +3999,8 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id) gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); LLAttachmentsMgr::instance().onAttachmentArrived(item_id); + + mAttachmentsChangeSignal(); } void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) @@ -4015,6 +4021,8 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) { //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL; } + + mAttachmentsChangeSignal(); } BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 2e570b9188..f0d3f80f59 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -229,6 +229,10 @@ public: void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; } std::string getAppearanceServiceURL() const; + typedef boost::function<void ()> attachments_changed_callback_t; + typedef boost::signals2::signal<void ()> attachments_changed_signal_t; + boost::signals2::connection setAttachmentsChangedCallback(attachments_changed_callback_t cb); + private: @@ -272,6 +276,8 @@ private: LLTimer mInFlightTimer; static bool mActive; + attachments_changed_signal_t mAttachmentsChangeSignal; + LLUUID mCOFImageID; std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 72e5eefc49..a0ebae119e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -99,6 +99,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" +#include "llskinningutil.h" // Linden library includes #include "llavatarnamecache.h" @@ -125,7 +126,10 @@ #include "llexception.h" #if !LL_LINUX #include "cef/llceflib.h" -#endif +#if LL_WINDOWS +#include "vlc/libvlc_version.h" +#endif // LL_WINDOWS +#endif // LL_LINUX // Third party library includes #include <boost/bind.hpp> @@ -698,7 +702,8 @@ LLAppViewer::LLAppViewer() mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)), mFastTimerLogThread(NULL), mUpdater(new LLUpdaterService()), - mSettingsLocationList(NULL) + mSettingsLocationList(NULL), + mIsFirstRun(false) { if(NULL != sInstance) { @@ -798,6 +803,9 @@ bool LLAppViewer::init() LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; + // initialize skinning util + LLSkinningUtil::initClass(); + //set the max heap size. initMaxHeapSize() ; LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); @@ -924,7 +932,7 @@ bool LLAppViewer::init() // Provide the text fields with callbacks for opening Urls LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null)); - LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null)); + LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null, false)); LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null)); LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); @@ -1121,17 +1129,23 @@ bool LLAppViewer::init() #if LL_WINDOWS if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion()) { + std::string url; if (gGLManager.mIsIntel) { - LLNotificationsUtil::add("IntelOldDriver"); + url = LLTrans::getString("IntelDriverPage"); } else if (gGLManager.mIsNVIDIA) { - LLNotificationsUtil::add("NVIDIAOldDriver"); + url = LLTrans::getString("NvidiaDriverPage"); } else if (gGLManager.mIsATI) { - LLNotificationsUtil::add("AMDOldDriver"); + url = LLTrans::getString("AMDDriverPage"); + } + + if (!url.empty()) + { + LLNotificationsUtil::add("OldGPUDriver", LLSD().with("URL", url)); } } #endif @@ -1219,6 +1233,8 @@ bool LLAppViewer::init() boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1), boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS)); + showReleaseNotesIfRequired(); + /*----------------------------------------------------------------------*/ // nat 2016-06-29 moved the following here from the former mainLoop(). mMainloopTimeout = new LLWatchdogTimeout(); @@ -1540,10 +1556,14 @@ bool LLAppViewer::frame() resumeMainloopTimeout(); pingMainloopTimeout("Main:End"); - } + } + } + catch (const LLContinueError&) + { + LOG_UNHANDLED_EXCEPTION(""); } catch(std::bad_alloc) - { + { LLMemory::logMemoryInfo(TRUE) ; //stop memory leaking simulation @@ -1551,7 +1571,7 @@ bool LLAppViewer::frame() LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); if(mem_leak_instance) { - mem_leak_instance->stop() ; + mem_leak_instance->stop() ; LL_WARNS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL ; } else @@ -1562,6 +1582,10 @@ bool LLAppViewer::frame() LL_ERRS() << "Bad memory allocation in LLAppViewer::frame()!" << LL_ENDL ; } } + catch (...) + { + CRASH_ON_UNHANDLED_EXCEPTION(""); + } if (LLApp::isExiting()) { @@ -1575,7 +1599,7 @@ bool LLAppViewer::frame() catch(std::bad_alloc) { LL_WARNS() << "Bad memory allocation when saveFinalSnapshot() is called!" << LL_ENDL ; - + //stop memory leaking simulation LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); @@ -1584,12 +1608,16 @@ bool LLAppViewer::frame() mem_leak_instance->stop() ; } } + catch (...) + { + CRASH_ON_UNHANDLED_EXCEPTION("saveFinalSnapshot()"); + } } - + delete gServicePump; - + destroyMainloopTimeout(); - + LL_INFOS() << "Exiting main_loop" << LL_ENDL; } @@ -2458,7 +2486,10 @@ bool LLAppViewer::initConfiguration() if (gSavedSettings.getBOOL("FirstRunThisInstall")) { - // Note that the "FirstRunThisInstall" settings is currently unused. + // Set firstrun flag to indicate that some further init actiona should be taken + // like determining screen DPI value and so on + mIsFirstRun = true; + gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); } @@ -3115,7 +3146,8 @@ bool LLAppViewer::initWindow() .min_width(gSavedSettings.getU32("MinWindowWidth")) .min_height(gSavedSettings.getU32("MinWindowHeight")) .fullscreen(gSavedSettings.getBOOL("FullScreen")) - .ignore_pixel_depth(ignorePixelDepth); + .ignore_pixel_depth(ignorePixelDepth) + .first_run(mIsFirstRun); gViewerWindow = new LLViewerWindow(window_params); @@ -3317,6 +3349,19 @@ LLSD LLAppViewer::getViewerInfo() const info["LLCEFLIB_VERSION"] = LLCEFLIB_VERSION; #else info["LLCEFLIB_VERSION"] = "Undefined"; + +#endif + +#if LL_WINDOWS + std::ostringstream ver_codec; + ver_codec << LIBVLC_VERSION_MAJOR; + ver_codec << "."; + ver_codec << LIBVLC_VERSION_MINOR; + ver_codec << "."; + ver_codec << LIBVLC_VERSION_REVISION; + info["LIBVLC_VERSION"] = ver_codec.str(); +#else + info["LIBVLC_VERSION"] = "Undefined"; #endif S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN); @@ -5521,7 +5566,7 @@ void LLAppViewer::forceErrorInfiniteLoop() void LLAppViewer::forceErrorSoftwareException() { LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL; - BOOST_THROW_EXCEPTION(LLException("User selected Force Software Exception")); + LLTHROW(LLException("User selected Force Software Exception")); } void LLAppViewer::forceErrorDriverCrash() @@ -5773,6 +5818,20 @@ void LLAppViewer::launchUpdater() // LLAppViewer::instance()->forceQuit(); } +/** +* Check if user is running a new version of the viewer. +* Display the Release Notes if it's not overriden by the "UpdaterShowReleaseNotes" setting. +*/ +void LLAppViewer::showReleaseNotesIfRequired() +{ + if (LLVersionInfo::getChannelAndVersion() != gLastRunVersion + && gSavedSettings.getBOOL("UpdaterShowReleaseNotes") + && !gSavedSettings.getBOOL("FirstLoginThisInstall")) + { + LLSD info(getViewerInfo()); + LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]); + } +} //virtual void LLAppViewer::setMasterSystemAudioMute(bool mute) @@ -5805,7 +5864,6 @@ void LLAppViewer::metricsUpdateRegion(U64 region_handle) } } - /** * Attempts to start a multi-threaded metrics report to be sent back to * the grid for consumption. @@ -5823,6 +5881,11 @@ void LLAppViewer::metricsSend(bool enable_reporting) { std::string caps_url = regionp->getCapability("ViewerMetrics"); + if (gSavedSettings.getBOOL("QAModeMetrics")) + { + dump_sequential_xml("metric_asset_stats",gViewerAssetStats->asLLSD(true)); + } + // Make a copy of the main stats to send into another thread. // Receiving thread takes ownership. LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStats)); diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index f7c1bb58b4..948d316009 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -254,6 +254,8 @@ private: void sendLogoutRequest(); void disconnectViewer(); + + void showReleaseNotesIfRequired(); // *FIX: the app viewer class should be some sort of singleton, no? // Perhaps its child class is the singleton and this should be an abstract base. @@ -315,6 +317,7 @@ private: // llcorehttp library init/shutdown helper LLAppCoreHttp mAppCoreHttp; + bool mIsFirstRun; //--------------------------------------------- //*NOTE: Mani - legacy updater stuff // Still useable? diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index a7f248ab5a..5107030476 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -231,6 +231,8 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, DWORD heap_enable_lfh_error[MAX_HEAPS]; S32 num_heaps = 0; + LLWindowWin32::setDPIAwareness(); + #if WINDOWS_CRT_MEM_CHECKS && !INCLUDE_VLD _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); // dump memory leaks on exit #elif 0 @@ -328,33 +330,33 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, // app cleanup if there was a problem. // #if WINDOWS_CRT_MEM_CHECKS - LL_INFOS() << "CRT Checking memory:" << LL_ENDL; - if (!_CrtCheckMemory()) - { - LL_WARNS() << "_CrtCheckMemory() failed at prior to cleanup!" << LL_ENDL; - } - else - { - LL_INFOS() << " No corruption detected." << LL_ENDL; - } + LL_INFOS() << "CRT Checking memory:" << LL_ENDL; + if (!_CrtCheckMemory()) + { + LL_WARNS() << "_CrtCheckMemory() failed at prior to cleanup!" << LL_ENDL; + } + else + { + LL_INFOS() << " No corruption detected." << LL_ENDL; + } #endif - - gGLActive = TRUE; - viewer_app_ptr->cleanup(); - + gGLActive = TRUE; + + viewer_app_ptr->cleanup(); + #if WINDOWS_CRT_MEM_CHECKS - LL_INFOS() << "CRT Checking memory:" << LL_ENDL; - if (!_CrtCheckMemory()) - { - LL_WARNS() << "_CrtCheckMemory() failed after cleanup!" << LL_ENDL; - } - else - { - LL_INFOS() << " No corruption detected." << LL_ENDL; - } + LL_INFOS() << "CRT Checking memory:" << LL_ENDL; + if (!_CrtCheckMemory()) + { + LL_WARNS() << "_CrtCheckMemory() failed after cleanup!" << LL_ENDL; + } + else + { + LL_INFOS() << " No corruption detected." << LL_ENDL; + } #endif - + } delete viewer_app_ptr; viewer_app_ptr = NULL; @@ -567,7 +569,7 @@ bool LLAppViewerWin32::initHardwareTest() // Do driver verification and initialization based on DirectX // hardware polling and driver versions // - if (FALSE == gSavedSettings.getBOOL("NoHardwareProbe")) + if (TRUE == gSavedSettings.getBOOL("ProbeHardwareOnStartup") && FALSE == gSavedSettings.getBOOL("NoHardwareProbe")) { // per DEV-11631 - disable hardware probing for everything // but vram. diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index a6e745448a..7b8c630837 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -950,15 +950,22 @@ bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NUL const std::set<LLFolderViewItem*> inventory_selected = root_folder->getSelectionList(); if (inventory_selected.empty()) return false; // nothing selected + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); bool can_share = true; std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin(); const std::set<LLFolderViewItem*>::const_iterator it_end = inventory_selected.end(); for (; it != it_end; ++it) { - LLViewerInventoryCategory* inv_cat = gInventory.getCategory(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID()); - // any category can be offered. + LLUUID cat_id = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID(); + LLViewerInventoryCategory* inv_cat = gInventory.getCategory(cat_id); + // any category can be offered if it's not in trash. if (inv_cat) { + if ((cat_id == trash_id) || gInventory.isObjectDescendentOf(cat_id, trash_id)) + { + can_share = false; + break; + } continue; } diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp index 5431daca32..7413dbed20 100644 --- a/indra/newview/llavatarrenderinfoaccountant.cpp +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -354,7 +354,7 @@ void LLAvatarRenderInfoAccountant::resetRenderInfoScanTimer() // are returned for a new LLViewerRegion, and is the earliest time to get render info void LLAvatarRenderInfoAccountant::scanNewRegion(const LLUUID& region_id) { - LL_INFOS("AvatarRenderInfo") << region_id << LL_ENDL; + LL_DEBUGS("AvatarRenderInfo") << region_id << LL_ENDL; // Reset the global timer so it will scan regions on the next call to ::idle LLAvatarRenderInfoAccountant::getInstance()->resetRenderInfoScanTimer(); diff --git a/indra/newview/llavatarrendernotifier.cpp b/indra/newview/llavatarrendernotifier.cpp index 24934fdb73..94584a623b 100644 --- a/indra/newview/llavatarrendernotifier.cpp +++ b/indra/newview/llavatarrendernotifier.cpp @@ -38,6 +38,7 @@ #include "llnotifications.h" #include "llnotificationsutil.h" #include "llnotificationtemplate.h" +#include "llslurl.h" #include "lltimer.h" #include "llvoavatarself.h" #include "llviewercontrol.h" @@ -51,6 +52,11 @@ static const F32 RENDER_ALLOWED_CHANGE_PCT = 0.1; // wait seconds before processing over limit updates after last complexity change static const U32 OVER_LIMIT_UPDATE_DELAY = 70; +static const U32 WARN_HUD_OBJECTS_LIMIT = 1000; +static const U32 WARN_HUD_TEXTURES_LIMIT = 200; +static const U32 WARN_HUD_OVERSIZED_TEXTURES_LIMIT = 6; +static const U32 WARN_HUD_TEXTURE_MEMORY_LIMIT = 32000000; // in bytes + LLAvatarRenderNotifier::LLAvatarRenderNotifier() : mAgentsCount(0), @@ -264,3 +270,220 @@ void LLAvatarRenderNotifier::updateNotificationAgent(U32 agentComplexity) } } +// LLHUDRenderNotifier + +static const char* e_hud_messages[] = +{ + "hud_render_textures_warning", + "hud_render_cramped_warning", + "hud_render_heavy_textures_warning", + "hud_render_cost_warning", + "hud_render_memory_warning", +}; + +LLHUDRenderNotifier::LLHUDRenderNotifier() : +mReportedHUDWarning(WARN_NONE) +{ +} + +LLHUDRenderNotifier::~LLHUDRenderNotifier() +{ +} + +void LLHUDRenderNotifier::updateNotificationHUD(hud_complexity_list_t complexity) +{ + if (!isAgentAvatarValid() || !gAgentWearables.areWearablesLoaded()) + { + // data not ready. + return; + } + + // TODO: + // Find a way to show message with list of issues, but without making it too large + // and intrusive. + + LLHUDComplexity new_total_complexity; + LLHUDComplexity report_complexity; + + hud_complexity_list_t::iterator iter = complexity.begin(); + hud_complexity_list_t::iterator end = complexity.end(); + EWarnLevel warning_level = WARN_NONE; + for (; iter != end; ++iter) + { + LLHUDComplexity object_complexity = *iter; + EWarnLevel object_level = getWarningType(object_complexity, report_complexity); + if (object_level >= 0) + { + warning_level = object_level; + report_complexity = object_complexity; + } + new_total_complexity.objectsCost += object_complexity.objectsCost; + new_total_complexity.objectsCount += object_complexity.objectsCount; + new_total_complexity.texturesCost += object_complexity.texturesCost; + new_total_complexity.texturesCount += object_complexity.texturesCount; + new_total_complexity.largeTexturesCount += object_complexity.largeTexturesCount; + new_total_complexity.texturesMemoryTotal += object_complexity.texturesMemoryTotal; + } + + if (mHUDPopUpDelayTimer.hasExpired() || isNotificationVisible()) + { + if (warning_level >= 0) + { + // Display info about most complex HUD object + // make sure it shown only once unless object's complexity or object itself changed + if (mReportedHUDComplexity.objectId != report_complexity.objectId + || mReportedHUDWarning != warning_level) + { + displayHUDNotification(warning_level, report_complexity.objectId, report_complexity.objectName, report_complexity.jointName); + mReportedHUDComplexity = report_complexity; + mReportedHUDWarning = warning_level; + } + } + else + { + // Check if total complexity is above threshold and above previous warning + // Show warning with highest importance (5m delay between warnings by default) + if (!mReportedHUDComplexity.objectId.isNull()) + { + mReportedHUDComplexity.reset(); + mReportedHUDWarning = WARN_NONE; + } + + warning_level = getWarningType(new_total_complexity, mReportedHUDComplexity); + if (warning_level >= 0 && mReportedHUDWarning != warning_level) + { + displayHUDNotification(warning_level); + } + mReportedHUDComplexity = new_total_complexity; + mReportedHUDWarning = warning_level; + } + } + else if (warning_level >= 0) + { + LL_DEBUGS("HUDdetail") << "HUD individual warning postponed" << LL_ENDL; + } + + if (mLatestHUDComplexity.objectsCost != new_total_complexity.objectsCost + || mLatestHUDComplexity.objectsCount != new_total_complexity.objectsCount + || mLatestHUDComplexity.texturesCost != new_total_complexity.texturesCost + || mLatestHUDComplexity.texturesCount != new_total_complexity.texturesCount + || mLatestHUDComplexity.largeTexturesCount != new_total_complexity.largeTexturesCount + || mLatestHUDComplexity.texturesMemoryTotal != new_total_complexity.texturesMemoryTotal) + { + LL_INFOS("HUDdetail") << "HUD textures count: " << new_total_complexity.texturesCount + << " HUD textures cost: " << new_total_complexity.texturesCost + << " Large textures: " << new_total_complexity.largeTexturesCount + << " HUD objects cost: " << new_total_complexity.objectsCost + << " HUD objects count: " << new_total_complexity.objectsCount << LL_ENDL; + + mLatestHUDComplexity = new_total_complexity; + } +} + +bool LLHUDRenderNotifier::isNotificationVisible() +{ + return mHUDNotificationPtr != NULL && mHUDNotificationPtr->isActive(); +} + +// private static +LLHUDRenderNotifier::EWarnLevel LLHUDRenderNotifier::getWarningType(LLHUDComplexity object_complexity, LLHUDComplexity cmp_complexity) +{ + static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U); // ties max HUD cost to avatar cost + static LLCachedControl<U32> max_objects_count(gSavedSettings, "RenderHUDObjectsWarning", WARN_HUD_OBJECTS_LIMIT); + static LLCachedControl<U32> max_textures_count(gSavedSettings, "RenderHUDTexturesWarning", WARN_HUD_TEXTURES_LIMIT); + static LLCachedControl<U32> max_oversized_count(gSavedSettings, "RenderHUDOversizedTexturesWarning", WARN_HUD_OVERSIZED_TEXTURES_LIMIT); + static LLCachedControl<U32> max_texture_memory(gSavedSettings, "RenderHUDTexturesMemoryWarning", WARN_HUD_TEXTURE_MEMORY_LIMIT); + + if (cmp_complexity.texturesMemoryTotal < object_complexity.texturesMemoryTotal + && object_complexity.texturesMemoryTotal > (F64Bytes)max_texture_memory) + { + // Note: Memory might not be accurate since texture is still loading or discard level changes + + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " memory usage over limit, " + << " was " << cmp_complexity.texturesMemoryTotal + << " is " << object_complexity.texturesMemoryTotal << LL_ENDL; + + return WARN_MEMORY; + } + else if ((cmp_complexity.objectsCost < object_complexity.objectsCost + || cmp_complexity.texturesCost < object_complexity.texturesCost) + && max_render_cost > 0 + && object_complexity.objectsCost + object_complexity.texturesCost > max_render_cost) + { + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " complexity over limit," + << " HUD textures cost: " << object_complexity.texturesCost + << " HUD objects cost: " << object_complexity.objectsCost << LL_ENDL; + + return WARN_COST; + } + else if (cmp_complexity.largeTexturesCount < object_complexity.largeTexturesCount + && object_complexity.largeTexturesCount > max_oversized_count) + { + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " contains to many large textures: " + << object_complexity.largeTexturesCount << LL_ENDL; + + return WARN_HEAVY; + } + else if (cmp_complexity.texturesCount < object_complexity.texturesCount + && object_complexity.texturesCount > max_textures_count) + { + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " contains too many textures: " + << object_complexity.texturesCount << LL_ENDL; + + return WARN_CRAMPED; + } + else if (cmp_complexity.objectsCount < object_complexity.objectsCount + && object_complexity.objectsCount > max_objects_count) + { + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " contains too many objects: " + << object_complexity.objectsCount << LL_ENDL; + + return WARN_TEXTURES; + } + return WARN_NONE; +} + +void LLHUDRenderNotifier::displayHUDNotification(EWarnLevel warn_type, LLUUID obj_id, std::string obj_name, std::string joint_name) +{ + static LLCachedControl<U32> pop_up_delay(gSavedSettings, "ComplexityChangesPopUpDelay", 300); + static LLCachedControl<U32> expire_delay(gSavedSettings, "ShowMyComplexityChanges", 20); + LLDate expire_date(LLDate::now().secondsSinceEpoch() + expire_delay); + + // Since we need working "ignoretext" there is no other way but to + // use single notification while constructing it from multiple pieces + LLSD reason_args; + if (obj_id.isNull()) + { + reason_args["HUD_DETAILS"] = LLTrans::getString("hud_description_total"); + } + else + { + if (obj_name.empty()) + { + LL_WARNS("HUDdetail") << "Object name not assigned" << LL_ENDL; + } + if (joint_name.empty()) + { + std::string verb = "select?name=" + LLURI::escape(obj_name); + reason_args["HUD_DETAILS"] = LLSLURL("inventory", obj_id, verb.c_str()).getSLURLString(); + } + else + { + LLSD object_args; + std::string verb = "select?name=" + LLURI::escape(obj_name); + object_args["OBJ_NAME"] = LLSLURL("inventory", obj_id, verb.c_str()).getSLURLString(); + object_args["JNT_NAME"] = LLTrans::getString(joint_name); + reason_args["HUD_DETAILS"] = LLTrans::getString("hud_name_with_joint", object_args); + } + } + + LLSD msg_args; + msg_args["HUD_REASON"] = LLTrans::getString(e_hud_messages[warn_type], reason_args); + + mHUDNotificationPtr = LLNotifications::instance().add(LLNotification::Params() + .name("HUDComplexityWarning") + .expiry(expire_date) + .substitutions(msg_args)); + mHUDPopUpDelayTimer.resetWithExpiry(pop_up_delay); +} + diff --git a/indra/newview/llavatarrendernotifier.h b/indra/newview/llavatarrendernotifier.h index 2a2704de28..a169baef40 100644 --- a/indra/newview/llavatarrendernotifier.h +++ b/indra/newview/llavatarrendernotifier.h @@ -33,6 +33,36 @@ class LLViewerRegion; +struct LLHUDComplexity +{ + LLHUDComplexity() + { + reset(); + } + void reset() + { + objectId = LLUUID::null; + objectName = ""; + objectsCost = 0; + objectsCount = 0; + texturesCost = 0; + texturesCount = 0; + largeTexturesCount = 0; + texturesMemoryTotal = (F64Bytes)0; + } + LLUUID objectId; + std::string objectName; + std::string jointName; + U32 objectsCost; + U32 objectsCount; + U32 texturesCost; + U32 texturesCount; + U32 largeTexturesCount; + F64Bytes texturesMemoryTotal; +}; + +typedef std::list<LLHUDComplexity> hud_complexity_list_t; + // Class to notify user about drastic changes in agent's render weights or if other agents // reported that user's agent is too 'heavy' for their settings class LLAvatarRenderNotifier : public LLSingleton<LLAvatarRenderNotifier> @@ -81,4 +111,36 @@ private: S32 mLastOutfitRezStatus; }; +// Class to notify user about heavy set of HUD +class LLHUDRenderNotifier : public LLSingleton<LLHUDRenderNotifier> +{ +public: + LLHUDRenderNotifier(); + ~LLHUDRenderNotifier(); + + void updateNotificationHUD(hud_complexity_list_t complexity); + bool isNotificationVisible(); + +private: + enum EWarnLevel + { + WARN_NONE = -1, + WARN_TEXTURES = 0, // least important + WARN_CRAMPED, + WARN_HEAVY, + WARN_COST, + WARN_MEMORY, //most important + }; + + LLNotificationPtr mHUDNotificationPtr; + + static EWarnLevel getWarningType(LLHUDComplexity object_complexity, LLHUDComplexity cmp_complexity); + void displayHUDNotification(EWarnLevel warn_type, LLUUID obj_id = LLUUID::null, std::string object_name = "", std::string joint_name = ""); + + LLHUDComplexity mReportedHUDComplexity; + EWarnLevel mReportedHUDWarning; + LLHUDComplexity mLatestHUDComplexity; + LLFrameTimer mHUDPopUpDelayTimer; +}; + #endif /* ! defined(LL_llavatarrendernotifier_H) */ diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 00fa6dd979..54c6c985d6 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -311,7 +311,8 @@ LLWString LLChatBar::stripChannelNumber(const LLWString &mesg, S32* channel) } else if (mesg[0] == '/' && mesg[1] - && LLStringOps::isDigit(mesg[1])) + && (LLStringOps::isDigit(mesg[1]) + || (mesg[1] == '-' && mesg[2] && LLStringOps::isDigit(mesg[2])))) { // This a special "/20" speak on a channel S32 pos = 0; @@ -325,7 +326,7 @@ LLWString LLChatBar::stripChannelNumber(const LLWString &mesg, S32* channel) channel_string.push_back(c); pos++; } - while(c && pos < 64 && LLStringOps::isDigit(c)); + while(c && pos < 64 && (LLStringOps::isDigit(c) || (pos == 1 && c == '-'))); // Move the pointer forward to the first non-whitespace char // Check isspace before looping, so we can handle "/33foo" diff --git a/indra/newview/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp index 54f96b8872..90a5483dc9 100644 --- a/indra/newview/llcommandlineparser.cpp +++ b/indra/newview/llcommandlineparser.cpp @@ -43,7 +43,6 @@ #include <boost/bind.hpp> #include <boost/tokenizer.hpp> #include <boost/assign/list_of.hpp> -#include <boost/throw_exception.hpp> #if _MSC_VER # pragma warning(pop) @@ -52,6 +51,7 @@ #include "llsdserialize.h" #include "llerror.h" #include "stringize.h" +#include "llexception.h" #include <string> #include <set> #include <iostream> @@ -204,17 +204,17 @@ protected: { if(gPastLastOption) { - BOOST_THROW_EXCEPTION(LLCLPLastOption("Don't parse no more!")); + LLTHROW(LLCLPLastOption("Don't parse no more!")); } // Error checks. Needed? if (!value_store.empty() && !is_composing()) { - BOOST_THROW_EXCEPTION(LLCLPError("Non composing value with multiple occurences.")); + LLTHROW(LLCLPError("Non composing value with multiple occurences.")); } if (new_tokens.size() < min_tokens() || new_tokens.size() > max_tokens()) { - BOOST_THROW_EXCEPTION(LLCLPError("Illegal number of tokens specified.")); + LLTHROW(LLCLPError("Illegal number of tokens specified.")); } if(value_store.empty()) @@ -468,7 +468,7 @@ onevalue(const std::string& option, { // What does it mean when the user specifies a command-line switch // that requires a value, but omits the value? Complain. - BOOST_THROW_EXCEPTION(LLCLPError(STRINGIZE("No value specified for --" << option << "!"))); + LLTHROW(LLCLPError(STRINGIZE("No value specified for --" << option << "!"))); } else if (value.size() > 1) { @@ -486,10 +486,9 @@ void badvalue(const std::string& option, // If the user passes an unusable value for a command-line switch, it // seems like a really bad idea to just ignore it, even with a log // warning. - BOOST_THROW_EXCEPTION( - LLCLPError(STRINGIZE("Invalid value specified by command-line switch '" << option - << "' for variable '" << varname << "' of type " << type - << ": '" << value << "'"))); + LLTHROW(LLCLPError(STRINGIZE("Invalid value specified by command-line switch '" << option + << "' for variable '" << varname << "' of type " << type + << ": '" << value << "'"))); } template <typename T> diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index 05c7e6caa5..4e69896b69 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -448,7 +448,12 @@ bool LLConversationLog::moveLog(const std::string &originDirectory, const std::s std::string LLConversationLog::getFileName() { std::string filename = "conversation"; - return gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename) + ".log"; + std::string log_address = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename); + if (!log_address.empty()) + { + log_address += ".log"; + } + return log_address; } bool LLConversationLog::saveToFile(const std::string& filename) diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 4c16c542d6..499cf76bff 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "lldrawpoolavatar.h" +#include "llskinningutil.h" #include "llrender.h" #include "llvoavatar.h" @@ -56,8 +57,6 @@ static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK; static U32 sBufferUsage = GL_STREAM_DRAW_ARB; static U32 sShaderLevel = 0; -#define JOINT_COUNT 52 - LLGLSLShader* LLDrawPoolAvatar::sVertexProgram = NULL; BOOL LLDrawPoolAvatar::sSkipOpaque = FALSE; BOOL LLDrawPoolAvatar::sSkipTransparent = FALSE; @@ -1461,7 +1460,13 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } } -void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face) +void LLDrawPoolAvatar::getRiggedGeometry( + LLFace* face, + LLPointer<LLVertexBuffer>& buffer, + U32 data_mask, + const LLMeshSkinInfo* skin, + LLVolume* volume, + const LLVolumeFace& vol_face) { face->setGeomIndex(0); face->setIndicesIndex(0); @@ -1470,7 +1475,8 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer> face->setTextureIndex(255); if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable()) - { //make a new buffer + { + // make a new buffer if (sShaderLevel > 0) { buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB); @@ -1482,7 +1488,8 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer> buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true); } else - { //resize existing buffer + { + //resize existing buffer buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices); } @@ -1496,9 +1503,9 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer> m = m.inverse().transpose(); F32 mat3[] = - { m.m[0], m.m[1], m.m[2], - m.m[4], m.m[5], m.m[6], - m.m[8], m.m[9], m.m[10] }; + { m.m[0], m.m[1], m.m[2], + m.m[4], m.m[5], m.m[6], + m.m[8], m.m[9], m.m[10] }; LLMatrix3 mat_normal(mat3); @@ -1525,25 +1532,36 @@ void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer> { face->clearState(LLFace::TEXTURE_ANIM); } - - face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true); buffer->flush(); } -void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face) +void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( + LLVOAvatar* avatar, + LLFace* face, + const LLMeshSkinInfo* skin, + LLVolume* volume, + const LLVolumeFace& vol_face) { - LLVector4a* weight = vol_face.mWeights; - if (!weight) + LLVector4a* weights = vol_face.mWeights; + if (!weights) { return; } + // FIXME ugly const cast + LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin)); LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer(); LLDrawable* drawable = face->getDrawable(); U32 data_mask = face->getRiggedVertexBufferDataMask(); + + if (!vol_face.mWeightsScrubbed) + { + LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin); + vol_face.mWeightsScrubbed = TRUE; + } if (buffer.isNull() || buffer->getTypeMask() != data_mask || @@ -1595,62 +1613,22 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL; //build matrix palette - LLMatrix4a mp[JOINT_COUNT]; - LLMatrix4* mat = (LLMatrix4*) mp; - - U32 count = llmin((U32) skin->mJointNames.size(), (U32) JOINT_COUNT); - for (U32 j = 0; j < count; ++j) - { - LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); - if (!joint) - { - joint = avatar->getJoint("mPelvis"); - } - if (joint) - { - mat[j] = skin->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } + LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + U32 count = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); + LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin); LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); + const U32 max_joints = LLSkinningUtil::getMaxJointCount(); for (U32 j = 0; j < buffer->getNumVerts(); ++j) { LLMatrix4a final_mat; - final_mat.clear(); - - S32 idx[4]; - - LLVector4 wght; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j][k]; - - idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)JOINT_COUNT-1); - - wght[k] = w - floorf(w); - scale += wght[k]; - } - // This is enforced in unpackVolumeFaces() - llassert(scale>0.f); - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32 w = wght[k]; - - LLMatrix4a src; - src.setMul(mp[idx[k]], w); - - final_mat.add(src); - } - + LLSkinningUtil::getPerVertexSkinMatrix(weights[j].getF32ptr(), mat, false, final_mat, max_joints); LLVector4a& v = vol_face.mPositions[j]; + LLVector4a t; LLVector4a dst; bind_shape_matrix.affineTransform(v, t); @@ -1728,64 +1706,43 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) if (buff) { if (sShaderLevel > 0) - { //upload matrix palette to shader - LLMatrix4 mat[JOINT_COUNT]; - - U32 count = llmin((U32) skin->mJointNames.size(), (U32) JOINT_COUNT); + { + // upload matrix palette to shader + LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + U32 count = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); - for (U32 i = 0; i < count; ++i) - { - LLJoint* joint = avatar->getJoint(skin->mJointNames[i]); - if (!joint) - { - joint = avatar->getJoint("mPelvis"); - } - if (joint) - { - mat[i] = skin->mInvBindMatrix[i]; - mat[i] *= joint->getWorldMatrix(); - } - } - stop_glerror(); - F32 mp[JOINT_COUNT*9]; - - F32 transp[JOINT_COUNT*3]; + F32 mp[LL_MAX_JOINTS_PER_MESH_OBJECT*12]; for (U32 i = 0; i < count; ++i) { - F32* m = (F32*) mat[i].mMatrix; + F32* m = (F32*) mat[i].mMatrix[0].getF32ptr(); - U32 idx = i*9; + U32 idx = i*12; mp[idx+0] = m[0]; mp[idx+1] = m[1]; mp[idx+2] = m[2]; + mp[idx+3] = m[12]; - mp[idx+3] = m[4]; - mp[idx+4] = m[5]; - mp[idx+5] = m[6]; - - mp[idx+6] = m[8]; - mp[idx+7] = m[9]; - mp[idx+8] = m[10]; - - idx = i*3; + mp[idx+4] = m[4]; + mp[idx+5] = m[5]; + mp[idx+6] = m[6]; + mp[idx+7] = m[13]; - transp[idx+0] = m[12]; - transp[idx+1] = m[13]; - transp[idx+2] = m[14]; + mp[idx+8] = m[8]; + mp[idx+9] = m[9]; + mp[idx+10] = m[10]; + mp[idx+11] = m[14]; } - LLDrawPoolAvatar::sVertexProgram->uniformMatrix3fv(LLViewerShaderMgr::AVATAR_MATRIX, + LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, count, FALSE, (GLfloat*) mp); - LLDrawPoolAvatar::sVertexProgram->uniform3fv(LLShaderMgr::AVATAR_TRANSLATION, count, transp); - - stop_glerror(); } else diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index cc77b407ae..5e0f3ab7f9 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -144,7 +144,7 @@ namespace Details int errorCount = 0; int counter = mCounter; // saved on the stack for logging. - LL_INFOS("LLEventPollImpl") << " <" << counter << "> entering coroutine." << LL_ENDL; + LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> entering coroutine." << LL_ENDL; mAdapter = httpAdapter; @@ -172,7 +172,7 @@ namespace Details { if (status == LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT)) { // A standard timeout response we get this when there are no events. - LL_INFOS("LLEventPollImpl") << "All is very quiet on target server. It may have gone idle?" << LL_ENDL; + LL_DEBUGS("LLEventPollImpl") << "All is very quiet on target server. It may have gone idle?" << LL_ENDL; errorCount = 0; continue; } @@ -266,7 +266,7 @@ namespace Details } } } - LL_INFOS("LLEventPollImpl") << " <" << counter << "> Leaving coroutine." << LL_ENDL; + LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> Leaving coroutine." << LL_ENDL; } } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index de349a03d4..3d5e2d356e 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -573,6 +573,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) LLRiggedVolume* rigged = volume->getRiggedVolume(); if (rigged) { + // called when selecting a face during edit of a mesh object LLGLEnable offset(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.f, -1.f); gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix); diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 4a059fdc67..d1e77f57e2 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -904,7 +904,8 @@ void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target base[label]["Samples"].asInteger()); } - exportCharts(baseline, target); + // This currently crashes, possibly due to a race condition in shutdown: + // exportCharts(baseline, target); os.flush(); os.close(); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index bababca652..c2d0d9f06b 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -108,6 +108,7 @@ private: static const std::string sCheckUpdateListenerName; static void startFetchServerReleaseNotes(); + static void fetchServerReleaseNotesCoro(const std::string& cap_url); static void handleServerReleaseNotes(LLSD results); }; @@ -224,35 +225,62 @@ void LLFloaterAbout::startFetchServerReleaseNotes() // an URL suitable for external browsers in the "Location:" HTTP header. std::string cap_url = region->getCapability("ServerReleaseNotes"); - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(cap_url, - &LLFloaterAbout::handleServerReleaseNotes, &LLFloaterAbout::handleServerReleaseNotes); + LLCoros::instance().launch("fetchServerReleaseNotesCoro", boost::bind(&LLFloaterAbout::fetchServerReleaseNotesCoro, cap_url)); } /*static*/ +void LLFloaterAbout::fetchServerReleaseNotesCoro(const std::string& cap_url) +{ + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("fetchServerReleaseNotesCoro", LLCore::HttpRequest::DEFAULT_POLICY_ID)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, cap_url, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + handleServerReleaseNotes(httpResults); + } + else + { + handleServerReleaseNotes(result); + } +} + +/*static*/ void LLFloaterAbout::handleServerReleaseNotes(LLSD results) { -// LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about"); -// if (floater_about) -// { - LLSD http_headers; - if (results.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS)) - { - LLSD http_results = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - http_headers = http_results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; - } - else - { - http_headers = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; - } - - std::string location = http_headers[HTTP_IN_HEADER_LOCATION].asString(); - if (location.empty()) - { - location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); - } - LLAppViewer::instance()->setServerReleaseNotesURL(location); -// } + LLSD http_headers; + if (results.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS)) + { + LLSD http_results = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + http_headers = http_results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + } + else + { + http_headers = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + } + + std::string location = http_headers[HTTP_IN_HEADER_LOCATION].asString(); + if (location.empty()) + { + location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); + } + LLAppViewer::instance()->setServerReleaseNotesURL(location); + + LLFloaterAbout* floater_about = LLFloaterReg::findTypedInstance<LLFloaterAbout>("sl_about"); + if (floater_about) + { + floater_about->setSupportText(location); + } } class LLFloaterAboutListener: public LLEventAPI diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 72892b47a4..aa7bfbfdb7 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -55,6 +55,8 @@ //#include "llsdserialize.h" +static const U32 AVATAR_PICKER_SEARCH_TIMEOUT = 180U; + //put it back as a member once the legacy path is out? static std::map<LLUUID, LLAvatarName> sAvatarNameMap; @@ -463,10 +465,13 @@ void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::strin LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; - LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + httpOpts->setTimeout(AVATAR_PICKER_SEARCH_TIMEOUT); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts); LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp index e21a8594bc..91436e52fe 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -280,7 +280,7 @@ void LLFloaterBuyCurrencyUI::onClickCancel() void LLFloaterBuyCurrencyUI::onClickErrorWeb() { - LLWeb::loadURLExternal(mManager.errorURI()); + LLWeb::loadURL(mManager.errorURI()); closeFloater(); // Update L$ balance LLStatusBar::sendMoneyBalanceRequest(); diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index e5df417ca9..d33a138e94 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -178,6 +178,12 @@ void LLFloaterBvhPreview::setAnimCallbacks() getChild<LLUICtrl>("ease_out_time")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateEaseOut, this, _1)); } +std::map <std::string, std::string> LLFloaterBvhPreview::getJointAliases() +{ + LLPointer<LLVOAvatar> av = (LLVOAvatar*)mAnimPreview->getDummyAvatar(); + return av->getJointAliases(); +} + //----------------------------------------------------------------------------- // postBuild() //----------------------------------------------------------------------------- @@ -215,6 +221,8 @@ BOOL LLFloaterBvhPreview::postBuild() getChildView("bad_animation_text")->setVisible(FALSE); + mAnimPreview = new LLPreviewAnimation(256, 256); + std::string exten = gDirUtilp->getExtension(mFilename); if (exten == "bvh") { @@ -241,8 +249,11 @@ BOOL LLFloaterBvhPreview::postBuild() file_buffer[file_size] = '\0'; LL_INFOS() << "Loading BVH file " << mFilename << LL_ENDL; ELoadStatus load_status = E_ST_OK; - S32 line_number = 0; - loaderp = new LLBVHLoader(file_buffer, load_status, line_number); + S32 line_number = 0; + + std::map<std::string, std::string> joint_alias_map = getJointAliases(); + + loaderp = new LLBVHLoader(file_buffer, load_status, line_number, joint_alias_map); std::string status = getString(STATUS[load_status]); if(load_status == E_ST_NO_XLT_FILE) @@ -266,8 +277,6 @@ BOOL LLFloaterBvhPreview::postBuild() mTransactionID.generate(); mMotionID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); - mAnimPreview = new LLPreviewAnimation(256, 256); - // motion will be returned, but it will be in a load-pending state, as this is a new motion // this motion will not request an asset transfer until next update, so we have a chance to // load the keyframe data locally @@ -280,9 +289,12 @@ BOOL LLFloaterBvhPreview::postBuild() LLDataPackerBinaryBuffer dp(buffer, buffer_size); // pass animation data through memory buffer + LL_INFOS("BVH") << "Serializing loaderp" << LL_ENDL; loaderp->serialize(dp); dp.reset(); + LL_INFOS("BVH") << "Deserializing motionp" << LL_ENDL; BOOL success = motionp && motionp->deserialize(dp); + LL_INFOS("BVH") << "Done" << LL_ENDL; delete []buffer; diff --git a/indra/newview/llfloaterbvhpreview.h b/indra/newview/llfloaterbvhpreview.h index b81cc6e3a5..20d15d9603 100644 --- a/indra/newview/llfloaterbvhpreview.h +++ b/indra/newview/llfloaterbvhpreview.h @@ -109,7 +109,9 @@ public: S32 status, LLExtStat ext_status); private: void setAnimCallbacks() ; - + std::map <std::string, std::string> getJointAliases(); + + protected: void draw(); void resetMotion(); diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index d842106146..b840d37c4d 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -328,7 +328,7 @@ void LLFloaterGesture::addGesture(const LLUUID& item_id , LLMultiGesture* gestur element["columns"][0]["font"]["name"] = "SANSSERIF"; element["columns"][0]["font"]["style"] = font_style; - std::string key_string = LLKeyboard::stringFromKey(gesture->mKey); + std::string key_string; std::string buffer; if (gesture->mKey == KEY_NONE) @@ -338,6 +338,7 @@ void LLFloaterGesture::addGesture(const LLUUID& item_id , LLMultiGesture* gestur } else { + key_string = LLKeyboard::stringFromKey(gesture->mKey); buffer = LLKeyboard::stringFromAccelerator(gesture->mMask, gesture->mKey); } diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 7a989806a1..257b39a7dd 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -798,7 +798,8 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32* } else if (mesg[0] == '/' && mesg[1] - && LLStringOps::isDigit(mesg[1])) + && (LLStringOps::isDigit(mesg[1]) + || (mesg[1] == '-' && mesg[2] && LLStringOps::isDigit(mesg[2])))) { // This a special "/20" speak on a channel S32 pos = 0; @@ -812,7 +813,7 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32* channel_string.push_back(c); pos++; } - while(c && pos < 64 && LLStringOps::isDigit(c)); + while(c && pos < 64 && (LLStringOps::isDigit(c) || (pos==1 && c =='-'))); // Move the pointer forward to the first non-whitespace char // Check isspace before looping, so we can handle "/33foo" @@ -837,19 +838,36 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32* void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ChatFromViewer); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ChatData); - msg->addStringFast(_PREHASH_Message, utf8_out_text); - msg->addU8Fast(_PREHASH_Type, type); - msg->addS32("Channel", channel); - - gAgent.sendReliableMessage(); - - add(LLStatViewer::CHAT_COUNT, 1); + LLMessageSystem* msg = gMessageSystem; + + if (channel >= 0) + { + msg->newMessageFast(_PREHASH_ChatFromViewer); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ChatData); + msg->addStringFast(_PREHASH_Message, utf8_out_text); + msg->addU8Fast(_PREHASH_Type, type); + msg->addS32("Channel", channel); + + } + else + { + // Hack: ChatFromViewer doesn't allow negative channels + msg->newMessage("ScriptDialogReply"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgentID); + msg->addUUID("SessionID", gAgentSessionID); + msg->nextBlock("Data"); + msg->addUUID("ObjectID", gAgentID); + msg->addS32("ChatChannel", channel); + msg->addS32("ButtonIndex", 0); + msg->addString("ButtonLabel", utf8_out_text); + } + + gAgent.sendReliableMessage(); + add(LLStatViewer::CHAT_COUNT, 1); } class LLChatCommandHandler : public LLCommandHandler diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ffeebfd256..7aae48cf5d 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -42,7 +42,6 @@ #include "llcombobox.h" #include "lldatapacker.h" #include "lldrawable.h" -#include "lldrawpoolavatar.h" #include "llrender.h" #include "llface.h" #include "lleconomy.h" @@ -54,6 +53,7 @@ #include "llmeshrepository.h" #include "llnotificationsutil.h" #include "llsdutil_math.h" +#include "llskinningutil.h" #include "lltextbox.h" #include "lltoolmgr.h" #include "llui.h" @@ -298,6 +298,7 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("upload_skin", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL); childSetCommitCallback("upload_joints", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL); + childSetCommitCallback("lock_scale_if_joint_position", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL); childSetCommitCallback("upload_textures", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL); childSetTextArg("status", "[STATUS]", getString("status_idle")); @@ -311,6 +312,7 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("upload_skin", onUploadSkinCommit, this); childSetCommitCallback("upload_joints", onUploadJointsCommit, this); + childSetCommitCallback("lock_scale_if_joint_position", onUploadJointsCommit, this); childSetCommitCallback("import_scale", onImportScaleCommit, this); childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this); @@ -323,6 +325,7 @@ BOOL LLFloaterModelPreview::postBuild() childDisable("upload_skin"); childDisable("upload_joints"); + childDisable("lock_scale_if_joint_position"); initDecompControls(); @@ -488,11 +491,21 @@ void LLFloaterModelPreview::onClickCalculateBtn() bool upload_skinweights = childGetValue("upload_skin").asBoolean(); bool upload_joint_positions = childGetValue("upload_joints").asBoolean(); + bool lock_scale_if_joint_position = childGetValue("lock_scale_if_joint_position").asBoolean(); + + if (upload_joint_positions) + { + // Diagnostic message showing list of joints for which joint offsets are defined. + // FIXME - given time, would be much better to put this in the UI, in updateStatusMessages(). + mModelPreview->getPreviewAvatar()->showAttachmentOverrides(); + } mUploadModelUrl.clear(); gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, - childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mUploadModelUrl, false, + childGetValue("upload_textures").asBoolean(), + upload_skinweights, upload_joint_positions, lock_scale_if_joint_position, + mUploadModelUrl, false, getWholeModelFeeObserverHandle()); toggleCalculateButton(false); @@ -1190,7 +1203,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) , mPhysicsSearchLOD( LLModel::LOD_PHYSICS ) , mResetJoints( false ) , mModelNoErrors( true ) -, mRigParityWithScene( false ) , mLastJointUpdate( false ) { mNeedsUpdate = TRUE; @@ -1317,9 +1329,10 @@ U32 LLModelPreview::calcResourceCost() decomp, mFMP->childGetValue("upload_skin").asBoolean(), mFMP->childGetValue("upload_joints").asBoolean(), + mFMP->childGetValue("lock_scale_if_joint_position").asBoolean(), TRUE, - FALSE, - instance.mModel->mSubmodelID); + FALSE, + instance.mModel->mSubmodelID); num_hulls += decomp.mHull.size(); for (U32 i = 0; i < decomp.mHull.size(); ++i) @@ -1644,27 +1657,23 @@ void LLModelPreview::rebuildUploadData() } -void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions) +void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) { if (!mLODFile[LLModel::LOD_HIGH].empty()) { std::string filename = mLODFile[LLModel::LOD_HIGH]; - - std::string::size_type i = filename.rfind("."); - if (i != std::string::npos) - { - filename.replace(i, filename.size()-1, ".slm"); - saveUploadData(filename, save_skinweights, save_joint_positions); + std::string slm_filename; + + if (LLModelLoader::getSLMFilename(filename, slm_filename)) + { + saveUploadData(slm_filename, save_skinweights, save_joint_positions, lock_scale_if_joint_position); } } } -void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions) +void LLModelPreview::saveUploadData(const std::string& filename, + bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) { - if (!gSavedSettings.getBOOL("MeshImportUseSLM")) - { - return; - } std::set<LLPointer<LLModel> > meshes; std::map<LLModel*, std::string> mesh_binary; @@ -1704,7 +1713,9 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw instance.mLOD[LLModel::LOD_LOW], instance.mLOD[LLModel::LOD_IMPOSTOR], decomp, - save_skinweights, save_joint_positions, + save_skinweights, + save_joint_positions, + lock_scale_if_joint_position, FALSE, TRUE, instance.mModel->mSubmodelID); data["mesh"][instance.mModel->mLocalID] = str.str(); @@ -1731,6 +1742,20 @@ void LLModelPreview::clearModel(S32 lod) mScene[lod].clear(); } +void LLModelPreview::getJointAliases( JointMap& joint_map) +{ + // Get all standard skeleton joints from the preview avatar. + LLVOAvatar *av = getPreviewAvatar(); + + //Joint names and aliases come from avatar_skeleton.xml + + joint_map = av->getJointAliases(); + for (S32 i = 0; i < av->mNumCollisionVolumes; i++) + { + joint_map[av->mCollisionVolumes[i].getName()] = av->mCollisionVolumes[i].getName(); + } +} + void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable_slm) { assert_main_thread(); @@ -1773,6 +1798,9 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable clearGLODGroup(); } + std::map<std::string, std::string> joint_alias_map; + getJointAliases(joint_alias_map); + mModelLoader = new LLDAELoader( filename, lod, @@ -1783,6 +1811,8 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable this, mJointTransformMap, mJointsFromNode, + joint_alias_map, + LLSkinningUtil::getMaxJointCount(), gSavedSettings.getU32("ImporterModelLimit"), gSavedSettings.getBOOL("ImporterPreprocessDAE")); @@ -1792,6 +1822,12 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable } else { + // For MAINT-6647, we have set force_disable_slm to true, + // which means this code path will never be taken. Trying to + // re-use SLM files has never worked properly; in particular, + // it tends to force the UI into strange checkbox options + // which cannot be altered. + //only try to load from slm if viewer is configured to do so and this is the //initial model load (not an LoD or physics shape) mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty(); @@ -1919,6 +1955,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) bool skin_weights = false; bool joint_positions = false; + bool lock_scale_if_joint_position = false; for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) { //for each LoD @@ -1966,6 +2003,10 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) { joint_positions = true; } + if (list_iter->mModel->mSkinInfo.mLockScaleIfJointPosition) + { + lock_scale_if_joint_position = true; + } } } } @@ -1989,6 +2030,13 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) mViewOption["show_joint_positions"] = true; fmp->childSetValue("upload_joints", true); } + + if (lock_scale_if_joint_position) + { + fmp->enableViewOption("lock_scale_if_joint_position"); + mViewOption["lock_scale_if_joint_position"] = true; + fmp->childSetValue("lock_scale_if_joint_position", true); + } } //copy high lod to base scene for LoD generation @@ -3307,14 +3355,17 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) LLVector3 pos(vf.mPositions[i].getF32ptr()); const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); + llassert(weight_list.size()>0 && weight_list.size() <= 4); // LLModel::loadModel() should guarantee this LLVector4 w(0,0,0,0); for (U32 i = 0; i < weight_list.size(); ++i) { - F32 wght = llmin(weight_list[i].mWeight, 0.999999f); + F32 wght = llclamp(weight_list[i].mWeight, 0.001f, 0.999f); F32 joint = (F32) weight_list[i].mJointIdx; w.mV[i] = joint + wght; + llassert(w.mV[i]-(S32)w.mV[i]>0.0f); // because weights are non-zero, and range of wt values + //should not cause floating point precision issues. } *(weights_strider++) = w; @@ -3368,19 +3419,6 @@ void LLModelPreview::update() } //----------------------------------------------------------------------------- -// getTranslationForJointOffset() -//----------------------------------------------------------------------------- -LLVector3 LLModelPreview::getTranslationForJointOffset( std::string joint ) -{ - LLMatrix4 jointTransform; - if ( mJointTransformMap.find( joint ) != mJointTransformMap.end() ) - { - jointTransform = mJointTransformMap[joint]; - return jointTransform.getTranslation(); - } - return LLVector3(0.0f,0.0f,0.0f); -} -//----------------------------------------------------------------------------- // createPreviewAvatar //----------------------------------------------------------------------------- void LLModelPreview::createPreviewAvatar( void ) @@ -3509,6 +3547,7 @@ void LLModelPreview::addEmptyFace( LLModel* pTarget ) pTarget->setVolumeFaceData( faceCnt+1, pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices() ); } + //----------------------------------------------------------------------------- // render() //----------------------------------------------------------------------------- @@ -3627,7 +3666,17 @@ BOOL LLModelPreview::render() mFMP->childSetValue("upload_joints", false); upload_joints = false; } - + + if (upload_skin && upload_joints) + { + mFMP->childEnable("lock_scale_if_joint_position"); + } + else + { + mFMP->childDisable("lock_scale_if_joint_position"); + mFMP->childSetValue("lock_scale_if_joint_position", false); + } + //Only enable joint offsets if it passed the earlier critiquing if ( isRigValidForJointPositionUpload() ) { @@ -4002,20 +4051,6 @@ BOOL LLModelPreview::render() LLVector3::z_axis, // up target_pos); // point of interest - if (joint_positions) - { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - if (shader) - { - gDebugProgram.bind(); - } - getPreviewAvatar()->renderCollisionVolumes(); - if (shader) - { - shader->bind(); - } - } - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) @@ -4040,58 +4075,32 @@ BOOL LLModelPreview::render() //quick 'n dirty software vertex skinning //build matrix palette - - LLMatrix4 mat[64]; - for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j) - { - LLJoint* joint = getPreviewAvatar()->getJoint(model->mSkinInfo.mJointNames[j]); - if (joint) - { - mat[j] = model->mSkinInfo.mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } + LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + const LLMeshSkinInfo *skin = &model->mSkinInfo; + U32 count = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, + skin, getPreviewAvatar()); + LLMatrix4a bind_shape_matrix; + bind_shape_matrix.loadu(skin->mBindShapeMatrix); + U32 max_joints = LLSkinningUtil::getMaxJointCount(); for (U32 j = 0; j < buffer->getNumVerts(); ++j) { - LLMatrix4 final_mat; - final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - - LLVector4 wght; - S32 idx[4]; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j].mV[k]; - - idx[k] = (S32) floorf(w); - wght.mV[k] = w - floorf(w); - scale += wght.mV[k]; - } - - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32* src = (F32*) mat[idx[k]].mMatrix; - F32* dst = (F32*) final_mat.mMatrix; - - F32 w = wght.mV[k]; - - for (U32 l = 0; l < 16; l++) - { - dst[l] += src[l]*w; - } - } + LLMatrix4a final_mat; + F32 *wptr = weight[j].mV; + LLSkinningUtil::getPerVertexSkinMatrix(wptr, mat, true, final_mat, max_joints); //VECTORIZE THIS - LLVector3 v(face.mPositions[j].getF32ptr()); + LLVector4a& v = face.mPositions[j]; - v = v * model->mSkinInfo.mBindShapeMatrix; - v = v * final_mat; + LLVector4a t; + LLVector4a dst; + bind_shape_matrix.affineTransform(v, t); + final_mat.affineTransform(t, dst); - position[j] = v; + position[j][0] = dst[0]; + position[j][1] = dst[1]; + position[j][2] = dst[2]; } llassert(model->mMaterialList.size() > i); @@ -4125,6 +4134,22 @@ BOOL LLModelPreview::render() } } } + + if (joint_positions) + { + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + if (shader) + { + gDebugProgram.bind(); + } + getPreviewAvatar()->renderCollisionVolumes(); + getPreviewAvatar()->renderBones(); + if (shader) + { + shader->bind(); + } + } + } } @@ -4245,11 +4270,17 @@ void LLFloaterModelPreview::onUpload(void* user_data) bool upload_skinweights = mp->childGetValue("upload_skin").asBoolean(); bool upload_joint_positions = mp->childGetValue("upload_joints").asBoolean(); + bool lock_scale_if_joint_position = mp->childGetValue("lock_scale_if_joint_position").asBoolean(); - mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions); + if (gSavedSettings.getBOOL("MeshImportUseSLM")) + { + mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions, lock_scale_if_joint_position); + } gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mp->mUploadModelUrl, + mp->childGetValue("upload_textures").asBoolean(), + upload_skinweights, upload_joint_positions, lock_scale_if_joint_position, + mp->mUploadModelUrl, true, LLHandle<LLWholeModelFeeObserver>(), mp->getWholeModelUploadObserverHandle()); } @@ -4261,7 +4292,14 @@ void LLFloaterModelPreview::refresh() } //static -void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) +void LLModelPreview::textureLoadedCallback( + BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* src_aux, + S32 discard_level, + BOOL final, + void* userdata ) { LLModelPreview* preview = (LLModelPreview*) userdata; preview->refresh(); diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index a73ca50260..a7a5c1b33a 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -260,6 +260,7 @@ public: virtual BOOL needsRender() { return mNeedsUpdate; } void setPreviewLOD(S32 lod); void clearModel(S32 lod); + void getJointAliases(JointMap& joint_map); void loadModel(std::string filename, S32 lod, bool force_disable_slm = false); void loadModelCallback(S32 lod); bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } @@ -269,8 +270,8 @@ public: void restoreNormals(); U32 calcResourceCost(); void rebuildUploadData(); - void saveUploadData(bool save_skinweights, bool save_joint_poisitions); - void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_poisitions); + void saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); + void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); void clearIncompatible(S32 lod); void updateStatusMessages(); void updateLodControls(S32 lod); @@ -300,11 +301,7 @@ public: void setLoadState( U32 state ) { mLoadState = state; } U32 getLoadState() { return mLoadState; } - void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; } - const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; } - LLVector3 getTranslationForJointOffset( std::string joint ); - static bool sIgnoreLoadedCallback; std::vector<S32> mLodsQuery; @@ -352,7 +349,6 @@ private: bool mLoading; U32 mLoadState; bool mResetJoints; - bool mRigParityWithScene; bool mModelNoErrors; std::map<std::string, bool> mViewOption; @@ -410,7 +406,7 @@ private: bool mLastJointUpdate; - JointSet mJointsFromNode; + JointNameSet mJointsFromNode; JointTransformMap mJointTransformMap; LLPointer<LLVOAvatar> mPreviewAvatar; diff --git a/indra/newview/llfloaterpay.cpp b/indra/newview/llfloaterpay.cpp index 31245db344..dfe462c8d1 100644 --- a/indra/newview/llfloaterpay.cpp +++ b/indra/newview/llfloaterpay.cpp @@ -72,6 +72,8 @@ struct LLGiveMoneyInfo mFloater(floater), mAmount(amount){} }; +typedef boost::shared_ptr<LLGiveMoneyInfo> give_money_ptr; + ///---------------------------------------------------------------------------- /// Class LLFloaterPay ///---------------------------------------------------------------------------- @@ -94,18 +96,18 @@ public: bool is_group); static bool payConfirmationCallback(const LLSD& notification, const LLSD& response, - LLGiveMoneyInfo* info); + give_money_ptr info); private: static void onCancel(void* data); static void onKeystroke(LLLineEditor* editor, void* data); - static void onGive(void* data); + static void onGive(give_money_ptr info); void give(S32 amount); static void processPayPriceReply(LLMessageSystem* msg, void **userdata); void finishPayUI(const LLUUID& target_id, BOOL is_group); protected: - std::vector<LLGiveMoneyInfo*> mCallbackData; + std::vector<give_money_ptr> mCallbackData; money_callback mCallback; LLTextBox* mObjectNameText; LLUUID mTargetUUID; @@ -113,7 +115,7 @@ protected: BOOL mHaveName; LLButton* mQuickPayButton[MAX_PAY_BUTTONS]; - LLGiveMoneyInfo* mQuickPayInfo[MAX_PAY_BUTTONS]; + give_money_ptr mQuickPayInfo[MAX_PAY_BUTTONS]; LLSafeHandle<LLObjectSelection> mObjectSelection; }; @@ -136,7 +138,11 @@ LLFloaterPay::LLFloaterPay(const LLSD& key) // Destroys the object LLFloaterPay::~LLFloaterPay() { - std::for_each(mCallbackData.begin(), mCallbackData.end(), DeletePointer()); + std::vector<give_money_ptr>::iterator iter; + for (iter = mCallbackData.begin(); iter != mCallbackData.end(); ++iter) + { + (*iter)->mFloater = NULL; + } mCallbackData.clear(); // Name callbacks will be automatically disconnected since LLFloater is trackable @@ -148,40 +154,40 @@ BOOL LLFloaterPay::postBuild() { S32 i = 0; - LLGiveMoneyInfo* info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_0); + give_money_ptr info = give_money_ptr(new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_0)); mCallbackData.push_back(info); - childSetAction("fastpay 1",&LLFloaterPay::onGive,info); + childSetAction("fastpay 1", boost::bind(LLFloaterPay::onGive, info)); getChildView("fastpay 1")->setVisible(FALSE); mQuickPayButton[i] = getChild<LLButton>("fastpay 1"); mQuickPayInfo[i] = info; ++i; - info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_1); + info = give_money_ptr(new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_1)); mCallbackData.push_back(info); - childSetAction("fastpay 5",&LLFloaterPay::onGive,info); + childSetAction("fastpay 5", boost::bind(LLFloaterPay::onGive, info)); getChildView("fastpay 5")->setVisible(FALSE); mQuickPayButton[i] = getChild<LLButton>("fastpay 5"); mQuickPayInfo[i] = info; ++i; - info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_2); + info = give_money_ptr(new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_2)); mCallbackData.push_back(info); - childSetAction("fastpay 10",&LLFloaterPay::onGive,info); + childSetAction("fastpay 10", boost::bind(LLFloaterPay::onGive, info)); getChildView("fastpay 10")->setVisible(FALSE); mQuickPayButton[i] = getChild<LLButton>("fastpay 10"); mQuickPayInfo[i] = info; ++i; - info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_3); + info = give_money_ptr(new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_3)); mCallbackData.push_back(info); - childSetAction("fastpay 20",&LLFloaterPay::onGive,info); + childSetAction("fastpay 20", boost::bind(LLFloaterPay::onGive, info)); getChildView("fastpay 20")->setVisible(FALSE); mQuickPayButton[i] = getChild<LLButton>("fastpay 20"); @@ -195,10 +201,10 @@ BOOL LLFloaterPay::postBuild() getChild<LLLineEditor>("amount")->setKeystrokeCallback(&LLFloaterPay::onKeystroke, this); getChild<LLLineEditor>("amount")->setPrevalidate(LLTextValidate::validateNonNegativeS32); - info = new LLGiveMoneyInfo(this, 0); + info = give_money_ptr(new LLGiveMoneyInfo(this, 0)); mCallbackData.push_back(info); - childSetAction("pay btn",&LLFloaterPay::onGive,info); + childSetAction("pay btn", boost::bind(LLFloaterPay::onGive, info)); setDefaultBtn("pay btn"); getChildView("pay btn")->setVisible(FALSE); getChildView("pay btn")->setEnabled(FALSE); @@ -415,9 +421,9 @@ void LLFloaterPay::payDirectly(money_callback callback, floater->finishPayUI(target_id, is_group); } -bool LLFloaterPay::payConfirmationCallback(const LLSD& notification, const LLSD& response, LLGiveMoneyInfo* info) +bool LLFloaterPay::payConfirmationCallback(const LLSD& notification, const LLSD& response, give_money_ptr info) { - if (!info || !info->mFloater) + if (!info.get() || !info->mFloater) { return false; } @@ -479,54 +485,61 @@ void LLFloaterPay::onKeystroke(LLLineEditor*, void* data) } // static -void LLFloaterPay::onGive(void* data) +void LLFloaterPay::onGive(give_money_ptr info) { - LLGiveMoneyInfo* info = reinterpret_cast<LLGiveMoneyInfo*>(data); - LLFloaterPay* floater = info->mFloater; - if(info && floater) - { - S32 amount = info->mAmount; - if(amount == 0) - { - amount = atoi(floater->getChild<LLUICtrl>("amount")->getValue().asString().c_str()); - } - if (amount > PAY_AMOUNT_NOTIFICATION && gStatusBar && gStatusBar->getBalance() > amount) - { - LLUUID payee_id = LLUUID::null; - BOOL is_group = false; - if (floater->mObjectSelection.notNull()) - { - LLSelectNode* node = floater->mObjectSelection->getFirstRootNode(); - if (node) - { - node->mPermissions->getOwnership(payee_id, is_group); - } - else - { - // object no longer exists - LLNotificationsUtil::add("PayObjectFailed"); - floater->closeFloater(); - return; - } - } - else - { - is_group = floater->mTargetIsGroup; - payee_id = floater->mTargetUUID; - } - - LLSD args; - args["TARGET"] = LLSLURL( is_group ? "group" : "agent", payee_id, "completename").getSLURLString(); - args["AMOUNT"] = amount; - - LLNotificationsUtil::add("PayConfirmation", args, LLSD(), boost::bind(&LLFloaterPay::payConfirmationCallback, _1, _2, info)); - } - else - { - floater->give(amount); - floater->closeFloater(); - } - } + if (!info.get() || !info->mFloater) + { + return; + } + + LLFloaterPay* floater = info->mFloater; + S32 amount = info->mAmount; + if (amount == 0) + { + LLUICtrl* text_field = floater->getChild<LLUICtrl>("amount"); + if (!text_field) + { + return; + } + amount = atoi(text_field->getValue().asString().c_str()); + } + + if (amount > PAY_AMOUNT_NOTIFICATION && gStatusBar && gStatusBar->getBalance() > amount) + { + LLUUID payee_id = LLUUID::null; + BOOL is_group = false; + if (floater->mObjectSelection.notNull()) + { + LLSelectNode* node = floater->mObjectSelection->getFirstRootNode(); + if (node) + { + node->mPermissions->getOwnership(payee_id, is_group); + } + else + { + // object no longer exists + LLNotificationsUtil::add("PayObjectFailed"); + floater->closeFloater(); + return; + } + } + else + { + is_group = floater->mTargetIsGroup; + payee_id = floater->mTargetUUID; + } + + LLSD args; + args["TARGET"] = LLSLURL(is_group ? "group" : "agent", payee_id, "completename").getSLURLString(); + args["AMOUNT"] = amount; + + LLNotificationsUtil::add("PayConfirmation", args, LLSD(), boost::bind(&LLFloaterPay::payConfirmationCallback, _1, _2, info)); + } + else + { + floater->give(amount); + floater->closeFloater(); + } } void LLFloaterPay::give(S32 amount) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 36bdcf4d89..100ee5ab72 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1232,6 +1232,9 @@ void LLFloaterPreference::refreshEnabledState() (ctrl_wind_light->get()) ? TRUE : FALSE; ctrl_deferred->setEnabled(enabled); + + // Cannot have floater active until caps have been received + getChild<LLButton>("default_creation_permissions")->setEnabled(LLStartUp::getStartupState() < STATE_STARTED ? false : true); } void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() @@ -1250,7 +1253,7 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() LLCheckBoxCtrl* bumpshiny_ctrl = getChild<LLCheckBoxCtrl>("BumpShiny"); bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE); - + // Avatar Mode // Enable Avatar Shaders LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram"); @@ -1369,9 +1372,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() disableUnavailableSettings(); getChildView("block_list")->setEnabled(LLLoginInstance::getInstance()->authSuccess()); - - // Cannot have floater active until caps have been received - getChild<LLButton>("default_creation_permissions")->setEnabled(LLStartUp::getStartupState() < STATE_STARTED ? false : true); } // static @@ -1411,7 +1411,7 @@ void LLAvatarComplexityControls::setIndirectMaxArc() else { // This is the inverse of the calculation in updateMaxComplexity - indirect_max_arc = (U32)((log(max_arc) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE) + MIN_INDIRECT_ARC_LIMIT; + indirect_max_arc = (U32)ll_round(((log(F32(max_arc)) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE)) + MIN_INDIRECT_ARC_LIMIT; } gSavedSettings.setU32("IndirectMaxComplexity", indirect_max_arc); } @@ -1930,7 +1930,7 @@ void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* valu { // if this is changed, the inverse calculation in setIndirectMaxArc // must be changed to match - max_arc = (U32)exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT))); + max_arc = (U32)ll_round(exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT)))); } gSavedSettings.setU32("RenderAvatarMaxComplexity", (U32)max_arc); @@ -2004,7 +2004,7 @@ void LLFloaterPreference::onClickAutoReplace() void LLFloaterPreference::onClickSpellChecker() { - LLFloaterReg::showInstance("prefs_spellchecker"); + LLFloaterReg::showInstance("prefs_spellchecker"); } void LLFloaterPreference::onClickAdvanced() diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index ed6f4ede9f..a6ce0ba678 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -192,7 +192,6 @@ BOOL LLFloaterReporter::postBuild() mOwnerName = LLStringUtil::null; getChild<LLUICtrl>("summary_edit")->setFocus(TRUE); - getChild<LLCheckBoxCtrl>("screen_check")->set(TRUE); mDefaultSummary = getChild<LLUICtrl>("details_edit")->getValue().asString(); @@ -246,8 +245,6 @@ LLFloaterReporter::~LLFloaterReporter() // virtual void LLFloaterReporter::draw() { - getChildView("screen_check")->setEnabled(TRUE ); - LLFloater::draw(); } @@ -255,7 +252,6 @@ void LLFloaterReporter::enableControls(BOOL enable) { getChildView("category_combo")->setEnabled(enable); getChildView("chat_check")->setEnabled(enable); - getChildView("screen_check")->setEnabled(enable); getChildView("screenshot")->setEnabled(FALSE); getChildView("pick_btn")->setEnabled(enable); getChildView("summary_edit")->setEnabled(enable); @@ -448,23 +444,15 @@ void LLFloaterReporter::onClickSend(void *userdata) if(!url.empty() || !sshot_url.empty()) { self->sendReportViaCaps(url, sshot_url, self->gatherReport()); + LLNotificationsUtil::add("HelpReportAbuseConfirm"); self->closeFloater(); } else { - if(self->getChild<LLUICtrl>("screen_check")->getValue()) - { - self->getChildView("send_btn")->setEnabled(FALSE); - self->getChildView("cancel_btn")->setEnabled(FALSE); - // the callback from uploading the image calls sendReportViaLegacy() - self->uploadImage(); - } - else - { - self->sendReportViaLegacy(self->gatherReport()); - LLUploadDialog::modalUploadFinished(); - self->closeFloater(); - } + self->getChildView("send_btn")->setEnabled(FALSE); + self->getChildView("cancel_btn")->setEnabled(FALSE); + // the callback from uploading the image calls sendReportViaLegacy() + self->uploadImage(); } } } @@ -713,10 +701,7 @@ LLSD LLFloaterReporter::gatherReport() // only send a screenshot ID if we're asked to and the email is // going to LL - Estate Owners cannot see the screenshot asset LLUUID screenshot_id = LLUUID::null; - if (getChild<LLUICtrl>("screen_check")->getValue()) - { - screenshot_id = getChild<LLUICtrl>("screenshot")->getValue(); - }; + screenshot_id = getChild<LLUICtrl>("screenshot")->getValue(); LLSD report = LLSD::emptyMap(); report["report-type"] = (U8) mReportType; @@ -770,7 +755,7 @@ void LLFloaterReporter::finishedARPost(const LLSD &) void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report) { - if(getChild<LLUICtrl>("screen_check")->getValue().asBoolean() && !sshot_url.empty()) + if(!sshot_url.empty()) { // try to upload screenshot LLResourceUploadInfo::ptr_t uploadInfo(new LLARScreenShotUploader(report, mResourceDatap->mAssetInfo.mUuid, mResourceDatap->mAssetInfo.mType)); @@ -885,6 +870,7 @@ void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data, self->mScreenID = uuid; LL_INFOS() << "Got screen shot " << uuid << LL_ENDL; self->sendReportViaLegacy(self->gatherReport()); + LLNotificationsUtil::add("HelpReportAbuseConfirm"); self->closeFloater(); } } diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 7b8fc5b35b..eae16b9f03 100644 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -660,6 +660,8 @@ BOOL LLPanelScriptLimitsRegionMemory::postBuild() { return FALSE; } + list->setCommitCallback(boost::bind(&LLPanelScriptLimitsRegionMemory::checkButtonsEnabled, this)); + checkButtonsEnabled(); //set all columns to resizable mode even if some columns will be empty for(S32 column = 0; column < list->getNumColumns(); column++) @@ -750,6 +752,14 @@ void LLPanelScriptLimitsRegionMemory::clearList() getChild<LLUICtrl>("parcels_listed")->setValue(LLSD(msg_empty_string)); mObjectListItems.clear(); + checkButtonsEnabled(); +} + +void LLPanelScriptLimitsRegionMemory::checkButtonsEnabled() +{ + LLScrollListCtrl* list = getChild<LLScrollListCtrl>("scripts_list"); + getChild<LLButton>("highlight_btn")->setEnabled(list->getNumSelected() > 0); + getChild<LLButton>("return_btn")->setEnabled(list->getNumSelected() > 0); } // static diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index e3cbbd185f..2ac3862b4f 100644 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -113,6 +113,7 @@ public: void showBeacon(); void returnObjectsFromParcel(S32 local_id); void returnObjects(); + void checkButtonsEnabled(); private: void onNameCache(const LLUUID& id, diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp index 0cb37dabe7..b139e5daf5 100644 --- a/indra/newview/llfloatersellland.cpp +++ b/indra/newview/llfloatersellland.cpp @@ -257,7 +257,6 @@ void LLFloaterSellLandUI::setBadge(const char* id, Badge badge) static std::string badgeOK("badge_ok.j2c"); static std::string badgeNote("badge_note.j2c"); static std::string badgeWarn("badge_warn.j2c"); - static std::string badgeError("badge_error.j2c"); std::string badgeName; switch (badge) @@ -266,7 +265,7 @@ void LLFloaterSellLandUI::setBadge(const char* id, Badge badge) case BADGE_OK: badgeName = badgeOK; break; case BADGE_NOTE: badgeName = badgeNote; break; case BADGE_WARN: badgeName = badgeWarn; break; - case BADGE_ERROR: badgeName = badgeError; break; + case BADGE_ERROR: badgeName = badgeWarn; break; } getChild<LLUICtrl>(id)->setValue(badgeName); diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index ff7594a531..b5ba64716d 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -1375,7 +1375,7 @@ const LLVector3d& LLFloaterSnapshotBase::getPosTakenGlobal() // static void LLFloaterSnapshot::setAgentEmail(const std::string& email) { - LLFloaterSnapshot* instance = getInstance(); + LLFloaterSnapshot* instance = findInstance(); if (instance) { LLSideTrayPanelContainer* panel_container = instance->getChild<LLSideTrayPanelContainer>("panel_container"); diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 024e315632..dece3fc1ea 100644 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -55,7 +55,8 @@ LLFloaterWebContent::_Params::_Params() preferred_media_size("preferred_media_size"), trusted_content("trusted_content", false), show_page_title("show_page_title", true), - clean_browser("clean_browser", false) + clean_browser("clean_browser", false), + dev_mode("dev_mode", false) {} LLFloaterWebContent::LLFloaterWebContent( const Params& params ) @@ -74,14 +75,16 @@ LLFloaterWebContent::LLFloaterWebContent( const Params& params ) mShowPageTitle(params.show_page_title), mAllowNavigation(true), mCurrentURL(""), - mDisplayURL("") + mDisplayURL(""), + mDevelopMode(params.dev_mode) // if called from "Develop" Menu, set a flag and change things to be more useful for devs { mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this )); mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this )); mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this )); mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this )); mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this )); - mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this )); + mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind(&LLFloaterWebContent::onPopExternal, this)); + mCommitCallbackRegistrar.add( "WebContent.TestURL", boost::bind(&LLFloaterWebContent::onTestURL, this, _2)); } BOOL LLFloaterWebContent::postBuild() @@ -195,8 +198,6 @@ void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height) width + getRect().getWidth() - browser_rect.getWidth(), height + getRect().getHeight() - browser_rect.getHeight()); - LL_DEBUGS() << "geometry change: " << geom << LL_ENDL; - LLRect new_rect; getParent()->screenRectToLocal(geom, &new_rect); setShape(new_rect); @@ -205,8 +206,6 @@ void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height) // static void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p) { - LL_DEBUGS() << "url = " << p.url() << ", target = " << p.target() << ", uuid = " << p.id() << LL_ENDL; - if (!p.id.isProvided()) { p.id = LLUUID::generateNewID().asString(); @@ -224,12 +223,6 @@ void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p) // and close the least recently opened one if this will put us over the limit. LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList(p.window_class); - LL_DEBUGS() << "total instance count is " << instances.size() << LL_ENDL; - - for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++) - { - LL_DEBUGS() << " " << (*iter)->getKey()["target"] << LL_ENDL; - } if(instances.size() >= (size_t)browser_window_limit) { @@ -241,16 +234,19 @@ void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p) void LLFloaterWebContent::open_media(const Params& p) { - // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin. LLViewerMedia::proxyWindowOpened(p.target(), p.id()); - mWebBrowser->setHomePageUrl(p.url, HTTP_CONTENT_TEXT_HTML); + mWebBrowser->setHomePageUrl(p.url); mWebBrowser->setTarget(p.target); - mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML, p.clean_browser); + mWebBrowser->navigateTo(p.url); set_current_url(p.url); getChild<LLLayoutPanel>("status_bar")->setVisible(p.show_chrome); getChild<LLLayoutPanel>("nav_controls")->setVisible(p.show_chrome); + + // turn additional debug controls on but only for Develop mode (Develop menu open) + getChild<LLLayoutPanel>("debug_controls")->setVisible(mDevelopMode); + bool address_entry_enabled = p.allow_address_entry && !p.trusted_content; mAllowNavigation = p.allow_back_forward_navigation; getChildView("address")->setEnabled(address_entry_enabled); @@ -499,7 +495,7 @@ void LLFloaterWebContent::onEnterAddress() LLStringUtil::trim(url); if ( url.length() > 0 ) { - mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); + mWebBrowser->navigateTo(url); }; } @@ -508,9 +504,18 @@ void LLFloaterWebContent::onPopExternal() // make sure there is at least something there. // (perhaps this test should be for minimum length of a URL) std::string url = mAddressCombo->getValue().asString(); - LLStringUtil::trim(url); - if ( url.length() > 0 ) + LLStringUtil::trim(url); + if (url.length() > 0) + { + LLWeb::loadURLExternal(url); + }; +} + +void LLFloaterWebContent::onTestURL(std::string url) +{ + LLStringUtil::trim(url); + if (url.length() > 0) { - LLWeb::loadURLExternal( url ); + mWebBrowser->navigateTo(url); }; } diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h index 4291fd9f2c..0bf93504c2 100644 --- a/indra/newview/llfloaterwebcontent.h +++ b/indra/newview/llfloaterwebcontent.h @@ -58,7 +58,8 @@ public: allow_back_forward_navigation, trusted_content, show_page_title, - clean_browser; + clean_browser, + dev_mode; Optional<LLRect> preferred_media_size; _Params(); @@ -92,6 +93,7 @@ protected: void onClickStop(); void onEnterAddress(); void onPopExternal(); + void onTestURL(std::string url); static void preCreate(Params& p); void open_media(const Params& ); @@ -113,6 +115,7 @@ protected: std::string mUUID; bool mShowPageTitle; bool mAllowNavigation; + bool mDevelopMode; }; #endif // LL_LLFLOATERWEBCONTENT_H diff --git a/indra/newview/llgroupiconctrl.cpp b/indra/newview/llgroupiconctrl.cpp index 271dd44c1f..7c2a3cad43 100644 --- a/indra/newview/llgroupiconctrl.cpp +++ b/indra/newview/llgroupiconctrl.cpp @@ -74,9 +74,16 @@ LLGroupIconCtrl::~LLGroupIconCtrl() LLGroupMgr::getInstance()->removeObserver(this); } -void LLGroupIconCtrl::setIconId(const LLSD& value) +void LLGroupIconCtrl::setIconId(const LLUUID& icon_id) { - LLIconCtrl::setValue(value); + if (icon_id.notNull()) + { + LLIconCtrl::setValue(icon_id); + } + else + { + LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); + } } void LLGroupIconCtrl::setValue(const LLSD& value) @@ -122,14 +129,7 @@ bool LLGroupIconCtrl::updateFromCache() LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mGroupId); if (!group_data) return false; - if (group_data->mInsigniaID.notNull()) - { - LLIconCtrl::setValue(group_data->mInsigniaID); - } - else - { - LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); - } + setIconId(group_data->mInsigniaID); if (mDrawTooltip && !group_data->mName.empty()) { diff --git a/indra/newview/llgroupiconctrl.h b/indra/newview/llgroupiconctrl.h index f8b22cf581..43e384d3e2 100644 --- a/indra/newview/llgroupiconctrl.h +++ b/indra/newview/llgroupiconctrl.h @@ -66,7 +66,13 @@ public: */ virtual void setValue(const LLSD& value); - void setIconId(const LLSD& value); + /** + * Sets icon_id as icon value directly. Avoids LLGroupMgr cache checks for group id + * Uses default icon in case id is null. + * + * @params icon_id - it is processed as icon id, default image will be used in case id is null. + */ + void setIconId(const LLUUID& icon_id); // LLGroupMgrObserver observer trigger virtual void changed(LLGroupChange gc); diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 6126db2988..62414d3bbb 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -379,10 +379,7 @@ void LLGroupListItem::setGroupID(const LLUUID& group_id) void LLGroupListItem::setGroupIconID(const LLUUID& group_icon_id) { - if (group_icon_id.notNull()) - { - mGroupIcon->setIconId(group_icon_id); - } + mGroupIcon->setIconId(group_icon_id); } void LLGroupListItem::setGroupIconVisible(bool visible) diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 52e83fe412..6b1e196182 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -53,7 +53,7 @@ const F32 VERTICAL_PADDING = 12.f; const F32 BUFFER_SIZE = 2.f; const F32 HUD_TEXT_MAX_WIDTH = 190.f; const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f; -const F32 MAX_DRAW_DISTANCE = 64.f; +const F32 MAX_DRAW_DISTANCE = 300.f; std::set<LLPointer<LLHUDText> > LLHUDText::sTextObjects; std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleTextObjects; @@ -394,7 +394,20 @@ void LLHUDText::updateVisibility() LLVector3 pos_agent_center = gAgent.getPosAgentFromGlobal(mPositionGlobal) - dir_from_camera; F32 last_distance_center = (pos_agent_center - LLViewerCamera::getInstance()->getOrigin()).magVec(); - if(last_distance_center > MAX_DRAW_DISTANCE) + F32 max_draw_distance = gSavedSettings.getF32("PrimTextMaxDrawDistance"); + + if(max_draw_distance < 0) + { + max_draw_distance = 0; + gSavedSettings.setF32("PrimTextMaxDrawDistance", max_draw_distance); + } + else if(max_draw_distance > MAX_DRAW_DISTANCE) + { + max_draw_distance = MAX_DRAW_DISTANCE; + gSavedSettings.setF32("PrimTextMaxDrawDistance", MAX_DRAW_DISTANCE); + } + + if(last_distance_center > max_draw_distance) { mVisible = FALSE; return; diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp index 8e91af321e..a4fce36783 100644 --- a/indra/newview/llinspectgroup.cpp +++ b/indra/newview/llinspectgroup.cpp @@ -41,6 +41,7 @@ #include "lltooltip.h" // positionViewNearMouse() #include "lltrans.h" #include "lluictrl.h" +#include "llgroupiconctrl.h" ////////////////////////////////////////////////////////////////////////////// // LLInspectGroup @@ -233,7 +234,7 @@ void LLInspectGroup::processGroupData() getChild<LLUICtrl>("group_details")->setValue( LLSD(data->mCharter) ); - getChild<LLUICtrl>("group_icon")->setValue( LLSD(data->mInsigniaID) ); + getChild<LLGroupIconCtrl>("group_icon")->setIconId(data->mInsigniaID); std::string cost; bool is_member = LLGroupActions::isInGroup(mGroupID); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 9f0b35fc8c..eebb6a0384 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -286,6 +286,16 @@ BOOL LLInvFVBridge::cutToClipboard() return FALSE; } +// virtual +bool LLInvFVBridge::isCutToClipboard() +{ + if (LLClipboard::instance().isCutMode()) + { + return LLClipboard::instance().isOnClipboard(mUUID); + } + return false; +} + // Callback for cutToClipboard if DAMA required... BOOL LLInvFVBridge::callback_cutToClipboard(const LLSD& notification, const LLSD& response) { @@ -307,9 +317,7 @@ BOOL LLInvFVBridge::perform_cutToClipboard() if (obj && isItemMovable() && isItemRemovable()) { LLClipboard::instance().setCutMode(true); - BOOL added_to_clipboard = LLClipboard::instance().addToClipboard(mUUID); - removeObject(&gInventory, mUUID); // Always perform the remove even if the object couldn't make it to the clipboard - return added_to_clipboard; + return LLClipboard::instance().addToClipboard(mUUID); } return FALSE; } @@ -1390,6 +1398,12 @@ bool LLInvFVBridge::canShare() const // Categories can be given. can_share = (model->getCategory(mUUID) != NULL); } + + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if ((mUUID == trash_id) || gInventory.isObjectDescendentOf(mUUID, trash_id)) + { + can_share = false; + } } } @@ -1925,13 +1939,15 @@ BOOL LLItemBridge::removeItem() } // move it to the trash - LLPreview::hide(mUUID, TRUE); LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); LLViewerInventoryItem* item = getItem(); if (!item) return FALSE; - + if (item->getType() != LLAssetType::AT_LSL_TEXT) + { + LLPreview::hide(mUUID, TRUE); + } // Already in trash if (model->isObjectDescendentOf(mUUID, trash_id)) return FALSE; diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 9053c61171..df25e01688 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -116,6 +116,7 @@ public: virtual BOOL isItemCopyable() const { return FALSE; } virtual BOOL copyToClipboard() const; virtual BOOL cutToClipboard(); + virtual bool isCutToClipboard(); virtual BOOL isClipboardPasteable() const; virtual BOOL isClipboardPasteableAsLink() const; virtual void pasteFromClipboard() {} diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 003bbcafed..e995c138b4 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -84,21 +84,18 @@ LLInventoryFilter::LLInventoryFilter(const Params& p) bool LLInventoryFilter::check(const LLFolderViewModelItem* item) { const LLFolderViewModelItemInventory* listener = dynamic_cast<const LLFolderViewModelItemInventory*>(item); - // Clipboard cut items are *always* filtered so we need this value upfront - const BOOL passed_clipboard = (listener ? checkAgainstClipboard(listener->getUUID()) : TRUE); // If it's a folder and we're showing all folders, return automatically. const BOOL is_folder = listener->getInventoryType() == LLInventoryType::IT_CATEGORY; if (is_folder && (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)) { - return passed_clipboard; + return true; } bool passed = (mFilterSubString.size() ? listener->getSearchableName().find(mFilterSubString) != std::string::npos : true); passed = passed && checkAgainstFilterType(listener); passed = passed && checkAgainstPermissions(listener); passed = passed && checkAgainstFilterLinks(listener); - passed = passed && passed_clipboard; return passed; } @@ -108,9 +105,8 @@ bool LLInventoryFilter::check(const LLInventoryItem* item) const bool passed_string = (mFilterSubString.size() ? item->getName().find(mFilterSubString) != std::string::npos : true); const bool passed_filtertype = checkAgainstFilterType(item); const bool passed_permissions = checkAgainstPermissions(item); - const bool passed_clipboard = checkAgainstClipboard(item->getUUID()); - return passed_filtertype && passed_permissions && passed_clipboard && passed_string; + return passed_filtertype && passed_permissions && passed_string; } bool LLInventoryFilter::checkFolder(const LLFolderViewModelItem* item) const @@ -129,13 +125,10 @@ bool LLInventoryFilter::checkFolder(const LLFolderViewModelItem* item) const bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const { - // Always check against the clipboard - const BOOL passed_clipboard = checkAgainstClipboard(folder_id); - // we're showing all folders, overriding filter if (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS) { - return passed_clipboard; + return true; } // when applying a filter, matching folders get their contents downloaded first @@ -201,7 +194,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const LLViewerInventoryItem* item = gInventory.getItem(folder_id); if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) { - return passed_clipboard; + return true; } if (mFilterOps.mFilterTypes & FILTERTYPE_CATEGORY) @@ -216,7 +209,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const return false; } - return passed_clipboard; + return true; } bool LLInventoryFilter::checkAgainstFilterType(const LLFolderViewModelItemInventory* listener) const diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9a33e210ff..503fa28a33 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -582,7 +582,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, // Add the category to the internal representation LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); - cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 cat->setDescendentCount(0); LLCategoryUpdate update(cat->getParentUUID(), 1); accountForUpdate(update); @@ -640,7 +640,7 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv result["parent_id"].asUUID(), (LLFolderType::EType)result["type"].asInteger(), result["name"].asString(), gAgent.getID()); - cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 cat->setDescendentCount(0); LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); @@ -914,8 +914,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id); if( item_array ) { + LLInventoryModel::LLCategoryUpdate update(category_id, 1); + gInventory.accountForUpdate(update); + // *FIX: bit of a hack to call update server from here... - new_item->updateServer(TRUE); + new_item->updateParentOnServer(FALSE); item_array->push_back(new_item); } else @@ -956,9 +959,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) item_array = get_ptr_in_map(mParentChildItemTree, parent_id); if(item_array) { + LLInventoryModel::LLCategoryUpdate update(parent_id, 1); + gInventory.accountForUpdate(update); // *FIX: bit of a hack to call update server from // here... - new_item->updateServer(TRUE); + new_item->updateParentOnServer(FALSE); item_array->push_back(new_item); } else @@ -1045,7 +1050,6 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 if(old_cat) { // We already have an old category, modify its values - U32 mask = LLInventoryObserver::NONE; LLUUID old_parent_id = old_cat->getParentUUID(); LLUUID new_parent_id = cat->getParentUUID(); if(old_parent_id != new_parent_id) @@ -1100,7 +1104,8 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 item_array_t* itemsp = new item_array_t; mParentChildCategoryTree[new_cat->getUUID()] = catsp; mParentChildItemTree[new_cat->getUUID()] = itemsp; - addChangedMask(LLInventoryObserver::ADD, cat->getUUID()); + mask |= LLInventoryObserver::ADD; + addChangedMask(mask, cat->getUUID()); } } @@ -1390,7 +1395,11 @@ void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool f } // From purgeObject() - LLPreview::hide(object_id); + LLViewerInventoryItem *item = getItem(object_id); + if (item && (item->getType() != LLAssetType::AT_LSL_TEXT)) + { + LLPreview::hide(object_id, TRUE); + } deleteObject(object_id, fix_broken_links, do_notify_observers); } } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index aa934f95a1..a55938f334 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -181,7 +181,12 @@ bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate) if (gDirUtilp->fileExists(mFilename)) { // verifying that the file has indeed been modified + +#ifndef LL_WINDOWS const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename)); +#else + const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(utf8str_to_utf16str(mFilename))); +#endif LLSD new_last_modified = asctime(localtime(&temp_time)); if (mLastModified.asString() != new_last_modified.asString()) diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 53b2ca2b74..11bc1425f9 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -243,7 +243,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) params.commit_on_focus_lost(false); params.follows.flags(FOLLOWS_ALL); mTextEntry = LLUICtrlFactory::create<LLURLLineEditor>(params); - mTextEntry->setContextMenu(NULL); + mTextEntry->resetContextMenu(); addChild(mTextEntry); // LLLineEditor is replaced with LLLocationLineEditor diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 639641d1c2..485d4677b1 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -244,7 +244,10 @@ std::string LLLogChat::makeLogFileName(std::string filename) filename = cleanFileName(filename); filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename); - filename += '.' + LL_TRANSCRIPT_FILE_EXTENSION; + if (!filename.empty()) + { + filename += '.' + LL_TRANSCRIPT_FILE_EXTENSION; + } return filename; } diff --git a/indra/newview/llmanip.h b/indra/newview/llmanip.h index 1fb05e047a..69881e8589 100644 --- a/indra/newview/llmanip.h +++ b/indra/newview/llmanip.h @@ -1,4 +1,4 @@ -/** +/** * @file llmanip.h * @brief LLManip class definition * @@ -37,7 +37,7 @@ class LLToolComposite; class LLVector3; class LLObjectSelection; -const S32 MIN_DIVISION_PIXEL_WIDTH = 9; +const S32 MIN_DIVISION_PIXEL_WIDTH = 3; class LLManip : public LLTool { diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index b4259a456c..3975d3980b 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llmaniptranslate.cpp * @brief LLManipTranslate class implementation * @@ -548,12 +548,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) if (off_axis_magnitude > mSnapOffsetMeters) { mInSnapRegime = TRUE; - LLVector3 mouse_down_offset(mDragCursorStartGlobal - mDragSelectionStartGlobal); LLVector3 cursor_snap_agent = gAgent.getPosAgentFromGlobal(cursor_point_snap_line); - if (!gSavedSettings.getBOOL("SnapToMouseCursor")) - { - cursor_snap_agent -= mouse_down_offset; - } F32 cursor_grid_dist = (cursor_snap_agent - mGridOrigin) * axis_f; diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 6cc7a0fc99..54f95520db 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -773,7 +773,9 @@ void LLMarketplaceData::getMerchantStatusCoro() std::string url = getSLMConnectURL("/merchant"); if (url.empty()) { - LL_INFOS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL; + LL_WARNS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL; + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE); + return; } LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts); diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 9cf3249983..00043d1e72 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -1007,7 +1007,11 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) std::string uuid = self->getClickUUID(); LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << target << "\", uri is " << url << LL_ENDL; - LLWeb::loadURL(url, target, std::string()); + // try as slurl first + if (!LLURLDispatcher::dispatch(url, "clicked", NULL, mTrusted)) + { + LLWeb::loadURL(url, target, std::string()); + } // CP: removing this code because we no longer support popups so this breaks the flow. // replaced with a bare call to LLWeb::LoadURL(...) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 54f8fb93d0..9dacae2c4e 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1753,6 +1753,11 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size) { + if (data == NULL || data_size == 0) + { + return false; + } + LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); std::string mesh_string((char*) data, data_size); std::istringstream stream(mesh_string); @@ -1896,7 +1901,8 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 } LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, - bool upload_skin, bool upload_joints, const std::string & upload_url, bool do_upload, + bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, + const std::string & upload_url, bool do_upload, LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer) : LLThread("mesh upload"), @@ -1911,6 +1917,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadTextures = upload_textures; mUploadSkin = upload_skin; mUploadJoints = upload_joints; + mLockScaleIfJointPosition = lock_scale_if_joint_position; mMutex = new LLMutex(NULL); mPendingUploads = 0; mFinished = false; @@ -2097,6 +2104,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) decomp, mUploadSkin, mUploadJoints, + mLockScaleIfJointPosition, FALSE, FALSE, data.mBaseModel->mSubmodelID); @@ -2255,6 +2263,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) decomp, mUploadSkin, mUploadJoints, + mLockScaleIfJointPosition, FALSE, FALSE, data.mBaseModel->mSubmodelID); @@ -3010,12 +3019,23 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b } else if (data && data_size > 0) { - // header was successfully retrieved from sim, cache in vfs - LLSD header = gMeshRepo.mThread->mMeshHeader[mesh_id]; + // header was successfully retrieved from sim and parsed, cache in vfs + S32 header_bytes = 0; + LLSD header; - S32 version = header["version"].asInteger(); + gMeshRepo.mThread->mHeaderMutex->lock(); + LLMeshRepoThread::mesh_header_map::iterator iter = gMeshRepo.mThread->mMeshHeader.find(mesh_id); + if (iter != gMeshRepo.mThread->mMeshHeader.end()) + { + header_bytes = (S32)gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; + header = iter->second; + } + gMeshRepo.mThread->mHeaderMutex->unlock(); - if (version <= MAX_MESH_VERSION) + if (header_bytes > 0 + && !header.has("404") + && header.has("version") + && header["version"].asInteger() <= MAX_MESH_VERSION) { std::stringstream str; @@ -3064,6 +3084,17 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b } } } + else + { + LL_WARNS(LOG_MESH) << "Trying to cache nonexistent mesh, mesh id: " << mesh_id << LL_ENDL; + + // headerReceived() parsed header, but header's data is invalid so none of the LODs will be available + LLMutexLock lock(gMeshRepo.mThread->mMutex); + for (int i(0); i < 4; ++i) + { + gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); + } + } } } @@ -3946,11 +3977,13 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id) void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, - bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload, + bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, + std::string upload_url, bool do_upload, LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer) { - LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url, - do_upload, fee_observer, upload_observer); + LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, + upload_skin, upload_joints, lock_scale_if_joint_position, + upload_url, do_upload, fee_observer, upload_observer); mUploadWaitList.push_back(thread); } @@ -4115,7 +4148,7 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32 } } - F32 max_area = 102932.f; //area of circle that encompasses region + F32 max_area = 102944.f; //area of circle that encompasses region (see MAINT-6559) F32 min_area = 1.f; F32 high_area = llmin(F_PI*dmid*dmid, max_area); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index a762042597..30f042845a 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -400,6 +400,7 @@ public: bool mUploadTextures; bool mUploadSkin; bool mUploadJoints; + bool mLockScaleIfJointPosition; volatile bool mDiscarded; LLHost mHost; @@ -407,7 +408,8 @@ public: std::string mWholeModelUploadURL; LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures, - bool upload_skin, bool upload_joints, const std::string & upload_url, bool do_upload = true, + bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, + const std::string & upload_url, bool do_upload = true, LLHandle<LLWholeModelFeeObserver> fee_observer = (LLHandle<LLWholeModelFeeObserver>()), LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>())); ~LLMeshUploadThread(); @@ -510,8 +512,10 @@ public: LLSD& getMeshHeader(const LLUUID& mesh_id); void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, - bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload = true, - LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()), LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>())); + bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, + std::string upload_url, bool do_upload = true, + LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()), + LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>())); S32 getMeshSize(const LLUUID& mesh_id, S32 lod); diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 70035bcc74..c3dd08c327 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -252,7 +252,7 @@ void LLFloaterMove::setSittingMode(BOOL bSitting) LLPanelStandStopFlying::setStandStopFlyingMode(LLPanelStandStopFlying::SSFM_STOP_FLYING); } } - enableInstance(!bSitting); + enableInstance(); } // protected @@ -459,7 +459,7 @@ void LLFloaterMove::showModeButtons(BOOL bShow) } //static -void LLFloaterMove::enableInstance(BOOL bEnable) +void LLFloaterMove::enableInstance() { LLFloaterMove* instance = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview"); if (instance) @@ -470,7 +470,7 @@ void LLFloaterMove::enableInstance(BOOL bEnable) } else { - instance->showModeButtons(bEnable); + instance->showModeButtons(isAgentAvatarValid() && !gAgentAvatarp->isSitting()); } } } @@ -566,7 +566,7 @@ BOOL LLPanelStandStopFlying::postBuild() { mStandButton = getChild<LLButton>("stand_btn"); mStandButton->setCommitCallback(boost::bind(&LLPanelStandStopFlying::onStandButtonClick, this)); - mStandButton->setCommitCallback(boost::bind(&LLFloaterMove::enableInstance, TRUE)); + mStandButton->setCommitCallback(boost::bind(&LLFloaterMove::enableInstance)); mStandButton->setVisible(FALSE); LLHints::registerHintTarget("stand_btn", mStandButton->getHandle()); @@ -685,8 +685,7 @@ void LLPanelStandStopFlying::onStandButtonClick() LLSelectMgr::getInstance()->deselectAllForStandingUp(); gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); - setFocus(FALSE); // EXT-482 - mStandButton->setVisible(FALSE); // force visibility changing to avoid seeing Stand & Move buttons at once. + setFocus(FALSE); } void LLPanelStandStopFlying::onStopFlyingButtonClick() @@ -694,7 +693,6 @@ void LLPanelStandStopFlying::onStopFlyingButtonClick() gAgent.setFlying(FALSE); setFocus(FALSE); // EXT-482 - mStopFlyingButton->setVisible(FALSE); } /** diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h index c525d9dfdb..4a31f2a814 100644 --- a/indra/newview/llmoveview.h +++ b/indra/newview/llmoveview.h @@ -56,7 +56,7 @@ public: static void setAlwaysRunMode(bool run); void setAlwaysRunModeImpl(bool run); static void setSittingMode(BOOL bSitting); - static void enableInstance(BOOL bEnable); + static void enableInstance(); /*virtual*/ void onOpen(const LLSD& key); static void sUpdateFlyingStatus(); diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 2657b84ef3..63ab88da42 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -96,17 +96,21 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification) LLUUID from_id = notification->getPayload()["from_id"]; - //Will not play a notification sound for inventory and teleport offer based upon chat preference - bool playSound = (!notification->isDND() - && ((notification->getName() == "UserGiveItem" - && gSavedSettings.getBOOL("PlaySoundInventoryOffer")) - || (notification->getName() == "TeleportOffered" - && gSavedSettings.getBOOL("PlaySoundTeleportOffer")))); - - if(playSound) - { - notification->playSound(); - } + if (!notification->isDND()) + { + //Will not play a notification sound for inventory and teleport offer based upon chat preference + bool playSound = (notification->getName() == "UserGiveItem" + && gSavedSettings.getBOOL("PlaySoundInventoryOffer")) + || ((notification->getName() == "TeleportOffered" + || notification->getName() == "TeleportOffered_MaturityExceeded" + || notification->getName() == "TeleportOffered_MaturityBlocked") + && gSavedSettings.getBOOL("PlaySoundTeleportOffer")); + + if (playSound) + { + notification->playSound(); + } + } LLHandlerUtil::spawnIMSession(name, from_id); LLHandlerUtil::addNotifPanelToIM(notification); diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 65fd3f95ab..de6a36ce2f 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -999,7 +999,7 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id) } } - if (mGalleryCreated) + if (mGalleryCreated && !LLApp::isQuitting()) { reArrangeRows(); } diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index b2164c1f21..d17f5494a0 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -199,7 +199,7 @@ void LLPanelGroupGeneral::setupCtrls(LLPanel* panel_group) mGroupNameEditor = panel_group->getChild<LLLineEditor>("group_name_editor"); - mGroupNameEditor->setPrevalidate( LLTextValidate::validateASCII ); + mGroupNameEditor->setPrevalidate( LLTextValidate::validateASCIINoLeadingSpace ); } diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 8331c152e2..8b9941c0ca 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -1059,9 +1059,6 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void) case LLAssetType::AT_BODYPART: applyListViewFilter(LVIT_BODYPART); break; - case LLAssetType::AT_GESTURE: - applyListViewFilter(LVIT_GESTURES); - break; case LLAssetType::AT_CLOTHING: default: applyListViewFilter(LVIT_CLOTHING); diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index 841bb4337a..30870daf40 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -80,7 +80,6 @@ public: { LVIT_ALL = 0, LVIT_CLOTHING, - LVIT_GESTURES, LVIT_BODYPART, LVIT_ATTACHMENT, LVIT_SHAPE, diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 763657ebad..0bcd8a9e63 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -95,7 +95,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() : mVolumeSliderVisible(0), mWindowShade(NULL), mHideImmediately(false), - mSecureURL(false) + mSecureURL(false), + mMediaPlaySliderCtrlMouseDownValue(0.0) { mCommitCallbackRegistrar.add("MediaCtrl.Close", boost::bind(&LLPanelPrimMediaControls::onClickClose, this)); mCommitCallbackRegistrar.add("MediaCtrl.Back", boost::bind(&LLPanelPrimMediaControls::onClickBack, this)); @@ -109,7 +110,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() : mCommitCallbackRegistrar.add("MediaCtrl.Open", boost::bind(&LLPanelPrimMediaControls::onClickOpen, this)); mCommitCallbackRegistrar.add("MediaCtrl.Zoom", boost::bind(&LLPanelPrimMediaControls::onClickZoom, this)); mCommitCallbackRegistrar.add("MediaCtrl.CommitURL", boost::bind(&LLPanelPrimMediaControls::onCommitURL, this)); - mCommitCallbackRegistrar.add("MediaCtrl.JumpProgress", boost::bind(&LLPanelPrimMediaControls::onCommitSlider, this)); + mCommitCallbackRegistrar.add("MediaCtrl.MouseDown", boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseDown, this)); + mCommitCallbackRegistrar.add("MediaCtrl.MouseUp", boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseUp, this)); mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeUp", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeUp, this)); mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this)); mCommitCallbackRegistrar.add("MediaCtrl.Volume", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeSlider, this)); @@ -1246,26 +1248,38 @@ void LLPanelPrimMediaControls::setCurrentURL() #endif // USE_COMBO_BOX_FOR_MEDIA_URL } -void LLPanelPrimMediaControls::onCommitSlider() + +void LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseDown() { - focusOnTarget(); + mMediaPlaySliderCtrlMouseDownValue = mMediaPlaySliderCtrl->getValue().asReal(); - LLViewerMediaImpl* media_impl = getTargetMediaImpl(); - if (media_impl) + mUpdateSlider = false; +} + +void LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseUp() +{ + F64 cur_value = mMediaPlaySliderCtrl->getValue().asReal(); + + if (mMediaPlaySliderCtrlMouseDownValue != cur_value) { - // get slider value - F64 slider_value = mMediaPlaySliderCtrl->getValue().asReal(); - if(slider_value <= 0.0) - { - media_impl->stop(); - } - else + focusOnTarget(); + + LLViewerMediaImpl* media_impl = getTargetMediaImpl(); + if (media_impl) { - media_impl->seek(slider_value*mMovieDuration); - //mUpdateSlider= false; + if (cur_value <= 0.0) + { + media_impl->stop(); + } + else + { + media_impl->seek(cur_value * mMovieDuration); + } } + + mUpdateSlider = true; } -} +} void LLPanelPrimMediaControls::onCommitVolumeUp() { diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h index 6d2eb3430e..21d5236074 100644 --- a/indra/newview/llpanelprimmediacontrols.h +++ b/indra/newview/llpanelprimmediacontrols.h @@ -107,8 +107,10 @@ private: void updateZoom(); void setCurrentURL(); - void onCommitSlider(); - + + void onMediaPlaySliderCtrlMouseDown(); + void onMediaPlaySliderCtrlMouseUp(); + void onCommitVolumeUp(); void onCommitVolumeDown(); void onCommitVolumeSlider(); @@ -219,6 +221,8 @@ private: S32 mVolumeSliderVisible; LLNotificationPtr mActiveNotification; + + F64 mMediaPlaySliderCtrlMouseDownValue; }; #endif // LL_PANELPRIMMEDIACONTROLS_H diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 184238c40c..8afa35efa0 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -44,19 +44,11 @@ static const std::string PANEL_PICKS = "panel_picks"; std::string getProfileURL(const std::string& agent_name) { - std::string url; - - if (LLGridManager::getInstance()->isInProductionGrid()) - { - url = gSavedSettings.getString("WebProfileURL"); - } - else - { - url = gSavedSettings.getString("WebProfileNonProductionURL"); - } + std::string url = "[WEB_PROFILE_URL][AGENT_NAME]"; LLSD subs; + subs["WEB_PROFILE_URL"] = LLGridManager::getInstance()->getWebProfileURL(); subs["AGENT_NAME"] = agent_name; - url = LLWeb::expandURLSubstitutions(url,subs); + url = LLWeb::expandURLSubstitutions(url, subs); LLStringUtil::toLower(url); return url; } diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index d0353259a5..796372ba04 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -30,13 +30,19 @@ #include "lltoggleablemenu.h" +#include "llagent.h" +#include "llaccordionctrl.h" +#include "llaccordionctrltab.h" #include "llappearancemgr.h" #include "llfloatersidepanelcontainer.h" #include "llinventoryfunctions.h" +#include "llinventoryicon.h" #include "llinventorymodel.h" #include "llinventoryobserver.h" #include "llmenubutton.h" +#include "llscrolllistctrl.h" #include "llviewermenu.h" +#include "llviewerregion.h" #include "llwearableitemslist.h" #include "llsdserialize.h" #include "llclipboard.h" @@ -146,11 +152,47 @@ protected: menu->setItemVisible("detach", allow_detach); menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach); menu->setItemVisible("show_original", mUUIDs.size() == 1); + menu->setItemVisible("edit_item", FALSE); } }; ////////////////////////////////////////////////////////////////////////// +class LLTempAttachmentsContextMenu : public LLListContextMenu +{ +public: + LLTempAttachmentsContextMenu(LLPanelWearing* panel_wearing) + : mPanelWearing(panel_wearing) + {} +protected: + /* virtual */ LLContextMenu* createMenu() + { + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("Wearing.EditItem", boost::bind(&LLPanelWearing::onEditAttachment, mPanelWearing)); + registrar.add("Wearing.Detach", boost::bind(&LLPanelWearing::onRemoveAttachment, mPanelWearing)); + LLContextMenu* menu = createFromFile("menu_wearing_tab.xml"); + + updateMenuItemsVisibility(menu); + + return menu; + } + + void updateMenuItemsVisibility(LLContextMenu* menu) + { + menu->setItemVisible("take_off", FALSE); + menu->setItemVisible("detach", TRUE); + menu->setItemVisible("edit_outfit_separator", TRUE); + menu->setItemVisible("show_original", FALSE); + menu->setItemVisible("edit_item", TRUE); + menu->setItemVisible("edit", FALSE); + } + + LLPanelWearing* mPanelWearing; +}; + +////////////////////////////////////////////////////////////////////////// + std::string LLPanelAppearanceTab::sFilterSubString = LLStringUtil::null; static LLPanelInjector<LLPanelWearing> t_panel_wearing("panel_wearing"); @@ -159,30 +201,47 @@ LLPanelWearing::LLPanelWearing() : LLPanelAppearanceTab() , mCOFItemsList(NULL) , mIsInitialized(false) + , mAttachmentsChangedConnection() { mCategoriesObserver = new LLInventoryCategoriesObserver(); mGearMenu = new LLWearingGearMenu(this); mContextMenu = new LLWearingContextMenu(); + mAttachmentsMenu = new LLTempAttachmentsContextMenu(this); } LLPanelWearing::~LLPanelWearing() { delete mGearMenu; delete mContextMenu; + delete mAttachmentsMenu; if (gInventory.containsObserver(mCategoriesObserver)) { gInventory.removeObserver(mCategoriesObserver); } delete mCategoriesObserver; + + if (mAttachmentsChangedConnection.connected()) + { + mAttachmentsChangedConnection.disconnect(); + } } BOOL LLPanelWearing::postBuild() { + mAccordionCtrl = getChild<LLAccordionCtrl>("wearables_accordion"); + mWearablesTab = getChild<LLAccordionCtrlTab>("tab_wearables"); + mAttachmentsTab = getChild<LLAccordionCtrlTab>("tab_temp_attachments"); + mAttachmentsTab->setDropDownStateChangedCallback(boost::bind(&LLPanelWearing::onAccordionTabStateChanged, this)); + mCOFItemsList = getChild<LLWearableItemsList>("cof_items_list"); mCOFItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onWearableItemsListRightClick, this, _1, _2, _3)); + mTempItemsList = getChild<LLScrollListCtrl>("temp_attachments_list"); + mTempItemsList->setFgUnselectedColor(LLColor4::white); + mTempItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onTempAttachmentsListRightClick, this, _1, _2, _3)); + LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn"); menu_gear_btn->setMenu(mGearMenu->getMenu()); @@ -223,6 +282,44 @@ void LLPanelWearing::onOpen(const LLSD& /*info*/) } } +void LLPanelWearing::draw() +{ + if (mUpdateTimer.getStarted() && (mUpdateTimer.getElapsedTimeF32() > 0.1)) + { + mUpdateTimer.stop(); + updateAttachmentsList(); + } + LLPanel::draw(); +} + +void LLPanelWearing::onAccordionTabStateChanged() +{ + if(mAttachmentsTab->isExpanded()) + { + startUpdateTimer(); + mAttachmentsChangedConnection = LLAppearanceMgr::instance().setAttachmentsChangedCallback(boost::bind(&LLPanelWearing::startUpdateTimer, this)); + } + else + { + if (mAttachmentsChangedConnection.connected()) + { + mAttachmentsChangedConnection.disconnect(); + } + } +} + +void LLPanelWearing::startUpdateTimer() +{ + if (!mUpdateTimer.getStarted()) + { + mUpdateTimer.start(); + } + else + { + mUpdateTimer.reset(); + } +} + // virtual void LLPanelWearing::setFilterSubString(const std::string& string) { @@ -251,6 +348,124 @@ bool LLPanelWearing::isActionEnabled(const LLSD& userdata) return false; } +void LLPanelWearing::updateAttachmentsList() +{ + std::vector<LLViewerObject*> attachs = LLAgentWearables::getTempAttachments(); + mTempItemsList->deleteAllItems(); + mAttachmentsMap.clear(); + if(!attachs.empty()) + { + if(!populateAttachmentsList()) + { + requestAttachmentDetails(); + } + } + else + { + std::string no_attachments = getString("no_attachments"); + LLSD row; + row["columns"][0]["column"] = "text"; + row["columns"][0]["value"] = no_attachments; + row["columns"][0]["font"] = "SansSerifBold"; + mTempItemsList->addElement(row); + } +} + +bool LLPanelWearing::populateAttachmentsList(bool update) +{ + bool populated = true; + if(mTempItemsList) + { + mTempItemsList->deleteAllItems(); + mAttachmentsMap.clear(); + std::vector<LLViewerObject*> attachs = LLAgentWearables::getTempAttachments(); + + std::string icon_name = LLInventoryIcon::getIconName(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT); + for (std::vector<LLViewerObject*>::iterator iter = attachs.begin(); + iter != attachs.end(); ++iter) + { + LLViewerObject *attachment = *iter; + LLSD row; + row["id"] = attachment->getID(); + row["columns"][0]["column"] = "icon"; + row["columns"][0]["type"] = "icon"; + row["columns"][0]["value"] = icon_name; + row["columns"][1]["column"] = "text"; + if(mObjectNames.count(attachment->getID()) && !mObjectNames[attachment->getID()].empty()) + { + row["columns"][1]["value"] = mObjectNames[attachment->getID()]; + } + else if(update) + { + row["columns"][1]["value"] = attachment->getID(); + populated = false; + } + else + { + row["columns"][1]["value"] = "Loading..."; + populated = false; + } + mTempItemsList->addElement(row); + mAttachmentsMap[attachment->getID()] = attachment; + } + } + return populated; +} + +void LLPanelWearing::requestAttachmentDetails() +{ + LLSD body; + std::string url = gAgent.getRegion()->getCapability("AttachmentResources"); + if (!url.empty()) + { + LLCoros::instance().launch("LLPanelWearing::getAttachmentLimitsCoro", + boost::bind(&LLPanelWearing::getAttachmentLimitsCoro, this, url)); + } +} + +void LLPanelWearing::getAttachmentLimitsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL; + return; + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + setAttachmentDetails(result); +} + + +void LLPanelWearing::setAttachmentDetails(LLSD content) +{ + mObjectNames.clear(); + S32 number_attachments = content["attachments"].size(); + for(int i = 0; i < number_attachments; i++) + { + S32 number_objects = content["attachments"][i]["objects"].size(); + for(int j = 0; j < number_objects; j++) + { + LLUUID task_id = content["attachments"][i]["objects"][j]["id"].asUUID(); + std::string name = content["attachments"][i]["objects"][j]["name"].asString(); + mObjectNames[task_id] = name; + } + } + if(!mObjectNames.empty()) + { + populateAttachmentsList(true); + } +} + boost::signals2::connection LLPanelWearing::setSelectionChangeCallback(commit_callback_t cb) { if (!mCOFItemsList) return boost::signals2::connection(); @@ -270,6 +485,20 @@ void LLPanelWearing::onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y) mContextMenu->show(ctrl, selected_uuids, x, y); } +void LLPanelWearing::onTempAttachmentsListRightClick(LLUICtrl* ctrl, S32 x, S32 y) +{ + LLScrollListCtrl* list = dynamic_cast<LLScrollListCtrl*>(ctrl); + if (!list) return; + list->selectItemAt(x, y, MASK_NONE); + uuid_vec_t selected_uuids; + + if(list->getCurrentID().notNull()) + { + selected_uuids.push_back(list->getCurrentID()); + mAttachmentsMenu->show(ctrl, selected_uuids, x, y); + } +} + bool LLPanelWearing::hasItemSelected() { return mCOFItemsList->getSelectedItem() != NULL; @@ -280,6 +509,28 @@ void LLPanelWearing::getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const mCOFItemsList->getSelectedUUIDs(selected_uuids); } +void LLPanelWearing::onEditAttachment() +{ + LLScrollListItem* item = mTempItemsList->getFirstSelected(); + if (item) + { + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectAndFamily(mAttachmentsMap[item->getUUID()]); + handle_object_edit(); + } +} + +void LLPanelWearing::onRemoveAttachment() +{ + LLScrollListItem* item = mTempItemsList->getFirstSelected(); + if (item) + { + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectAndFamily(mAttachmentsMap[item->getUUID()]); + LLSelectMgr::getInstance()->sendDropAttachment(); + } +} + void LLPanelWearing::copyToClipboard() { std::string text; diff --git a/indra/newview/llpanelwearing.h b/indra/newview/llpanelwearing.h index 9a212b3cca..c5cb79092a 100644 --- a/indra/newview/llpanelwearing.h +++ b/indra/newview/llpanelwearing.h @@ -31,9 +31,14 @@ // newview #include "llpanelappearancetab.h" +#include "llselectmgr.h" +#include "lltimer.h" +class LLAccordionCtrl; +class LLAccordionCtrlTab; class LLInventoryCategoriesObserver; class LLListContextMenu; +class LLScrollListCtrl; class LLWearableItemsList; class LLWearingGearMenu; @@ -52,6 +57,8 @@ public: /*virtual*/ BOOL postBuild(); + /*virtual*/ void draw(); + /*virtual*/ void onOpen(const LLSD& info); /*virtual*/ void setFilterSubString(const std::string& string); @@ -62,17 +69,43 @@ public: /*virtual*/ void copyToClipboard(); + void startUpdateTimer(); + void updateAttachmentsList(); + boost::signals2::connection setSelectionChangeCallback(commit_callback_t cb); bool hasItemSelected(); + bool populateAttachmentsList(bool update = false); + void onAccordionTabStateChanged(); + void setAttachmentDetails(LLSD content); + void requestAttachmentDetails(); + void onEditAttachment(); + void onRemoveAttachment(); + private: void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y); + void onTempAttachmentsListRightClick(LLUICtrl* ctrl, S32 x, S32 y); + + void getAttachmentLimitsCoro(std::string url); LLInventoryCategoriesObserver* mCategoriesObserver; LLWearableItemsList* mCOFItemsList; + LLScrollListCtrl* mTempItemsList; LLWearingGearMenu* mGearMenu; LLListContextMenu* mContextMenu; + LLListContextMenu* mAttachmentsMenu; + + LLAccordionCtrlTab* mWearablesTab; + LLAccordionCtrlTab* mAttachmentsTab; + LLAccordionCtrl* mAccordionCtrl; + + std::map<LLUUID, LLViewerObject*> mAttachmentsMap; + + std::map<LLUUID, std::string> mObjectNames; + + boost::signals2::connection mAttachmentsChangedConnection; + LLFrameTimer mUpdateTimer; bool mIsInitialized; }; diff --git a/indra/newview/llpathfindinglinksetlist.cpp b/indra/newview/llpathfindinglinksetlist.cpp index b886e46765..eb7b95552e 100644 --- a/indra/newview/llpathfindinglinksetlist.cpp +++ b/indra/newview/llpathfindinglinksetlist.cpp @@ -204,7 +204,10 @@ void LLPathfindingLinksetList::parseLinksetListData(const LLSD& pLinksetListData { const std::string& uuid(linksetDataIter->first); const LLSD& linksetData = linksetDataIter->second; - LLPathfindingObjectPtr linksetPtr(new LLPathfindingLinkset(uuid, linksetData)); - objectMap.insert(std::pair<std::string, LLPathfindingObjectPtr>(uuid, linksetPtr)); + if(linksetData.size() != 0) + { + LLPathfindingObjectPtr linksetPtr(new LLPathfindingLinkset(uuid, linksetData)); + objectMap.insert(std::pair<std::string, LLPathfindingObjectPtr>(uuid, linksetPtr)); + } } } diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp index 9957039f72..836f63bffa 100644 --- a/indra/newview/llpresetsmanager.cpp +++ b/indra/newview/llpresetsmanager.cpp @@ -104,8 +104,7 @@ void LLPresetsManager::loadPresetNamesFromDir(const std::string& dir, preset_nam if (found) { std::string path = gDirUtilp->add(dir, file); - std::string name = gDirUtilp->getBaseFileName(LLURI::unescape(path), /*strip_exten = */ true); - + std::string name = LLURI::unescape(gDirUtilp->getBaseFileName(path, /*strip_exten = */ true)); LL_DEBUGS() << " Found preset '" << name << "'" << LL_ENDL; if (PRESETS_DEFAULT != name) diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 35ac0537a3..fb40af1302 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -37,6 +37,7 @@ #include "lllineeditor.h" #include "lluictrlfactory.h" #include "lluictrlfactory.h" +#include "lldatapacker.h" extern LLAgent gAgent; diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index ba9845ef04..510d91839d 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -437,6 +437,23 @@ void LLPreviewNotecard::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, } } +void LLPreviewNotecard::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId) +{ + + LLSD floater_key; + floater_key["taskid"] = taskId; + floater_key["itemid"] = itemId; + LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", floater_key); + if (nc) + { + if (nc->hasEmbeddedInventory()) + { + gVFS->removeFile(newAssetId, LLAssetType::AT_NOTECARD); + } + nc->setAssetId(newAssetId); + nc->refreshFromInventory(); + } +} bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) { @@ -485,7 +502,7 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) else if (!mObjectUUID.isNull() && !task_url.empty()) { uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID, mItemUUID, LLAssetType::AT_NOTECARD, buffer, - boost::bind(&LLPreviewNotecard::finishInventoryUpload, _1, _3, LLUUID::null))); + boost::bind(&LLPreviewNotecard::finishTaskUpload, _1, _3, mObjectUUID))); url = task_url; } diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index ba571995f6..017c4485ba 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -96,6 +96,7 @@ protected: bool handleConfirmDeleteDialog(const LLSD& notification, const LLSD& response); static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId); + static void finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId); protected: LLViewerTextEditor* mEditor; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 5b1b356597..f28ffce602 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -375,7 +375,8 @@ LLScriptEdCore::LLScriptEdCore( mLiveFile(NULL), mLive(live), mContainer(container), - mHasScriptData(FALSE) + mHasScriptData(FALSE), + mScriptRemoved(FALSE) { setFollowsAll(); setBorderVisible(FALSE); @@ -666,7 +667,7 @@ bool LLScriptEdCore::hasChanged() void LLScriptEdCore::draw() { BOOL script_changed = hasChanged(); - getChildView("Save_btn")->setEnabled(script_changed); + getChildView("Save_btn")->setEnabled(script_changed && !mScriptRemoved); if( mEditor->hasFocus() ) { @@ -840,7 +841,7 @@ void LLScriptEdCore::addHelpItemToHistory(const std::string& help_string) BOOL LLScriptEdCore::canClose() { - if(mForceClose || !hasChanged()) + if(mForceClose || !hasChanged() || mScriptRemoved) { return TRUE; } @@ -1511,6 +1512,17 @@ BOOL LLPreviewLSL::postBuild() return LLPreview::postBuild(); } +void LLPreviewLSL::draw() +{ + const LLInventoryItem* item = getItem(); + if(!item) + { + setTitle(LLTrans::getString("ScriptWasDeleted")); + mScriptEd->setItemRemoved(TRUE); + } + + LLPreview::draw(); +} // virtual void LLPreviewLSL::callbackLSLCompileSucceeded() { diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index a8c6a6eeeb..6b31125641 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -119,6 +119,8 @@ public: void setScriptName(const std::string& name){mScriptName = name;}; + void setItemRemoved(bool script_removed){mScriptRemoved = script_removed;}; + private: void onBtnHelp(); void onBtnDynamicHelp(); @@ -163,6 +165,7 @@ private: BOOL mHasScriptData; LLLiveLSLFile* mLiveFile; LLUUID mAssociatedExperience; + BOOL mScriptRemoved; LLScriptEdContainer* mContainer; // parent view @@ -198,6 +201,7 @@ public: /*virtual*/ BOOL postBuild(); protected: + virtual void draw(); virtual BOOL canClose(); void closeIfNeeded(); diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index bcb9417820..72d7cf1e45 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -29,7 +29,8 @@ #include "llviewerprecompiledheaders.h" #include "llsecapi.h" #include "llsechandler_basic.h" -#include <boost/throw_exception.hpp> +#include "llexception.h" +#include "stringize.h" #include <openssl/evp.h> #include <openssl/err.h> #include <map> @@ -70,7 +71,7 @@ void initializeSecHandler() } if (!exception_msg.empty()) // an exception was thrown. { - BOOST_THROW_EXCEPTION(LLProtectedDataException(exception_msg)); + LLTHROW(LLProtectedDataException(exception_msg)); } } @@ -102,6 +103,7 @@ std::ostream& operator <<(std::ostream& s, const LLCredential& cred) LLSD LLCredential::getLoginParams() { LLSD result = LLSD::emptyMap(); + std::string username; try { if (mIdentifier["type"].asString() == "agent") @@ -110,17 +112,19 @@ LLSD LLCredential::getLoginParams() result["passwd"] = "$1$" + mAuthenticator["secret"].asString(); result["first"] = mIdentifier["first_name"]; result["last"] = mIdentifier["last_name"]; - + username = result["first"].asString() + " " + result["last"].asString(); } else if (mIdentifier["type"].asString() == "account") { result["username"] = mIdentifier["account_name"]; result["passwd"] = mAuthenticator["secret"]; - + username = result["username"].asString(); } } catch (...) { + // nat 2016-08-18: not clear what exceptions the above COULD throw?! + LOG_UNHANDLED_EXCEPTION(STRINGIZE("for '" << username << "'")); // we could have corrupt data, so simply return a null login param if so LL_WARNS("AppInit") << "Invalid credential" << LL_ENDL; } diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 39ce64ad0e..d6fb801cc0 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -35,7 +35,8 @@ #include "llfile.h" #include "lldir.h" #include "llviewercontrol.h" -#include <boost/throw_exception.hpp> +#include "llexception.h" +#include "stringize.h" #include <vector> #include <ios> #include <openssl/ossl_typ.h> @@ -73,14 +74,14 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert) if(pem_bio == NULL) { LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; - BOOST_THROW_EXCEPTION(LLInvalidCertificate(this)); + LLTHROW(LLInvalidCertificate(this)); } mCert = NULL; PEM_read_bio_X509(pem_bio, &mCert, 0, NULL); BIO_free(pem_bio); if (!mCert) { - BOOST_THROW_EXCEPTION(LLInvalidCertificate(this)); + LLTHROW(LLInvalidCertificate(this)); } } @@ -89,7 +90,7 @@ LLBasicCertificate::LLBasicCertificate(X509* pCert) { if (!pCert || !pCert->cert_info) { - BOOST_THROW_EXCEPTION(LLInvalidCertificate(this)); + LLTHROW(LLInvalidCertificate(this)); } mCert = X509_dup(pCert); } @@ -618,7 +619,7 @@ void LLBasicCertificateStore::load_from_file(const std::string& filename) } catch (...) { - LL_WARNS("SECAPI") << "Failure creating certificate from the certificate store file." << LL_ENDL; + LOG_UNHANDLED_EXCEPTION("creating certificate from the certificate store file"); } X509_free(cert_x509); cert_x509 = NULL; @@ -874,22 +875,22 @@ void _validateCert(int validation_policy, // check basic properties exist in the cert if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING)) { - BOOST_THROW_EXCEPTION(LLCertException(cert, "Cert doesn't have a Subject Name")); + LLTHROW(LLCertException(cert, "Cert doesn't have a Subject Name")); } if(!current_cert_info.has(CERT_ISSUER_NAME_STRING)) { - BOOST_THROW_EXCEPTION(LLCertException(cert, "Cert doesn't have an Issuer Name")); + LLTHROW(LLCertException(cert, "Cert doesn't have an Issuer Name")); } // check basic properties exist in the cert if(!current_cert_info.has(CERT_VALID_FROM) || !current_cert_info.has(CERT_VALID_TO)) { - BOOST_THROW_EXCEPTION(LLCertException(cert, "Cert doesn't have an expiration period")); + LLTHROW(LLCertException(cert, "Cert doesn't have an expiration period")); } if (!current_cert_info.has(CERT_SHA1_DIGEST)) { - BOOST_THROW_EXCEPTION(LLCertException(cert, "No SHA1 digest")); + LLTHROW(LLCertException(cert, "No SHA1 digest")); } if (validation_policy & VALIDATION_POLICY_TIME) @@ -904,7 +905,7 @@ void _validateCert(int validation_policy, if((validation_date < current_cert_info[CERT_VALID_FROM].asDate()) || (validation_date > current_cert_info[CERT_VALID_TO].asDate())) { - BOOST_THROW_EXCEPTION(LLCertValidationExpirationException(cert, validation_date)); + LLTHROW(LLCertValidationExpirationException(cert, validation_date)); } } if (validation_policy & VALIDATION_POLICY_SSL_KU) @@ -915,14 +916,14 @@ void _validateCert(int validation_policy, !(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT))))) { - BOOST_THROW_EXCEPTION(LLCertKeyUsageValidationException(cert)); + LLTHROW(LLCertKeyUsageValidationException(cert)); } // only validate EKU if the cert has it if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() && (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE], LLSD((std::string)CERT_EKU_SERVER_AUTH)))) { - BOOST_THROW_EXCEPTION(LLCertKeyUsageValidationException(cert)); + LLTHROW(LLCertKeyUsageValidationException(cert)); } } if (validation_policy & VALIDATION_POLICY_CA_KU) @@ -931,7 +932,7 @@ void _validateCert(int validation_policy, (!_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], (std::string)CERT_KU_CERT_SIGN))) { - BOOST_THROW_EXCEPTION(LLCertKeyUsageValidationException(cert)); + LLTHROW(LLCertKeyUsageValidationException(cert)); } } @@ -943,13 +944,13 @@ void _validateCert(int validation_policy, if(!current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_CA) || !current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_CA]) { - BOOST_THROW_EXCEPTION(LLCertBasicConstraintsValidationException(cert)); + LLTHROW(LLCertBasicConstraintsValidationException(cert)); } if (current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_PATHLEN) && ((current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger() != 0) && (depth > current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger()))) { - BOOST_THROW_EXCEPTION(LLCertBasicConstraintsValidationException(cert)); + LLTHROW(LLCertBasicConstraintsValidationException(cert)); } } } @@ -1019,7 +1020,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if(cert_chain->size() < 1) { - BOOST_THROW_EXCEPTION(LLCertException(NULL, "No certs in chain")); + LLTHROW(LLCertException(NULL, "No certs in chain")); } iterator current_cert = cert_chain->begin(); LLSD current_cert_info; @@ -1034,11 +1035,11 @@ void LLBasicCertificateStore::validate(int validation_policy, (*current_cert)->getLLSD(current_cert_info); if(!validation_params.has(CERT_HOSTNAME)) { - BOOST_THROW_EXCEPTION(LLCertException((*current_cert), "No hostname passed in for validation")); + LLTHROW(LLCertException((*current_cert), "No hostname passed in for validation")); } if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info[CERT_SUBJECT_NAME].has(CERT_NAME_CN)) { - BOOST_THROW_EXCEPTION(LLInvalidCertificate((*current_cert))); + LLTHROW(LLInvalidCertificate((*current_cert))); } LL_DEBUGS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() << @@ -1055,7 +1056,7 @@ void LLBasicCertificateStore::validate(int validation_policy, X509* cert_x509 = (*current_cert)->getOpenSSLX509(); if(!cert_x509) { - BOOST_THROW_EXCEPTION(LLInvalidCertificate((*current_cert))); + LLTHROW(LLInvalidCertificate((*current_cert))); } std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH); X509_free( cert_x509 ); @@ -1076,7 +1077,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if((validation_date < cache_entry->second.first) || (validation_date > cache_entry->second.second)) { - BOOST_THROW_EXCEPTION(LLCertValidationExpirationException((*current_cert), validation_date)); + LLTHROW(LLCertValidationExpirationException((*current_cert), validation_date)); } } // successfully found in cache @@ -1108,7 +1109,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if(!_verify_signature((*current_cert), previous_cert)) { - BOOST_THROW_EXCEPTION(LLCertValidationInvalidSignatureException(previous_cert)); + LLTHROW(LLCertValidationInvalidSignatureException(previous_cert)); } } _validateCert(local_validation_policy, @@ -1157,7 +1158,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if(!_verify_signature((*found_store_cert), (*current_cert))) { - BOOST_THROW_EXCEPTION(LLCertValidationInvalidSignatureException(*current_cert)); + LLTHROW(LLCertValidationInvalidSignatureException(*current_cert)); } // successfully validated. mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time); @@ -1174,7 +1175,7 @@ void LLBasicCertificateStore::validate(int validation_policy, if (validation_policy & VALIDATION_POLICY_TRUSTED) { // we reached the end without finding a trusted cert. - BOOST_THROW_EXCEPTION(LLCertValidationTrustException((*cert_chain)[cert_chain->size()-1])); + LLTHROW(LLCertValidationTrustException((*cert_chain)[cert_chain->size()-1])); } mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time); @@ -1262,7 +1263,7 @@ void LLSecAPIBasicHandler::_readProtectedData() protected_data_stream.read((char *)salt, STORE_SALT_SIZE); if (protected_data_stream.gcount() < STORE_SALT_SIZE) { - BOOST_THROW_EXCEPTION(LLProtectedDataException("Config file too short.")); + LLTHROW(LLProtectedDataException("Config file too short.")); } cipher.decrypt(salt, STORE_SALT_SIZE); @@ -1302,7 +1303,7 @@ void LLSecAPIBasicHandler::_readProtectedData() if (parser->parse(parse_stream, mProtectedDataMap, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) { - BOOST_THROW_EXCEPTION(LLProtectedDataException("Config file cannot be decrypted.")); + LLTHROW(LLProtectedDataException("Config file cannot be decrypted.")); } } } @@ -1365,7 +1366,7 @@ void LLSecAPIBasicHandler::_writeProtectedData() } catch (...) { - LL_WARNS() << "LLProtectedDataException(Error writing Protected Data Store)" << LL_ENDL; + LOG_UNHANDLED_EXCEPTION("LLProtectedDataException(Error writing Protected Data Store)"); // it's good practice to clean up any secure information on error // (even though this file isn't really secure. Perhaps in the future // it may be, however. @@ -1373,39 +1374,39 @@ void LLSecAPIBasicHandler::_writeProtectedData() // EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData() // Decided throwing an exception here was overkill until we figure out why this happens - //BOOST_THROW_EXCEPTION(LLProtectedDataException("Error writing Protected Data Store")); + //LLTHROW(LLProtectedDataException("Error writing Protected Data Store")); } - try - { - // move the temporary file to the specified file location. - if((( (LLFile::isfile(mProtectedDataFilename) != 0) - && (LLFile::remove(mProtectedDataFilename) != 0))) - || (LLFile::rename(tmp_filename, mProtectedDataFilename))) - { - LL_WARNS() << "LLProtectedDataException(Could not overwrite protected data store)" << LL_ENDL; - LLFile::remove(tmp_filename); + try + { + // move the temporary file to the specified file location. + if((( (LLFile::isfile(mProtectedDataFilename) != 0) + && (LLFile::remove(mProtectedDataFilename) != 0))) + || (LLFile::rename(tmp_filename, mProtectedDataFilename))) + { + LL_WARNS() << "LLProtectedDataException(Could not overwrite protected data store)" << LL_ENDL; + LLFile::remove(tmp_filename); - // EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData() - // Decided throwing an exception here was overkill until we figure out why this happens - //BOOST_THROW_EXCEPTION(LLProtectedDataException("Could not overwrite protected data store")); - } + // EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData() + // Decided throwing an exception here was overkill until we figure out why this happens + //LLTHROW(LLProtectedDataException("Could not overwrite protected data store")); + } } catch (...) { - LL_WARNS() << "LLProtectedDataException(Error renaming '" << tmp_filename - << "' to '" << mProtectedDataFilename << "')" << LL_ENDL; + LOG_UNHANDLED_EXCEPTION(STRINGIZE("renaming '" << tmp_filename << "' to '" + << mProtectedDataFilename << "'")); // it's good practice to clean up any secure information on error // (even though this file isn't really secure. Perhaps in the future - // it may be, however. + // it may be, however). LLFile::remove(tmp_filename); //crash in LLSecAPIBasicHandler::_writeProtectedData() // Decided throwing an exception here was overkill until we figure out why this happens - //BOOST_THROW_EXCEPTION(LLProtectedDataException("Error writing Protected Data Store")); + //LLTHROW(LLProtectedDataException("Error writing Protected Data Store")); } } - + // instantiate a certificate from a pem string LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(const std::string& pem_cert) { diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 86135ee6e8..f07f0ed86c 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -383,7 +383,7 @@ void LLSidepanelAppearance::toggleOutfitEditPanel(BOOL visible, BOOL disable_cam void LLSidepanelAppearance::toggleWearableEditPanel(BOOL visible, LLViewerWearable *wearable, BOOL disable_camera_switch) { - if (!mEditWearable || mEditWearable->getVisible() == visible) + if (!mEditWearable || ((mEditWearable->getWearable() == wearable) && mEditWearable->getVisible() == visible)) { // visibility isn't changing, hence nothing to do return; diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp new file mode 100644 index 0000000000..cf09f6f978 --- /dev/null +++ b/indra/newview/llskinningutil.cpp @@ -0,0 +1,218 @@ +/** +* @file llskinningutil.cpp +* @brief Functions for mesh object skinning +* @author vir@lindenlab.com +* +* $LicenseInfo:firstyear=2015&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2015, 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 "llskinningutil.h" +#include "llvoavatar.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" + +// static +void LLSkinningUtil::initClass() +{ +} + +// static +U32 LLSkinningUtil::getMaxJointCount() +{ + U32 result = LL_MAX_JOINTS_PER_MESH_OBJECT; + return result; +} + +// static +U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin) +{ + return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size()); +} + +// static +void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin) +{ + if (skin->mInvalidJointsScrubbed) + { + return; + } + for (U32 j = 0; j < skin->mJointNames.size(); ++j) + { + // Fix invalid names to "mPelvis". Currently meshes with + // invalid names will be blocked on upload, so this is just + // needed for handling of any legacy bad data. + if (!avatar->getJoint(skin->mJointNames[j])) + { + LL_DEBUGS("Avatar") << "Mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL; + skin->mJointNames[j] = "mPelvis"; + } + } + skin->mInvalidJointsScrubbed = true; +} + +// static +void LLSkinningUtil::initSkinningMatrixPalette( + LLMatrix4* mat, + S32 count, + const LLMeshSkinInfo* skin, + LLVOAvatar *avatar) +{ + for (U32 j = 0; j < count; ++j) + { + LLJoint *joint = NULL; + if (skin->mJointNums[j] == -1) + { + joint = avatar->getJoint(skin->mJointNames[j]); + if (joint) + { + skin->mJointNums[j] = joint->getJointNum(); + } + } + else + { + joint = avatar->getJoint(skin->mJointNums[j]); + } + if (joint) + { +#define MAT_USE_SSE +#ifdef MAT_USE_SSE + LLMatrix4a bind, world, res; + bind.loadu(skin->mInvBindMatrix[j]); + world.loadu(joint->getWorldMatrix()); + matMul(bind,world,res); + memcpy(mat[j].mMatrix,res.mMatrix,16*sizeof(float)); +#else + mat[j] = skin->mInvBindMatrix[j]; + mat[j] *= joint->getWorldMatrix(); +#endif + } + else + { + mat[j] = skin->mInvBindMatrix[j]; + // This shouldn't happen - in mesh upload, skinned + // rendering should be disabled unless all joints are + // valid. In other cases of skinned rendering, invalid + // joints should already have been removed during scrubInvalidJoints(). + LL_WARNS_ONCE("Avatar") << "Rigged to invalid joint name " << skin->mJointNames[j] << LL_ENDL; + } + } +} + +// static +void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD + const S32 max_joints = skin->mJointNames.size(); + for (U32 j=0; j<num_vertices; j++) + { + F32 *w = weights[j].getF32ptr(); + + F32 wsum = 0.0; + for (U32 k=0; k<4; ++k) + { + S32 i = llfloor(w[k]); + llassert(i>=0); + llassert(i<max_joints); + wsum += w[k]-i; + } + llassert(wsum > 0.0f); + } +#endif +} + +void LLSkinningUtil::scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) +{ + const S32 max_joints = skin->mJointNames.size(); + for (U32 j=0; j<num_vertices; j++) + { + F32 *w = weights[j].getF32ptr(); + + for (U32 k=0; k<4; ++k) + { + S32 i = llfloor(w[k]); + F32 f = w[k]-i; + i = llclamp(i,0,max_joints-1); + w[k] = i + f; + } + } + checkSkinWeights(weights, num_vertices, skin); +} + +// static +void LLSkinningUtil::getPerVertexSkinMatrix( + F32* weights, + LLMatrix4a* mat, + bool handle_bad_scale, + LLMatrix4a& final_mat, + U32 max_joints) +{ + bool valid_weights = true; + final_mat.clear(); + + S32 idx[4]; + + LLVector4 wght; + + F32 scale = 0.f; + for (U32 k = 0; k < 4; k++) + { + F32 w = weights[k]; + + // BENTO potential optimizations + // - Do clamping in unpackVolumeFaces() (once instead of every time) + // - int vs floor: if we know w is + // >= 0.0, we can use int instead of floorf; the latter + // allegedly has a lot of overhead due to ieeefp error + // checking which we should not need. + idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)max_joints-1); + + wght[k] = w - floorf(w); + scale += wght[k]; + } + if (handle_bad_scale && scale <= 0.f) + { + wght = LLVector4(1.0f, 0.0f, 0.0f, 0.0f); + valid_weights = false; + } + else + { + // This is enforced in unpackVolumeFaces() + llassert(scale>0.f); + wght *= 1.f/scale; + } + + for (U32 k = 0; k < 4; k++) + { + F32 w = wght[k]; + + LLMatrix4a src; + src.setMul(mat[idx[k]], w); + + final_mat.add(src); + } + // SL-366 - with weight validation/cleanup code, it should no longer be + // possible to hit the bad scale case. + llassert(valid_weights); +} + diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h new file mode 100644 index 0000000000..135b25d4d2 --- /dev/null +++ b/indra/newview/llskinningutil.h @@ -0,0 +1,47 @@ +/** +* @file llskinningutil.h +* @brief Functions for mesh object skinning +* @author vir@lindenlab.com +* +* $LicenseInfo:firstyear=2015&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2015, 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 LLSKINNINGUTIL_H +#define LLSKINNINGUTIL_H + +class LLVOAvatar; +class LLMeshSkinInfo; +class LLMatrix4a; + +class LLSkinningUtil +{ +public: + static void initClass(); + static U32 getMaxJointCount(); + static U32 getMeshJointCount(const LLMeshSkinInfo *skin); + static void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); + static void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar); + static void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); + static void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); + static void getPerVertexSkinMatrix(F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); +}; + +#endif diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index b0eb4137a7..0fd36766b3 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -3213,6 +3213,11 @@ void renderAvatarCollisionVolumes(LLVOAvatar* avatar) avatar->renderCollisionVolumes(); } +void renderAvatarBones(LLVOAvatar* avatar) +{ + avatar->renderBones(); +} + void renderAgentTarget(LLVOAvatar* avatar) { // render these for self only (why, i don't know) @@ -3371,6 +3376,11 @@ public: renderAvatarCollisionVolumes(avatar); } + if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_JOINTS)) + { + renderAvatarBones(avatar); + } + if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET)) { renderAgentTarget(avatar); @@ -3661,6 +3671,7 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_TEXTURE_ANIM | LLPipeline::RENDER_DEBUG_RAYCAST | LLPipeline::RENDER_DEBUG_AVATAR_VOLUME | + LLPipeline::RENDER_DEBUG_AVATAR_JOINTS | LLPipeline::RENDER_DEBUG_AGENT_TARGET | //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA | diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a2c8e7772e..dab25f144b 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -28,6 +28,7 @@ #include "llappviewer.h" #include "llstartup.h" +#include "llcallstack.h" #if LL_WINDOWS # include <process.h> // _spawnl() @@ -194,6 +195,8 @@ #include "lltoolbarview.h" #include "llexperiencelog.h" +#include "llstacktrace.h" + #if LL_WINDOWS #include "lldxhardware.h" #endif @@ -771,7 +774,11 @@ bool idle_startup() LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL; } } - + display_startup(); + if (gViewerWindow->getSystemUIScaleFactorChanged()) + { + LLViewerWindow::showSystemUIScaleFactorChanged(); + } LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input } else @@ -1218,7 +1225,7 @@ bool idle_startup() LLPostProcess::initClass(); display_startup(); - LLAvatarAppearance::initClass(); + LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml"); display_startup(); LLViewerObject::initVOClasses(); diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 2d06b8599c..d28a7cc048 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -230,8 +230,8 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 const F32 xyScaleInv = (1.f / xyScale)*(0.2222222222f); F32 vec[3] = { - fmod((F32)(mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f), - fmod((F32)(mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f), + (F32)fmod((F32)(mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f), + (F32)fmod((F32)(mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f), 0.f }; F32 rand_val = llclamp(noise2(vec)* 0.75f + 0.5f, 0.f, 1.f); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 37cc908e84..36c4f0d516 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1928,6 +1928,12 @@ bool LLTextureCache::writeToFastCache(S32 id, LLPointer<LLImageRaw> raw, S32 dis { //make a duplicate to keep the original raw image untouched. raw = raw->duplicate(); + if (raw->isBufferInvalid()) + { + LL_WARNS() << "Invalid image duplicate buffer" << LL_ENDL; + return false; + } + raw->scale(w, h) ; discardlevel += i ; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index ad4f903dff..24bc55c998 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1327,7 +1327,7 @@ void LLTextureCtrl::setOnTextureSelectedCallback(texture_selected_callback cb) void LLTextureCtrl::setImageAssetName(const std::string& name) { - LLPointer<LLUIImage> imagep = LLUI::getUIImage(name, LLGLTexture::BOOST_PREVIEW); + LLPointer<LLUIImage> imagep = LLUI::getUIImage(name); if(imagep) { LLViewerFetchedTexture* pTexture = dynamic_cast<LLViewerFetchedTexture*>(imagep->getImage().get()); diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index fd950864aa..01d799dcd5 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -283,7 +283,7 @@ bool LLToolBarView::loadToolbars(bool force_default) } BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.left_toolbar.commands) { - if (addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_LEFT])) + if (!addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_LEFT])) { LL_WARNS() << "Error adding command '" << command_params.name() << "' to left toolbar." << LL_ENDL; } @@ -298,7 +298,7 @@ bool LLToolBarView::loadToolbars(bool force_default) } BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.right_toolbar.commands) { - if (addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_RIGHT])) + if (!addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_RIGHT])) { LL_WARNS() << "Error adding command '" << command_params.name() << "' to right toolbar." << LL_ENDL; } @@ -313,7 +313,7 @@ bool LLToolBarView::loadToolbars(bool force_default) } BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.bottom_toolbar.commands) { - if (addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_BOTTOM])) + if (!addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_BOTTOM])) { LL_WARNS() << "Error adding command '" << command_params.name() << "' to bottom toolbar." << LL_ENDL; } diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index c4696c3a01..caa055e5e0 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -223,6 +223,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info) } if (!(pick_info.mKeyMask & MASK_ALT) && + !LLFloaterCamera::inFreeCameraMode() && gAgentCamera.cameraThirdPerson() && gViewerWindow->getLeftMouseDown() && !gSavedSettings.getBOOL("FreezeTime") && diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index b0e3b5bf89..f6eb290bc3 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -267,7 +267,7 @@ bool LLToolMgr::canEdit() bool LLToolMgr::buildEnabledOrActive() { - return inEdit() || canEdit(); + return LLFloaterReg::instanceVisible("build") || canEdit(); } void LLToolMgr::toggleBuildMode(const LLSD& sdname) diff --git a/indra/newview/llviewchildren.cpp b/indra/newview/llviewchildren.cpp index 5c5bbdc8f5..32b2f7e9f5 100644 --- a/indra/newview/llviewchildren.cpp +++ b/indra/newview/llviewchildren.cpp @@ -79,8 +79,9 @@ void LLViewChildren::setBadge(const std::string& id, Badge badge, bool visible) default: case BADGE_OK: child->setValue(std::string("badge_ok.j2c")); break; case BADGE_NOTE: child->setValue(std::string("badge_note.j2c")); break; - case BADGE_WARN: child->setValue(std::string("badge_warn.j2c")); break; - case BADGE_ERROR: child->setValue(std::string("badge_error.j2c")); break; + case BADGE_WARN: + case BADGE_ERROR: + child->setValue(std::string("badge_warn.j2c")); break; } } } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 16f40fb747..db71849659 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -67,6 +67,7 @@ #include "llvowlsky.h" #include "llrender.h" #include "llnavigationbar.h" +#include "llnotificationsutil.h" #include "llfloatertools.h" #include "llpaneloutfitsinventory.h" #include "llpanellogin.h" @@ -119,6 +120,13 @@ static bool handleTerrainDetailChanged(const LLSD& newvalue) } +static bool handleDebugAvatarJointsChanged(const LLSD& newvalue) +{ + std::string new_string = newvalue.asString(); + LLJoint::setDebugJointNames(new_string); + return true; +} + static bool handleSetShaderChanged(const LLSD& newvalue) { // changing shader level may invalidate existing cached bump maps, as the shader type determines the format of the bump map it expects - clear and repopulate the bump cache @@ -741,6 +749,7 @@ void settings_setup_listeners() gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); gSavedSettings.getControl("SpellCheckDictionary")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); gSavedSettings.getControl("LoginLocation")->getSignal()->connect(boost::bind(&handleLoginLocationChanged)); + gSavedSettings.getControl("DebugAvatarJoints")->getCommitSignal()->connect(boost::bind(&handleDebugAvatarJointsChanged, _2)); } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index d0813544f8..0bbe9fa2c2 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1007,6 +1007,22 @@ void activate_gesture_cb(const LLUUID& inv_item) LLGestureMgr::instance().activateGesture(inv_item); } +void set_default_permissions(LLViewerInventoryItem* item, std::string perm_type) +{ + llassert(item); + LLPermissions perm = item->getPermissions(); + if (perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms(perm_type) + || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms(perm_type)) + { + perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms(perm_type)); + perm.setMaskGroup(LLFloaterPerms::getGroupPerms(perm_type)); + + item->setPermissions(perm); + + item->updateServer(FALSE); + } +} + void create_script_cb(const LLUUID& inv_item) { if (!inv_item.isNull()) @@ -1014,13 +1030,9 @@ void create_script_cb(const LLUUID& inv_item) LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (item) { - LLPermissions perm = item->getPermissions(); - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Scripts")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Scripts")); - - item->setPermissions(perm); + set_default_permissions(item, "Scripts"); - item->updateServer(FALSE); + // item was just created, update even if permissions did not changed gInventory.updateItem(item); gInventory.notifyObservers(); } @@ -1036,13 +1048,8 @@ void create_gesture_cb(const LLUUID& inv_item) LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (item) { - LLPermissions perm = item->getPermissions(); - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Gestures")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Gestures")); + set_default_permissions(item, "Gestures"); - item->setPermissions(perm); - - item->updateServer(FALSE); gInventory.updateItem(item); gInventory.notifyObservers(); @@ -1061,13 +1068,8 @@ void create_notecard_cb(const LLUUID& inv_item) LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (item) { - LLPermissions perm = item->getPermissions(); - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Notecards")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Notecards")); - - item->setPermissions(perm); + set_default_permissions(item, "Notecards"); - item->updateServer(FALSE); gInventory.updateItem(item); gInventory.notifyObservers(); } diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp index e46299f9d2..b7bd131246 100644 --- a/indra/newview/llviewerjoint.cpp +++ b/indra/newview/llviewerjoint.cpp @@ -48,14 +48,13 @@ LLViewerJoint::LLViewerJoint() : LLAvatarJoint() { } -LLViewerJoint::LLViewerJoint(const std::string &name, LLJoint *parent) : - LLAvatarJoint(name, parent) -{ } - LLViewerJoint::LLViewerJoint(S32 joint_num) : LLAvatarJoint(joint_num) { } +LLViewerJoint::LLViewerJoint(const std::string &name, LLJoint *parent) : + LLAvatarJoint(name, parent) +{ } //----------------------------------------------------------------------------- // ~LLViewerJoint() diff --git a/indra/newview/llviewerjoint.h b/indra/newview/llviewerjoint.h index fd262b6e80..abe11bbf5c 100644 --- a/indra/newview/llviewerjoint.h +++ b/indra/newview/llviewerjoint.h @@ -44,7 +44,8 @@ class LLViewerJoint : { public: LLViewerJoint(); - LLViewerJoint(S32 joint_num); + LLViewerJoint(S32 joint_num); + // *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform* LLViewerJoint(const std::string &name, LLJoint *parent = NULL); virtual ~LLViewerJoint(); diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 888decd3be..66e392ac42 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -352,6 +352,7 @@ void LLViewerJointAttachment::setAttachmentVisibility(BOOL visible) void LLViewerJointAttachment::setOriginalPosition(LLVector3& position) { mOriginalPos = position; + // SL-315 setPosition(position); } diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index bf7cf08c63..43a81ada49 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -203,7 +203,7 @@ void LLViewerJointMesh::uploadJointMatrices() // DrawElementsBLEND and utility code //-------------------------------------------------------------------- -// compate_int is used by the qsort function to sort the index array +// compare_int is used by the qsort function to sort the index array int compare_int(const void *a, const void *b) { if (*(U32*)a < *(U32*)b) diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6ed063e066..78c4d98d55 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1490,7 +1490,7 @@ void LLViewerMedia::createSpareBrowserMediaSource() // The null owner will keep the browser plugin from fully initializing // (specifically, it keeps LLPluginClassMedia from negotiating a size change, // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) - sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0); + sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0, 1.0); } } @@ -1762,7 +1762,7 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type) ////////////////////////////////////////////////////////////////////////////////////////// /*static*/ -LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target, bool clean_browser) +LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target, bool clean_browser) { std::string plugin_basename = LLMIMETypes::implType(media_type); LLPluginClassMedia* media_source = NULL; @@ -1779,6 +1779,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ media_source->setOwner(owner); media_source->setTarget(target); media_source->setSize(default_width, default_height); + media_source->setZoomFactor(zoom_factor); return media_source; } @@ -1827,6 +1828,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ media_source->setSize(default_width, default_height); media_source->setUserDataPath(user_data_path_cache, user_data_path_cookies); media_source->setLanguageCode(LLUI::getLanguage()); + media_source->setZoomFactor(zoom_factor); // collect 'cookies enabled' setting from prefs and send to embedded browser bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" ); @@ -1883,6 +1885,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) // Save the previous media source's last set size before destroying it. mMediaWidth = mMediaSource->getSetWidth(); mMediaHeight = mMediaSource->getSetHeight(); + mZoomFactor = mMediaSource->getZoomFactor(); } // Always delete the old media impl first. @@ -1905,7 +1908,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) // Save the MIME type that really caused the plugin to load mCurrentMimeType = mMimeType; - LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget, mCleanBrowser); + LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mZoomFactor, mTarget, mCleanBrowser); if (media_source) { diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 48f0d9dc4d..1fecf15fc9 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -299,7 +299,7 @@ public: void setTarget(const std::string& target) { mTarget = target; } // utility function to create a ready-to-use media instance from a desired media type. - static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target = LLStringUtil::null, bool clean_browser = false); + static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target = LLStringUtil::null, bool clean_browser = false); // Internally set our desired browser user agent string, including // the Second Life version and skin name. Used because we can diff --git a/indra/newview/llviewermedia_streamingaudio.cpp b/indra/newview/llviewermedia_streamingaudio.cpp index c107e8472c..3ccf3070ab 100644 --- a/indra/newview/llviewermedia_streamingaudio.cpp +++ b/indra/newview/llviewermedia_streamingaudio.cpp @@ -154,7 +154,8 @@ LLPluginClassMedia* LLStreamingAudio_MediaPlugins::initializeMedia(const std::st { LLPluginClassMediaOwner* owner = NULL; S32 default_size = 1; // audio-only - be minimal, doesn't matter - LLPluginClassMedia* media_source = LLViewerMediaImpl::newSourceFromMediaType(media_type, owner, default_size, default_size); + F64 default_zoom = 1.0; + LLPluginClassMedia* media_source = LLViewerMediaImpl::newSourceFromMediaType(media_type, owner, default_size, default_size, default_zoom); if (media_source) { diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index f5b06fbd19..72579d4d7a 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -187,10 +187,10 @@ LLMenuGL* gDetachSubMenu = NULL; LLMenuGL* gTakeOffClothes = NULL; LLContextMenu* gAttachScreenPieMenu = NULL; LLContextMenu* gAttachPieMenu = NULL; -LLContextMenu* gAttachBodyPartPieMenus[8]; +LLContextMenu* gAttachBodyPartPieMenus[9]; LLContextMenu* gDetachPieMenu = NULL; LLContextMenu* gDetachScreenPieMenu = NULL; -LLContextMenu* gDetachBodyPartPieMenus[8]; +LLContextMenu* gDetachBodyPartPieMenus[9]; // // Local prototypes @@ -397,13 +397,15 @@ void set_merchant_SLM_menu() gToolBarView->enableCommand(command->id(), true); } -void check_merchant_status() +void check_merchant_status(bool force) { if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth")) { - // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() - LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); - + if (force) + { + // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() + LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); + } // Hide SLM related menu item gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(FALSE); @@ -5998,6 +6000,31 @@ class LLAvatarToggleMyProfile : public view_listener_t } }; +class LLAvatarResetSkeleton: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + avatar->resetSkeleton(false); + } + return true; + } +}; + +class LLAvatarResetSkeletonAndAnimations : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(true); + } + return true; + } +}; class LLAvatarAddContact : public view_listener_t { @@ -7906,7 +7933,7 @@ void handle_web_browser_test(const LLSD& param) void handle_web_content_test(const LLSD& param) { std::string url = param.asString(); - LLWeb::loadURLInternal(url); + LLWeb::loadURLInternal(url, LLStringUtil::null, LLStringUtil::null, true); } void handle_show_url(const LLSD& param) @@ -8989,6 +9016,8 @@ void initialize_menus() enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); + view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); + view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index b7bdf00157..7abb0c8e74 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -83,7 +83,7 @@ BOOL enable_god_full(void* user_data); BOOL enable_god_liaison(void* user_data); BOOL enable_god_basic(void* user_data); void set_underclothes_menu_options(); -void check_merchant_status(); +void check_merchant_status(bool force = false); void exchange_callingcard(const LLUUID& dest_id); @@ -108,6 +108,7 @@ void handle_look_at_selection(const LLSD& param); void handle_zoom_to_object(LLUUID object_id); void handle_object_return(); void handle_object_delete(); +void handle_object_edit(); void handle_buy_land(); @@ -188,8 +189,8 @@ extern LLContextMenu* gAttachScreenPieMenu; extern LLContextMenu* gDetachScreenPieMenu; extern LLContextMenu* gAttachPieMenu; extern LLContextMenu* gDetachPieMenu; -extern LLContextMenu* gAttachBodyPartPieMenus[8]; -extern LLContextMenu* gDetachBodyPartPieMenus[8]; +extern LLContextMenu* gAttachBodyPartPieMenus[9]; +extern LLContextMenu* gDetachBodyPartPieMenus[9]; extern LLMenuItemCallGL* gMutePieMenu; extern LLMenuItemCallGL* gMuteObjectPieMenu; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 54b12cae12..b48b45502b 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -508,8 +508,8 @@ class LLFileEnableCloseAllWindows : public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::getInstance(); - LLFloaterOutfitSnapshot* floater_outfit_snapshot = LLFloaterOutfitSnapshot::getInstance(); + LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); + LLFloaterOutfitSnapshot* floater_outfit_snapshot = LLFloaterOutfitSnapshot::findInstance(); bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain()) || (floater_outfit_snapshot && floater_outfit_snapshot->isInVisibleChain()); bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened; @@ -523,10 +523,10 @@ class LLFileCloseAllWindows : public view_listener_t { bool app_quitting = false; gFloaterView->closeAllChildren(app_quitting); - LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::getInstance(); + LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance(); if (floater_snapshot) floater_snapshot->closeFloater(app_quitting); - LLFloaterOutfitSnapshot* floater_outfit_snapshot = LLFloaterOutfitSnapshot::getInstance(); + LLFloaterOutfitSnapshot* floater_outfit_snapshot = LLFloaterOutfitSnapshot::findInstance(); if (floater_outfit_snapshot) floater_outfit_snapshot->closeFloater(app_quitting); if (gMenuHolder) gMenuHolder->hideMenus(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 92df3866f7..f472db080f 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1639,7 +1639,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); discard_agent_offer->startFetch(); - if (catp || (itemp && itemp->isFinished())) + if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished())) { discard_agent_offer->done(); } @@ -4719,7 +4719,9 @@ void process_sound_trigger(LLMessageSystem *msg, void **) { if (!gAudiop) { +#if !LL_LINUX LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; +#endif return; } @@ -4781,7 +4783,9 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data) { if (!gAudiop) { +#if !LL_LINUX LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; +#endif return; } @@ -6601,6 +6605,11 @@ void process_script_question(LLMessageSystem *msg, void **user_data) if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit) continue; + if (script_perm.question == "JoinAnExperience") + { // Some experience only permissions do not have an explicit permission bit. Add them here. + script_question += " " + LLTrans::getString("ForceSitAvatar") + "\n"; + } + script_question += " " + LLTrans::getString(script_perm.question) + "\n"; } } diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index 6666aecca2..2525886222 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -49,6 +49,8 @@ const std::string GRID_UPDATE_SERVICE_URL = "update_query_url_base"; const std::string GRID_HELPER_URI_VALUE = "helper_uri"; /// the splash page url const std::string GRID_LOGIN_PAGE_VALUE = "login_page"; +/// url for the web profile site +const std::string GRID_WEB_PROFILE_VALUE = "web_profile_url"; /// internal data on system grids const std::string GRID_IS_SYSTEM_GRID_VALUE = "system_grid"; /// whether this is single or double names @@ -70,6 +72,8 @@ const std::string SL_UPDATE_QUERY_URL = "https://update.secondlife.com/update"; const std::string MAIN_GRID_SLURL_BASE = "http://maps.secondlife.com/secondlife/"; const std::string SYSTEM_GRID_APP_SLURL_BASE = "secondlife:///app"; +const std::string MAIN_GRID_WEB_PROFILE_URL = "https://my.secondlife.com/"; + const char* SYSTEM_GRID_SLURL_BASE = "secondlife://%s/secondlife/"; const char* DEFAULT_SLURL_BASE = "https://%s/region/"; const char* DEFAULT_APP_SLURL_BASE = "x-grid-location-info://%s/app"; @@ -125,6 +129,7 @@ void LLGridManager::initialize(const std::string& grid_file) "https://secondlife.com/helpers/", DEFAULT_LOGIN_PAGE, SL_UPDATE_QUERY_URL, + MAIN_GRID_WEB_PROFILE_URL, "Agni"); addSystemGrid(LLTrans::getString("AditiGridLabel"), "util.aditi.lindenlab.com", @@ -132,6 +137,7 @@ void LLGridManager::initialize(const std::string& grid_file) "http://aditi-secondlife.webdev.lindenlab.com/helpers/", DEFAULT_LOGIN_PAGE, SL_UPDATE_QUERY_URL, + "https://my.aditi.lindenlab.com/", "Aditi"); LLSD other_grids; @@ -288,6 +294,10 @@ bool LLGridManager::addGrid(LLSD& grid_data) { grid_data[GRID_HELPER_URI_VALUE] = std::string("https://") + grid + "/helpers/"; } + if (!grid_data.has(GRID_WEB_PROFILE_VALUE)) + { + grid_data[GRID_WEB_PROFILE_VALUE] = std::string("https://") + grid + "/"; + } if (!grid_data.has(GRID_LOGIN_IDENTIFIER_TYPES)) { @@ -302,7 +312,8 @@ bool LLGridManager::addGrid(LLSD& grid_data) <<" id: "<<grid_data[GRID_ID_VALUE].asString()<<"\n" <<" label: "<<grid_data[GRID_LABEL_VALUE].asString()<<"\n" <<" login page: "<<grid_data[GRID_LOGIN_PAGE_VALUE].asString()<<"\n" - <<" helper page: "<<grid_data[GRID_HELPER_URI_VALUE].asString()<<"\n"; + <<" helper page: "<<grid_data[GRID_HELPER_URI_VALUE].asString()<<"\n" + <<" web profile: "<<grid_data[GRID_WEB_PROFILE_VALUE].asString()<<"\n"; /* still in LL_DEBUGS */ for (LLSD::array_const_iterator login_uris = grid_data[GRID_LOGIN_URI_VALUE].beginArray(); login_uris != grid_data[GRID_LOGIN_URI_VALUE].endArray(); @@ -339,6 +350,7 @@ void LLGridManager::addSystemGrid(const std::string& label, const std::string& helper, const std::string& login_page, const std::string& update_url_base, + const std::string& web_profile_url, const std::string& login_id) { LLSD grid = LLSD::emptyMap(); @@ -349,6 +361,7 @@ void LLGridManager::addSystemGrid(const std::string& label, grid[GRID_LOGIN_URI_VALUE].append(login_uri); grid[GRID_LOGIN_PAGE_VALUE] = login_page; grid[GRID_UPDATE_SERVICE_URL] = update_url_base; + grid[GRID_WEB_PROFILE_VALUE] = web_profile_url; grid[GRID_IS_SYSTEM_GRID_VALUE] = true; grid[GRID_LOGIN_IDENTIFIER_TYPES] = LLSD::emptyArray(); grid[GRID_LOGIN_IDENTIFIER_TYPES].append(CRED_IDENTIFIER_TYPE_AGENT); @@ -535,6 +548,21 @@ std::string LLGridManager::getLoginPage() return login_page; } +std::string LLGridManager::getWebProfileURL(const std::string& grid) +{ + std::string web_profile_url; + std::string grid_name = getGrid(grid); + if (!grid_name.empty()) + { + web_profile_url = mGridList[grid_name][GRID_WEB_PROFILE_VALUE].asString(); + } + else + { + LL_WARNS("GridManager")<<"invalid grid '"<<grid<<"'"<<LL_ENDL; + } + return web_profile_url; +} + void LLGridManager::getLoginIdentifierTypes(LLSD& idTypes) { idTypes = mGridList[mGrid][GRID_LOGIN_IDENTIFIER_TYPES]; diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h index 8526c0ba7f..228303d8e2 100644 --- a/indra/newview/llviewernetwork.h +++ b/indra/newview/llviewernetwork.h @@ -166,6 +166,13 @@ class LLGridManager : public LLSingleton<LLGridManager> /// Return the application URL prefix for the selected grid std::string getAppSLURLBase() { return getAppSLURLBase(mGrid); } + /// Return the url of the resident profile web site for the given grid + std::string getWebProfileURL(const std::string& grid); + + /// Return the url of the resident profile web site for the selected grid + std::string getWebProfileURL() { return getWebProfileURL(mGrid); } + + //@} /* ================================================================ @@ -216,6 +223,7 @@ class LLGridManager : public LLSingleton<LLGridManager> const std::string& helper, const std::string& login_page, const std::string& update_url_base, + const std::string& web_profile_url, const std::string& login_id = ""); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 5edc3c9745..4da26404e5 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -244,9 +244,10 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mPixelArea(1024.f), mInventory(NULL), mInventorySerialNum(0), - mRegionp( regionp ), - mInventoryPending(FALSE), + mInvRequestState(INVENTORY_REQUEST_STOPPED), + mInvRequestXFerId(0), mInventoryDirty(FALSE), + mRegionp(regionp), mDead(FALSE), mOrphaned(FALSE), mUserSelected(FALSE), @@ -370,7 +371,7 @@ void LLViewerObject::markDead() if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id)) { // This case is needed for indirectly attached mesh objects. - av->resetJointPositionsOnDetach(mesh_id); + av->resetJointsOnDetach(mesh_id); } // Mark itself as dead @@ -1434,10 +1435,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, setChanged(MOVED | SILHOUETTE); } - else if (mText.notNull()) + else { - mText->markDead(); - mText = NULL; + if (mText.notNull()) + { + mText->markDead(); + mText = NULL; + } + mHudText.clear(); } std::string media_url; @@ -1812,10 +1817,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, setChanged(TEXTURE); } - else if(mText.notNull()) + else { - mText->markDead(); - mText = NULL; + if (mText.notNull()) + { + mText->markDead(); + mText = NULL; + } + mHudText.clear(); } std::string media_url; @@ -2832,6 +2841,11 @@ void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener) } } +BOOL LLViewerObject::isInventoryPending() +{ + return mInvRequestState != INVENTORY_REQUEST_STOPPED; +} + void LLViewerObject::clearInventoryListeners() { for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer()); @@ -2870,7 +2884,7 @@ void LLViewerObject::requestInventory() void LLViewerObject::fetchInventoryFromServer() { - if (!mInventoryPending) + if (!isInventoryPending()) { delete mInventory; LLMessageSystem* msg = gMessageSystem; @@ -2883,7 +2897,7 @@ void LLViewerObject::fetchInventoryFromServer() msg->sendReliable(mRegionp->getHost()); // this will get reset by dirtyInventory or doInventoryCallback - mInventoryPending = TRUE; + mInvRequestState = INVENTORY_REQUEST_PENDING; } } @@ -2944,7 +2958,7 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) std::string unclean_filename; msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); - + if(ft->mFilename.empty()) { LL_DEBUGS() << "Task has no inventory" << LL_ENDL; @@ -2966,13 +2980,27 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) delete ft; return; } - gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), + U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), ft->mFilename, LL_PATH_CACHE, object->mRegionp->getHost(), TRUE, &LLViewerObject::processTaskInvFile, (void**)ft, LLXferManager::HIGH_PRIORITY); + if (object->mInvRequestState == INVENTORY_XFER) + { + if (new_id > 0 && new_id != object->mInvRequestXFerId) + { + // we started new download. + gXferManager->abortRequestById(object->mInvRequestXFerId, -1); + object->mInvRequestXFerId = new_id; + } + } + else + { + object->mInvRequestState = INVENTORY_XFER; + object->mInvRequestXFerId = new_id; + } } void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) @@ -3099,7 +3127,10 @@ void LLViewerObject::doInventoryCallback() mInventoryCallbacks.erase(curiter); } } - mInventoryPending = FALSE; + + // release inventory loading state + mInvRequestXFerId = 0; + mInvRequestState = INVENTORY_REQUEST_STOPPED; } void LLViewerObject::removeInventory(const LLUUID& item_id) @@ -4990,8 +5021,26 @@ void LLViewerObject::initHudText() void LLViewerObject::restoreHudText() { - if(mText) + if (mHudText.empty()) { + if (mText) + { + mText->markDead(); + mText = NULL; + } + } + else + { + if (!mText) + { + initHudText(); + } + else + { + // Restore default values + mText->setZCompare(TRUE); + mText->setDoFade(TRUE); + } mText->setColor(mHudTextColor); mText->setString(mHudText); } @@ -6271,7 +6320,7 @@ const LLUUID &LLViewerObject::extractAttachmentItemID() return getAttachmentItemID(); } -const std::string& LLViewerObject::getAttachmentItemName() +const std::string& LLViewerObject::getAttachmentItemName() const { static std::string empty; LLInventoryItem *item = gInventory.getItem(getAttachmentItemID()); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index cb8acfdcf8..1e8f3f4ec2 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -172,7 +172,7 @@ public: void setOnActiveList(BOOL on_active) { mOnActiveList = on_active; } virtual BOOL isAttachment() const { return FALSE; } - const std::string& getAttachmentItemName(); + const std::string& getAttachmentItemName() const; virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment virtual BOOL isHUDAttachment() const { return FALSE; } @@ -437,7 +437,7 @@ public: // viewer object has the inventory stored locally. void registerInventoryListener(LLVOInventoryListener* listener, void* user_data); void removeInventoryListener(LLVOInventoryListener* listener); - BOOL isInventoryPending() { return mInventoryPending; } + BOOL isInventoryPending(); void clearInventoryListeners(); bool hasInventoryListeners(); void requestInventory(); @@ -720,6 +720,7 @@ private: void deleteTEImages(); // correctly deletes list of images protected: + typedef std::map<char *, LLNameValue *> name_value_map_t; name_value_map_t mNameValuePairs; // Any name-value pairs stored by script @@ -756,9 +757,17 @@ protected: callback_list_t mInventoryCallbacks; S16 mInventorySerialNum; + enum EInventoryRequestState + { + INVENTORY_REQUEST_STOPPED, + INVENTORY_REQUEST_PENDING, + INVENTORY_XFER + }; + EInventoryRequestState mInvRequestState; + U64 mInvRequestXFerId; + BOOL mInventoryDirty; + LLViewerRegion *mRegionp; // Region that this object belongs to. - BOOL mInventoryPending; - BOOL mInventoryDirty; BOOL mDead; BOOL mOrphaned; // This is an orphaned child BOOL mUserSelected; // Cached user select information diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index dafe2cafec..3e0cec0f09 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -27,6 +27,8 @@ #include "llviewerprecompiledheaders.h" +#include <boost/lexical_cast.hpp> + #include "llfeaturemanager.h" #include "llviewershadermgr.h" @@ -41,6 +43,8 @@ #include "llsky.h" #include "llvosky.h" #include "llrender.h" +#include "lljoint.h" +#include "llskinningutil.h" #ifdef LL_RELEASE_FOR_DOWNLOAD #define UNIFORM_ERRS LL_WARNS_ONCE("Shader") @@ -871,7 +875,9 @@ BOOL LLViewerShaderMgr::loadBasicShaders() shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl", 1 ) ); boost::unordered_map<std::string, std::string> attribs; - + attribs["MAX_JOINTS_PER_MESH_OBJECT"] = + boost::lexical_cast<std::string>(LLSkinningUtil::getMaxJointCount()); + // We no longer have to bind the shaders to global glhandles, they are automatically added to a map now. for (U32 i = 0; i < shaders.size(); i++) { diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ed719ae418..178aa1e646 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1200,7 +1200,7 @@ void LLViewerFetchedTexture::loadFromFastCache() { S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS; S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; - if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) { // scale oversized icon, no need to give more work to gl mRawImage->scale(expected_width, expected_height); @@ -1981,7 +1981,7 @@ bool LLViewerFetchedTexture::updateFetch() { S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS; S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; - if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) { // scale oversized icon, no need to give more work to gl mRawImage->scale(expected_width, expected_height); diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index 0f73515b5d..ae9ce37a28 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -70,7 +70,7 @@ private: }; // Private local functions -static std::string asset_id_to_filename(const LLUUID &asset_id); +static std::string asset_id_to_filename(const LLUUID &asset_id, const ELLPath dir_spec); LLViewerWearable::LLViewerWearable(const LLTransactionID& transaction_id) : LLWearable(), @@ -451,7 +451,7 @@ void LLViewerWearable::copyDataFrom(const LLViewerWearable* src) // Probably reduntant, but ensure that the newly created wearable is not dirty by setting current value of params in new wearable // to be the same as the saved values (which were loaded from src at param->cloneParam(this)) - revertValues(); + revertValuesWithoutUpdate(); } void LLViewerWearable::setItemID(const LLUUID& item_id) @@ -471,6 +471,11 @@ void LLViewerWearable::revertValues() } } +void LLViewerWearable::revertValuesWithoutUpdate() +{ + LLWearable::revertValues(); +} + void LLViewerWearable::saveValues() { LLWearable::saveValues(); @@ -508,7 +513,7 @@ void LLViewerWearable::saveNewAsset() const // LL_INFOS() << "LLViewerWearable::saveNewAsset() type: " << getTypeName() << LL_ENDL; //LL_INFOS() << *this << LL_ENDL; - const std::string filename = asset_id_to_filename(mAssetID); + const std::string filename = asset_id_to_filename(mAssetID, LL_PATH_CACHE); if(! exportFile(filename)) { std::string buffer = llformat("Unable to save '%s' to wearable file.", mName.c_str()); @@ -520,6 +525,12 @@ void LLViewerWearable::saveNewAsset() const return; } + if (gSavedSettings.getBOOL("LogWearableAssetSave")) + { + const std::string log_filename = asset_id_to_filename(mAssetID, LL_PATH_LOGS); + exportFile(log_filename); + } + // save it out to database if( gAssetStorage ) { @@ -568,7 +579,7 @@ void LLViewerWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* } // Delete temp file - const std::string src_filename = asset_id_to_filename(new_asset_id); + const std::string src_filename = asset_id_to_filename(new_asset_id, LL_PATH_CACHE); LLFile::remove(src_filename); // delete the context data @@ -605,10 +616,10 @@ std::ostream& operator<<(std::ostream &s, const LLViewerWearable &w) return s; } -std::string asset_id_to_filename(const LLUUID &asset_id) +std::string asset_id_to_filename(const LLUUID &asset_id, const ELLPath dir_spec) { std::string asset_id_string; asset_id.toString(asset_id_string); - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id_string) + ".wbl"; + std::string filename = gDirUtilp->getExpandedFilename(dir_spec,asset_id_string) + ".wbl"; return filename; } diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h index 62cd5e21ad..cc99f6af2f 100644 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -85,6 +85,8 @@ public: /*virtual*/ void revertValues(); /*virtual*/ void saveValues(); + void revertValuesWithoutUpdate(); + // Something happened that requires the wearable's label to be updated (e.g. worn/unworn). /*virtual*/void setUpdated() const; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index cd9ab3e672..9e68bb78e0 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -251,6 +251,11 @@ BOOL gDisplayBadge = FALSE; static const U8 NO_FACE = 255; BOOL gQuietSnapshot = FALSE; +// Minimum value for UIScaleFactor, also defined in preferences, ui_scale_slider +static const F32 MIN_UI_SCALE = 0.75f; +// 4.0 in preferences, but win10 supports larger scaling and value is used more as +// sanity check, so leaving space for larger values from DPI updates. +static const F32 MAX_UI_SCALE = 7.0f; static const F32 MIN_DISPLAY_SCALE = 0.75f; std::string LLViewerWindow::sSnapshotBaseName; @@ -1593,6 +1598,20 @@ BOOL LLViewerWindow::handleDeviceChange(LLWindow *window) return FALSE; } +void LLViewerWindow::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height) +{ + if (ui_scale_factor >= MIN_UI_SCALE && ui_scale_factor <= MAX_UI_SCALE) + { + gSavedSettings.setF32("UIScaleFactor", ui_scale_factor); + LLViewerWindow::reshape(window_width, window_height); + mResDirty = true; + } + else + { + LL_WARNS() << "DPI change caused UI scale to go out of bounds: " << ui_scale_factor << LL_ENDL; + } +} + void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg) { LLAppViewer::instance()->pingMainloopTimeout(msg); @@ -1655,7 +1674,8 @@ LLViewerWindow::LLViewerWindow(const Params& p) mResDirty(false), mStatesDirty(false), mCurrResolutionIndex(0), - mProgressView(NULL) + mProgressView(NULL), + mSystemUIScaleFactorChanged(false) { // gKeyboard is still NULL, so it doesn't do LLWindowListener any good to // pass its value right now. Instead, pass it a nullary function that @@ -1743,9 +1763,24 @@ LLViewerWindow::LLViewerWindow(const Params& p) gSavedSettings.setS32("FullScreenHeight",scr.mY); } + + F32 system_scale_factor = mWindow->getSystemUISize(); + if (system_scale_factor < MIN_UI_SCALE || system_scale_factor > MAX_UI_SCALE) + { + // reset to default; + system_scale_factor = 1.f; + } + if (p.first_run || gSavedSettings.getF32("LastSystemUIScaleFactor") != system_scale_factor) + { + mSystemUIScaleFactorChanged = !p.first_run; + gSavedSettings.setF32("LastSystemUIScaleFactor", system_scale_factor); + gSavedSettings.setF32("UIScaleFactor", system_scale_factor); + } + + // Get the real window rect the window was created with (since there are various OS-dependent reasons why // the size of a window or fullscreen context may have been adjusted slightly...) - F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); + F32 ui_scale_factor = llclamp(gSavedSettings.getF32("UIScaleFactor"), MIN_UI_SCALE, MAX_UI_SCALE); mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); mDisplayScale *= ui_scale_factor; @@ -1838,6 +1873,28 @@ LLViewerWindow::LLViewerWindow(const Params& p) mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale); } +//static +void LLViewerWindow::showSystemUIScaleFactorChanged() +{ + LLNotificationsUtil::add("SystemUIScaleFactorChanged", LLSD(), LLSD(), onSystemUIScaleFactorChanged); +} + +//static +bool LLViewerWindow::onSystemUIScaleFactorChanged(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if(option == 0) + { + LLFloaterReg::toggleInstanceOrBringToFront("preferences"); + LLFloater* pref_floater = LLFloaterReg::getInstance("preferences"); + LLTabContainer* tab_container = pref_floater->getChild<LLTabContainer>("pref core"); + tab_container->selectTabByName("advanced1"); + + } + return false; +} + + void LLViewerWindow::initGLDefaults() { gGL.setSceneBlendType(LLRender::BT_ALPHA); @@ -5211,7 +5268,7 @@ F32 LLViewerWindow::getWorldViewAspectRatio() const void LLViewerWindow::calcDisplayScale() { - F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); + F32 ui_scale_factor = llclamp(gSavedSettings.getF32("UIScaleFactor"), MIN_UI_SCALE, MAX_UI_SCALE); LLVector2 display_scale; display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); display_scale *= ui_scale_factor; @@ -5224,7 +5281,7 @@ void LLViewerWindow::calcDisplayScale() if (display_scale != mDisplayScale) { - LL_INFOS() << "Setting display scale to " << display_scale << LL_ENDL; + LL_INFOS() << "Setting display scale to " << display_scale << " for ui scale: " << ui_scale_factor << LL_ENDL; mDisplayScale = display_scale; // Init default fonts diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index cdf5b686a7..72b7370621 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -156,7 +156,8 @@ public: min_width, min_height; Optional<bool> fullscreen, - ignore_pixel_depth; + ignore_pixel_depth, + first_run; Params(); }; @@ -210,6 +211,7 @@ public: /*virtual*/ void handleDataCopy(LLWindow *window, S32 data_type, void *data); /*virtual*/ BOOL handleTimerEvent(LLWindow *window); /*virtual*/ BOOL handleDeviceChange(LLWindow *window); + /*virtual*/ void handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); /*virtual*/ void handlePingWatchdog(LLWindow *window, const char * msg); /*virtual*/ void handlePauseWatchdog(LLWindow *window); @@ -415,6 +417,9 @@ public: void calcDisplayScale(); static LLRect calcScaledRect(const LLRect & rect, const LLVector2& display_scale); + bool getSystemUIScaleFactorChanged() { return mSystemUIScaleFactorChanged; } + static void showSystemUIScaleFactorChanged(); + private: bool shouldShowToolTipFor(LLMouseHandler *mh); @@ -428,6 +433,7 @@ private: S32 getChatConsoleBottomPad(); // Vertical padding for child console rect, varied by bottom clutter LLRect getChatConsoleRect(); // Get optimal cosole rect. + static bool onSystemUIScaleFactorChanged(const LLSD& notification, const LLSD& response); private: LLWindow* mWindow; // graphical window object bool mActive; @@ -506,6 +512,7 @@ private: LLPointer<LLViewerObject> mDragHoveredObject; static LLTrace::SampleStatHandle<> sMouseVelocityStat; + bool mSystemUIScaleFactorChanged; // system UI scale factor changed from last run }; // diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index cdc7e20c2c..96a1beffbc 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -106,6 +106,8 @@ #include "llsdutil.h" #include "llscenemonitor.h" #include "llsdserialize.h" +#include "llcallstack.h" +#include "llrendersphere.h" extern F32 SPEED_ADJUST_MAX; extern F32 SPEED_ADJUST_MAX_SEC; @@ -186,6 +188,7 @@ const F32 NAMETAG_VERTICAL_SCREEN_OFFSET = 25.f; const F32 NAMETAG_VERT_OFFSET_WEIGHT = 0.17f; const U32 LLVOAvatar::VISUAL_COMPLEXITY_UNKNOWN = 0; +const F64 HUD_OVERSIZED_TEXTURE_DATA_SIZE = 1024 * 1024; enum ERenderName { @@ -214,26 +217,8 @@ struct LLTextureMaskData ** **/ -//------------------------------------------------------------------------ -// LLVOAvatarBoneInfo -// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton. -//------------------------------------------------------------------------ -struct LLVOAvatarCollisionVolumeInfo : public LLInitParam::Block<LLVOAvatarCollisionVolumeInfo> -{ - LLVOAvatarCollisionVolumeInfo() - : name("name"), - pos("pos"), - rot("rot"), - scale("scale") - {} - Mandatory<std::string> name; - Mandatory<LLVector3> pos, - rot, - scale; -}; - -struct LLAppearanceMessageContents +struct LLAppearanceMessageContents: public LLRefCount { LLAppearanceMessageContents(): mAppearanceVersion(-1), @@ -253,49 +238,6 @@ struct LLAppearanceMessageContents bool mHoverOffsetWasSet; }; -struct LLVOAvatarChildJoint : public LLInitParam::ChoiceBlock<LLVOAvatarChildJoint> - { - Alternative<Lazy<struct LLVOAvatarBoneInfo, IS_A_BLOCK> > bone; - Alternative<LLVOAvatarCollisionVolumeInfo> collision_volume; - - LLVOAvatarChildJoint() - : bone("bone"), - collision_volume("collision_volume") - {} -}; - - - -struct LLVOAvatarBoneInfo : public LLInitParam::Block<LLVOAvatarBoneInfo, LLVOAvatarCollisionVolumeInfo> -{ - LLVOAvatarBoneInfo() - : pivot("pivot") - {} - - Mandatory<LLVector3> pivot; - Multiple<LLVOAvatarChildJoint> children; -}; - -//------------------------------------------------------------------------ -// LLVOAvatarSkeletonInfo -// Overall avatar skeleton -//------------------------------------------------------------------------ -struct LLVOAvatarSkeletonInfo : public LLInitParam::Block<LLVOAvatarSkeletonInfo> -{ - LLVOAvatarSkeletonInfo() - : skeleton_root(""), - num_bones("num_bones"), - num_collision_volumes("num_collision_volumes"), - version("version") - {} - - Mandatory<std::string> version; - Mandatory<S32> num_bones, - num_collision_volumes; - Mandatory<LLVOAvatarChildJoint> skeleton_root; -}; - - //----------------------------------------------------------------------------- // class LLBodyNoiseMotion @@ -1111,7 +1053,6 @@ void LLVOAvatar::deleteCachedImages(bool clearAll) { if (LLViewerTexLayerSet::sHasCaches) { - LL_DEBUGS() << "Deleting layer set caches" << LL_ENDL; for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); iter != LLCharacter::sInstances.end(); ++iter) { @@ -1142,6 +1083,9 @@ void LLVOAvatar::initClass() gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix"); gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target"); gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust"); + + // Where should this be set initially? + LLJoint::setDebugJointNames(gSavedSettings.getString("DebugAvatarJoints")); } @@ -1395,18 +1339,78 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) newMax.add(buffer); } +void render_sphere_and_line(const LLVector3& begin_pos, const LLVector3& end_pos, F32 sphere_scale, const LLVector3& occ_color, const LLVector3& visible_color) +{ + // Unoccluded bone portions + LLGLDepthTest normal_depth(GL_TRUE); + + // Draw line segment for unoccluded joint + gGL.diffuseColor3f(visible_color[0], visible_color[1], visible_color[2]); + + gGL.begin(LLRender::LINES); + gGL.vertex3fv(begin_pos.mV); + gGL.vertex3fv(end_pos.mV); + gGL.end(); + + + // Draw sphere representing joint pos + gGL.pushMatrix(); + gGL.scalef(sphere_scale, sphere_scale, sphere_scale); + gSphere.renderGGL(); + gGL.popMatrix(); + + LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER); + + // Occluded bone portions + gGL.diffuseColor3f(occ_color[0], occ_color[1], occ_color[2]); + + gGL.begin(LLRender::LINES); + gGL.vertex3fv(begin_pos.mV); + gGL.vertex3fv(end_pos.mV); + gGL.end(); + + // Draw sphere representing joint pos + gGL.pushMatrix(); + gGL.scalef(sphere_scale, sphere_scale, sphere_scale); + gSphere.renderGGL(); + gGL.popMatrix(); +} + //----------------------------------------------------------------------------- // renderCollisionVolumes() //----------------------------------------------------------------------------- void LLVOAvatar::renderCollisionVolumes() { std::ostringstream ostr; + for (S32 i = 0; i < mNumCollisionVolumes; i++) { - mCollisionVolumes[i].renderCollision(); ostr << mCollisionVolumes[i].getName() << ", "; - } + LLAvatarJointCollisionVolume& collision_volume = mCollisionVolumes[i]; + + collision_volume.updateWorldMatrix(); + + gGL.pushMatrix(); + gGL.multMatrix( &collision_volume.getXform()->getWorldMatrix().mMatrix[0][0] ); + + LLVector3 begin_pos(0,0,0); + LLVector3 end_pos(collision_volume.getEnd()); + static F32 sphere_scale = 1.0f; + static F32 center_dot_scale = 0.05f; + + static LLVector3 CV_COLOR_OCCLUDED(0.0f, 0.0f, 1.0f); + static LLVector3 CV_COLOR_VISIBLE(0.5f, 0.5f, 1.0f); + static LLVector3 DOT_COLOR_OCCLUDED(1.0f, 1.0f, 1.0f); + static LLVector3 DOT_COLOR_VISIBLE(1.0f, 1.0f, 1.0f); + + render_sphere_and_line(begin_pos, end_pos, sphere_scale, CV_COLOR_OCCLUDED, CV_COLOR_VISIBLE); + render_sphere_and_line(begin_pos, end_pos, center_dot_scale, DOT_COLOR_OCCLUDED, DOT_COLOR_VISIBLE); + + gGL.popMatrix(); + } + + if (mNameText.notNull()) { LLVector4a unused; @@ -1418,6 +1422,72 @@ void LLVOAvatar::renderCollisionVolumes() addDebugText(ostr.str()); } +void LLVOAvatar::renderBones() +{ + LLGLEnable blend(GL_BLEND); + + avatar_joint_list_t::iterator iter = mSkeleton.begin(); + avatar_joint_list_t::iterator end = mSkeleton.end(); + + // For bones with position overrides defined + static LLVector3 OVERRIDE_COLOR_OCCLUDED(1.0f, 0.0f, 0.0f); + static LLVector3 OVERRIDE_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); + // For bones which are rigged to by at least one attachment + static LLVector3 RIGGED_COLOR_OCCLUDED(0.0f, 1.0f, 1.0f); + static LLVector3 RIGGED_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); + // For bones not otherwise colored + static LLVector3 OTHER_COLOR_OCCLUDED(0.0f, 1.0f, 0.0f); + static LLVector3 OTHER_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); + + static F32 SPHERE_SCALEF = 0.001f; + + for (; iter != end; ++iter) + { + LLJoint* jointp = *iter; + if (!jointp) + { + continue; + } + + jointp->updateWorldMatrix(); + + LLVector3 occ_color, visible_color; + + LLVector3 pos; + LLUUID mesh_id; + if (jointp->hasAttachmentPosOverride(pos,mesh_id)) + { + occ_color = OVERRIDE_COLOR_OCCLUDED; + visible_color = OVERRIDE_COLOR_VISIBLE; + } + else + { + if (jointIsRiggedTo(jointp->getName())) + { + occ_color = RIGGED_COLOR_OCCLUDED; + visible_color = RIGGED_COLOR_VISIBLE; + } + else + { + occ_color = OTHER_COLOR_OCCLUDED; + visible_color = OTHER_COLOR_VISIBLE; + } + } + LLVector3 begin_pos(0,0,0); + LLVector3 end_pos(jointp->getEnd()); + + F32 sphere_scale = SPHERE_SCALEF; + + gGL.pushMatrix(); + gGL.multMatrix( &jointp->getXform()->getWorldMatrix().mMatrix[0][0] ); + + render_sphere_and_line(begin_pos, end_pos, sphere_scale, occ_color, visible_color); + + gGL.popMatrix(); + } +} + + void LLVOAvatar::renderJoints() { std::ostringstream ostr; @@ -1525,7 +1595,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& for (S32 i = 0; i < mNumCollisionVolumes; ++i) { mCollisionVolumes[i].updateWorldMatrix(); - + glh::matrix4f mat((F32*) mCollisionVolumes[i].getXform()->getWorldMatrix().mMatrix); glh::matrix4f inverse = mat.inverse(); glh::matrix4f norm_mat = inverse.transpose(); @@ -1734,6 +1804,133 @@ void LLVOAvatar::buildCharacter() mMeshValid = TRUE; } +//----------------------------------------------------------------------------- +// resetVisualParams() +//----------------------------------------------------------------------------- +void LLVOAvatar::resetVisualParams() +{ + // Skeletal params + { + LLAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter; + for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin(); + iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end(); + ++iter) + { + LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)*iter; + LLPolySkeletalDistortion *param = dynamic_cast<LLPolySkeletalDistortion*>(getVisualParam(info->getID())); + *param = LLPolySkeletalDistortion(this); + llassert(param); + if (!param->setInfo(info)) + { + llassert(false); + } + } + } + + // Driver parameters + for (LLAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin(); + iter != sAvatarXmlInfo->mDriverInfoList.end(); + ++iter) + { + LLDriverParamInfo *info = *iter; + LLDriverParam *param = dynamic_cast<LLDriverParam*>(getVisualParam(info->getID())); + LLDriverParam::entry_list_t driven_list = param->getDrivenList(); + *param = LLDriverParam(this); + llassert(param); + if (!param->setInfo(info)) + { + llassert(false); + } + param->setDrivenList(driven_list); + } +} + +//----------------------------------------------------------------------------- +// resetSkeleton() +//----------------------------------------------------------------------------- +void LLVOAvatar::resetSkeleton(bool reset_animations) +{ + LL_DEBUGS("Avatar") << avString() << " reset starts" << LL_ENDL; + if (!mLastProcessedAppearance) + { + LL_WARNS() << "Can't reset avatar; no appearance message has been received yet." << LL_ENDL; + return; + } + + // Save mPelvis state + //LLVector3 pelvis_pos = getJoint("mPelvis")->getPosition(); + //LLQuaternion pelvis_rot = getJoint("mPelvis")->getRotation(); + + // Clear all attachment pos and scale overrides + clearAttachmentOverrides(); + + // Note that we call buildSkeleton twice in this function. The first time is + // just to get the right scale for the collision volumes, because + // this will be used in setting the mJointScales for the + // LLPolySkeletalDistortions of which the CVs are children. + if( !buildSkeleton(sAvatarSkeletonInfo) ) + { + LL_ERRS() << "Error resetting skeleton" << LL_ENDL; + } + + // Reset some params to default state, without propagating changes downstream. + resetVisualParams(); + + // Now we have to reset the skeleton again, because its state + // got clobbered by the resetVisualParams() calls + // above. + if( !buildSkeleton(sAvatarSkeletonInfo) ) + { + LL_ERRS() << "Error resetting skeleton" << LL_ENDL; + } + + // Reset attachment points (buildSkeleton only does bones and CVs) + bool ignore_hud_joints = true; + initAttachmentPoints(ignore_hud_joints); + + // Fix up collision volumes + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + LLPolyMorphTarget *poly_morph = dynamic_cast<LLPolyMorphTarget*>(param); + if (poly_morph) + { + // This is a kludgy way to correct for the fact that the + // collision volumes have been reset out from under the + // poly morph sliders. + F32 delta_weight = poly_morph->getLastWeight() - poly_morph->getDefaultWeight(); + poly_morph->applyVolumeChanges(delta_weight); + } + } + + // Reset tweakable params to preserved state + bool slam_params = true; + applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params); + updateVisualParams(); + + // Restore attachment pos overrides + rebuildAttachmentOverrides(); + + // Animations + if (reset_animations) + { + if (isSelf()) + { + // This is equivalent to "Stop Animating Me". Will reset + // all animations and propagate the changes to other + // viewers. + gAgent.stopCurrentAnimations(); + } + else + { + // Local viewer-side reset for non-self avatars. + resetAnimations(); + } + } + + LL_DEBUGS("Avatar") << avString() << " reset ends" << LL_ENDL; +} //----------------------------------------------------------------------------- // releaseMeshData() @@ -1745,8 +1942,6 @@ void LLVOAvatar::releaseMeshData() return; } - LL_DEBUGS() << "Releasing mesh data" << LL_ENDL; - // cleanup mesh data for (avatar_joint_list_t::iterator iter = mMeshLOD.begin(); iter != mMeshLOD.end(); @@ -1956,17 +2151,12 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, // Do base class updates... U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); - //LLTEContents tec; - //S32 te_retval = parseTEMessage(mesgsys, _PREHASH_ObjectData, block_num, tec); - - LL_DEBUGS("Avatar") << avString() << update_type << LL_ENDL; - // Print out arrival information once we have name of avatar. - if (has_name && getNVPair("FirstName")) - { - mDebugExistenceTimer.reset(); - debugAvatarRezTime("AvatarRezArrivedNotification","avatar arrived"); - } + if (has_name && getNVPair("FirstName")) + { + mDebugExistenceTimer.reset(); + debugAvatarRezTime("AvatarRezArrivedNotification","avatar arrived"); + } if(retval & LLViewerObject::INVALID_UPDATE) { @@ -2074,6 +2264,8 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) return; } + LLScopedContextString str("avatar_idle_update " + getFullname()); + checkTextureLoading() ; // force immediate pixel area update on avatars using last frames data (before drawable or camera updates) @@ -3078,6 +3270,7 @@ void LLVOAvatar::idleUpdateBelowWater() void LLVOAvatar::slamPosition() { gAgent.setPositionAgent(getPositionAgent()); + // SL-315 mRoot->setWorldPosition(getPositionAgent()); // teleport setChanged(TRANSLATED); if (mDrawable.notNull()) @@ -3175,23 +3368,31 @@ void LLVOAvatar::updateDebugText() { debug_line += llformat(" - cof rcv:%d", last_received_cof_version); } - debug_line += llformat(" bsz-z: %f avofs-z: %f", mBodySize[2], mAvatarOffset[2]); + debug_line += llformat(" bsz-z: %.3f", mBodySize[2]); + if (mAvatarOffset[2] != 0.0f) + { + debug_line += llformat("avofs-z: %.3f", mAvatarOffset[2]); + } bool hover_enabled = getRegion() && getRegion()->avatarHoverHeightEnabled(); debug_line += hover_enabled ? " H" : " h"; const LLVector3& hover_offset = getHoverOffset(); if (hover_offset[2] != 0.0) { - debug_line += llformat(" hov_z: %f", hover_offset[2]); + debug_line += llformat(" hov_z: %.3f", hover_offset[2]); debug_line += llformat(" %s", (mIsSitting ? "S" : "T")); debug_line += llformat("%s", (isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED) ? "G" : "-")); } - F32 elapsed = mLastAppearanceMessageTimer.getElapsedTimeF32(); - static const char *elapsed_chars = "Xx*..."; - U32 bucket = U32(elapsed*2); - if (bucket < strlen(elapsed_chars)) - { - debug_line += llformat(" %c", elapsed_chars[bucket]); - } + LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); + LLVector3 normal; + LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; + resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); + F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); + debug_line += llformat(" relev %.3f", rightElev); + + LLVector3 root_pos = mRoot->getPosition(); + LLVector3 pelvis_pos = mPelvisp->getPosition(); + debug_line += llformat(" rp %.3f pp %.3f", root_pos[2], pelvis_pos[2]); + addDebugText(debug_line); } if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked")) @@ -3376,6 +3577,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) mTimeLast = animation_time; // put the pelvis at slaved position/mRotation + // SL-315 mRoot->setWorldPosition( getPositionAgent() ); // first frame mRoot->setWorldRotation( getRotation() ); } @@ -3416,6 +3618,13 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) } mInAir = in_air; + // SL-402: with the ability to animate the position of joints + // that affect the body size calculation, computed body size + // can get stale much more easily. Simplest fix is to update + // it frequently. + // SL-427: this appears to be too frequent, moving to only do on animation state change. + //computeBodySize(); + // correct for the fact that the pelvis is not necessarily the center // of the agent's physical representation root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; @@ -3430,6 +3639,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) if (newPosition != mRoot->getXform()->getWorldPosition()) { mRoot->touch(); + // SL-315 mRoot->setWorldPosition( newPosition ); // regular update } @@ -3593,6 +3803,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) { LLVector3 pos = mDrawable->getPosition(); pos += getHoverOffset() * mDrawable->getRotation(); + // SL-315 mRoot->setPosition(pos); mRoot->setRotation(mDrawable->getRotation()); } @@ -3623,6 +3834,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) LLVector3 pos = mRoot->getWorldPosition(); pos.mV[VZ] += off_z; mRoot->touch(); + // SL-315 mRoot->setWorldPosition(pos); } } @@ -3738,10 +3950,78 @@ void LLVOAvatar::updateHeadOffset() mHeadOffset = lerp(midEyePt, mHeadOffset, u); } } + +void LLVOAvatar::debugBodySize() const +{ + LLVector3 pelvis_scale = mPelvisp->getScale(); + + // some of the joints have not been cached + LLVector3 skull = mSkullp->getPosition(); + LL_DEBUGS("Avatar") << "skull pos " << skull << LL_ENDL; + //LLVector3 skull_scale = mSkullp->getScale(); + + LLVector3 neck = mNeckp->getPosition(); + LLVector3 neck_scale = mNeckp->getScale(); + LL_DEBUGS("Avatar") << "neck pos " << neck << " neck_scale " << neck_scale << LL_ENDL; + + LLVector3 chest = mChestp->getPosition(); + LLVector3 chest_scale = mChestp->getScale(); + LL_DEBUGS("Avatar") << "chest pos " << chest << " chest_scale " << chest_scale << LL_ENDL; + + // the rest of the joints have been cached + LLVector3 head = mHeadp->getPosition(); + LLVector3 head_scale = mHeadp->getScale(); + LL_DEBUGS("Avatar") << "head pos " << head << " head_scale " << head_scale << LL_ENDL; + + LLVector3 torso = mTorsop->getPosition(); + LLVector3 torso_scale = mTorsop->getScale(); + LL_DEBUGS("Avatar") << "torso pos " << torso << " torso_scale " << torso_scale << LL_ENDL; + + LLVector3 hip = mHipLeftp->getPosition(); + LLVector3 hip_scale = mHipLeftp->getScale(); + LL_DEBUGS("Avatar") << "hip pos " << hip << " hip_scale " << hip_scale << LL_ENDL; + + LLVector3 knee = mKneeLeftp->getPosition(); + LLVector3 knee_scale = mKneeLeftp->getScale(); + LL_DEBUGS("Avatar") << "knee pos " << knee << " knee_scale " << knee_scale << LL_ENDL; + + LLVector3 ankle = mAnkleLeftp->getPosition(); + LLVector3 ankle_scale = mAnkleLeftp->getScale(); + LL_DEBUGS("Avatar") << "ankle pos " << ankle << " ankle_scale " << ankle_scale << LL_ENDL; + + LLVector3 foot = mFootLeftp->getPosition(); + LL_DEBUGS("Avatar") << "foot pos " << foot << LL_ENDL; + + F32 new_offset = (const_cast<LLVOAvatar*>(this))->getVisualParamWeight(AVATAR_HOVER); + LL_DEBUGS("Avatar") << "new_offset " << new_offset << LL_ENDL; + + F32 new_pelvis_to_foot = hip.mV[VZ] * pelvis_scale.mV[VZ] - + knee.mV[VZ] * hip_scale.mV[VZ] - + ankle.mV[VZ] * knee_scale.mV[VZ] - + foot.mV[VZ] * ankle_scale.mV[VZ]; + LL_DEBUGS("Avatar") << "new_pelvis_to_foot " << new_pelvis_to_foot << LL_ENDL; + + LLVector3 new_body_size; + new_body_size.mV[VZ] = new_pelvis_to_foot + + // the sqrt(2) correction below is an approximate + // correction to get to the top of the head + F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + + head.mV[VZ] * neck_scale.mV[VZ] + + neck.mV[VZ] * chest_scale.mV[VZ] + + chest.mV[VZ] * torso_scale.mV[VZ] + + torso.mV[VZ] * pelvis_scale.mV[VZ]; + + // TODO -- measure the real depth and width + new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; + new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; + + LL_DEBUGS("Avatar") << "new_body_size " << new_body_size << LL_ENDL; +} + //------------------------------------------------------------------------ // postPelvisSetRecalc //------------------------------------------------------------------------ -void LLVOAvatar::postPelvisSetRecalc( void ) +void LLVOAvatar::postPelvisSetRecalc() { mRoot->updateWorldMatrixChildren(); computeBodySize(); @@ -4831,6 +5111,12 @@ void LLVOAvatar::processAnimationStateChanges() //----------------------------------------------------------------------------- BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL start ) { + // SL-402, SL-427 - we need to update body size often enough to + // keep appearances in sync, but not so often that animations + // cause constant jiggling of the body or camera. Possible + // compromise is to do it on animation changes: + computeBodySize(); + BOOL result = FALSE; if ( start ) // start animation @@ -5055,18 +5341,52 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name ) LLJoint* jointp = NULL; if (iter == mJointMap.end() || iter->second == NULL) - { //search for joint and cache found joint in lookup table + { //search for joint and cache found joint in lookup table jointp = mRoot->findJoint(name); mJointMap[name] = jointp; } else - { //return cached pointer + { //return cached pointer jointp = iter->second; } +#ifndef LL_RELEASE_FOR_DOWNLOAD + if (jointp && jointp->getName()!="mScreen" && jointp->getName()!="mRoot") + { + llassert(getJoint(jointp->getJointNum())==jointp); + } +#endif return jointp; } +LLJoint *LLVOAvatar::getJoint( S32 joint_num ) +{ + LLJoint *pJoint = NULL; + S32 collision_start = mNumBones; + S32 attachment_start = mNumBones + mNumCollisionVolumes; + if (joint_num>=attachment_start) + { + // Attachment IDs start at 1 + S32 attachment_id = joint_num - attachment_start + 1; + attachment_map_t::iterator iter = mAttachmentPoints.find(attachment_id); + if (iter != mAttachmentPoints.end()) + { + pJoint = iter->second; + } + } + else if (joint_num>=collision_start) + { + S32 collision_id = joint_num-collision_start; + pJoint = &mCollisionVolumes[collision_id]; + } + else if (joint_num>=0) + { + pJoint = mSkeleton[joint_num]; + } + llassert(!pJoint || pJoint->getJointNum() == joint_num); + return pJoint; +} + //----------------------------------------------------------------------------- // getRiggedMeshID // @@ -5097,37 +5417,121 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id) return false; } -void LLVOAvatar::clearAttachmentPosOverrides() +bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name) { - //Subsequent joints are relative to pelvis - avatar_joint_list_t::iterator iter = mSkeleton.begin(); - avatar_joint_list_t::iterator end = mSkeleton.end(); + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && jointIsRiggedTo(joint_name, attached_object)) + { + return true; + } + } + } + return false; +} - for (; iter != end; ++iter) +bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo) +{ + // Process all children + LLViewerObject::const_child_list_t& children = vo->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); + it != children.end(); ++it) { - LLJoint* pJoint = (*iter); - pJoint->clearAttachmentPosOverrides(); + LLViewerObject *childp = *it; + if (jointIsRiggedTo(joint_name,childp)) + { + return true; + } } + + const LLVOVolume *vobj = dynamic_cast<const LLVOVolume*>(vo); + if (!vobj) + { + return false; + } + + LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); + const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); + + if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData ) + { + if (std::find(pSkinData->mJointNames.begin(), pSkinData->mJointNames.end(), joint_name) != + pSkinData->mJointNames.end()) + { + return true; + } + } + + return false; } +void LLVOAvatar::clearAttachmentOverrides() +{ + LLScopedContextString str("clearAttachmentOverrides " + getFullname()); + + for (S32 i=0; i<LL_CHARACTER_MAX_ANIMATED_JOINTS; i++) + { + LLJoint *pJoint = getJoint(i); + if (pJoint) + { + pJoint->clearAttachmentPosOverrides(); + pJoint->clearAttachmentScaleOverrides(); + } + } +} + +//----------------------------------------------------------------------------- +// rebuildAttachmentOverrides +//----------------------------------------------------------------------------- +void LLVOAvatar::rebuildAttachmentOverrides() +{ + LLScopedContextString str("rebuildAttachmentOverrides " + getFullname()); + + // Attachment points + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin(); + at_it != attachment_pt->mAttachedObjects.end(); ++at_it) + { + addAttachmentOverridesForObject(*at_it); + } + } + } +} //----------------------------------------------------------------------------- // addAttachmentPosOverridesForObject //----------------------------------------------------------------------------- -void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo) +void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) { LLVOAvatar *av = vo->getAvatarAncestor(); if (!av || (av != this)) { LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL; + return; } - + + LLScopedContextString str("addAttachmentOverridesForObject " + av->getFullname()); + // Process all children LLViewerObject::const_child_list_t& children = vo->getChildren(); for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); it != children.end(); ++it) { LLViewerObject *childp = *it; - addAttachmentPosOverridesForObject(childp); + addAttachmentOverridesForObject(childp); } LLVOVolume *vobj = dynamic_cast<LLVOVolume*>(vo); @@ -5148,9 +5552,13 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo) if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData ) { const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - if ( bindCnt > 0 ) + const int jointCnt = pSkinData->mJointNames.size(); + if ((bindCnt > 0) && (bindCnt != jointCnt)) + { + LL_WARNS_ONCE() << "invalid mesh, bindCnt " << bindCnt << "!= jointCnt " << jointCnt << ", joint overrides will be ignored." << LL_ENDL; + } + if ((bindCnt > 0) && (bindCnt == jointCnt)) { - const int jointCnt = pSkinData->mJointNames.size(); const F32 pelvisZOffset = pSkinData->mPelvisOffset; const LLUUID& mesh_id = pSkinData->mMeshID; bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false; @@ -5160,24 +5568,43 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo) { std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); LLJoint* pJoint = getJoint( lookingForJoint ); - if ( pJoint && pJoint->getId() != currentId ) + if (pJoint) { - pJoint->setId( currentId ); const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); - //Set the joint position - pJoint->addAttachmentPosOverride( jointPos, mesh_id, avString() ); - - //If joint is a pelvis then handle old/new pelvis to foot values - if ( lookingForJoint == "mPelvis" ) - { - pelvisGotSet = true; - } + if (pJoint->aboveJointPosThreshold(jointPos)) + { + bool override_changed; + pJoint->addAttachmentPosOverride( jointPos, mesh_id, avString(), override_changed ); + + if (override_changed) + { + //If joint is a pelvis then handle old/new pelvis to foot values + if ( lookingForJoint == "mPelvis" ) + { + pelvisGotSet = true; + } + } + if (pSkinData->mLockScaleIfJointPosition) + { + // Note that unlike positions, there's no threshold check here, + // just a lock at the default value. + pJoint->addAttachmentScaleOverride(pJoint->getDefaultScale(), mesh_id, avString()); + } + } } } if (pelvisZOffset != 0.0F) { + F32 pelvis_fixup_before; + bool has_fixup_before = hasPelvisFixup(pelvis_fixup_before); addPelvisFixup( pelvisZOffset, mesh_id ); - pelvisGotSet = true; + F32 pelvis_fixup_after; + hasPelvisFixup(pelvis_fixup_after); // Don't have to check bool here because we just added it... + if (!has_fixup_before || (pelvis_fixup_before != pelvis_fixup_after)) + { + pelvisGotSet = true; + } + } } } @@ -5191,9 +5618,122 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo) } //----------------------------------------------------------------------------- -// resetJointPositionsOnDetach +// getAttachmentOverrideNames +//----------------------------------------------------------------------------- +void LLVOAvatar::getAttachmentOverrideNames(std::set<std::string>& pos_names, std::set<std::string>& scale_names) const +{ + LLVector3 pos; + LLVector3 scale; + LLUUID mesh_id; + + // Bones + for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); + iter != mSkeleton.end(); ++iter) + { + const LLJoint* pJoint = (*iter); + if (pJoint && pJoint->hasAttachmentPosOverride(pos,mesh_id)) + { + pos_names.insert(pJoint->getName()); + } + if (pJoint && pJoint->hasAttachmentScaleOverride(scale,mesh_id)) + { + scale_names.insert(pJoint->getName()); + } + } + + // Attachment points + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos,mesh_id)) + { + pos_names.insert(attachment_pt->getName()); + } + // Attachment points don't have scales. + } + +} + +//----------------------------------------------------------------------------- +// showAttachmentOverrides //----------------------------------------------------------------------------- -void LLVOAvatar::resetJointPositionsOnDetach(LLViewerObject *vo) +void LLVOAvatar::showAttachmentOverrides(bool verbose) const +{ + std::set<std::string> pos_names, scale_names; + getAttachmentOverrideNames(pos_names, scale_names); + if (pos_names.size()) + { + std::stringstream ss; + std::copy(pos_names.begin(), pos_names.end(), std::ostream_iterator<std::string>(ss, ",")); + LL_INFOS() << getFullname() << " attachment positions defined for joints: " << ss.str() << "\n" << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << getFullname() << " no attachment positions defined for any joints" << "\n" << LL_ENDL; + } + if (scale_names.size()) + { + std::stringstream ss; + std::copy(scale_names.begin(), scale_names.end(), std::ostream_iterator<std::string>(ss, ",")); + LL_INFOS() << getFullname() << " attachment scales defined for joints: " << ss.str() << "\n" << LL_ENDL; + } + else + { + LL_INFOS() << getFullname() << " no attachment scales defined for any joints" << "\n" << LL_ENDL; + } + + if (!verbose) + { + return; + } + + LLVector3 pos, scale; + LLUUID mesh_id; + S32 count = 0; + + // Bones + for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); + iter != mSkeleton.end(); ++iter) + { + const LLJoint* pJoint = (*iter); + if (pJoint && pJoint->hasAttachmentPosOverride(pos,mesh_id)) + { + pJoint->showAttachmentPosOverrides(getFullname()); + count++; + } + if (pJoint && pJoint->hasAttachmentScaleOverride(scale,mesh_id)) + { + pJoint->showAttachmentScaleOverrides(getFullname()); + count++; + } + } + + // Attachment points + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos,mesh_id)) + { + attachment_pt->showAttachmentPosOverrides(getFullname()); + count++; + } + } + + if (count) + { + LL_DEBUGS("Avatar") << avString() << " end of pos, scale overrides" << LL_ENDL; + LL_DEBUGS("Avatar") << "=================================" << LL_ENDL; + } +} + +//----------------------------------------------------------------------------- +// resetJointsOnDetach +//----------------------------------------------------------------------------- +void LLVOAvatar::resetJointsOnDetach(LLViewerObject *vo) { LLVOAvatar *av = vo->getAvatarAncestor(); if (!av || (av != this)) @@ -5207,21 +5747,21 @@ void LLVOAvatar::resetJointPositionsOnDetach(LLViewerObject *vo) it != children.end(); ++it) { LLViewerObject *childp = *it; - resetJointPositionsOnDetach(childp); + resetJointsOnDetach(childp); } // Process self. LLUUID mesh_id; if (getRiggedMeshID(vo,mesh_id)) { - resetJointPositionsOnDetach(mesh_id); + resetJointsOnDetach(mesh_id); } } //----------------------------------------------------------------------------- -// resetJointPositionsOnDetach +// resetJointsOnDetach //----------------------------------------------------------------------------- -void LLVOAvatar::resetJointPositionsOnDetach(const LLUUID& mesh_id) +void LLVOAvatar::resetJointsOnDetach(const LLUUID& mesh_id) { //Subsequent joints are relative to pelvis avatar_joint_list_t::iterator iter = mSkeleton.begin(); @@ -5235,12 +5775,14 @@ void LLVOAvatar::resetJointPositionsOnDetach(const LLUUID& mesh_id) //Reset joints except for pelvis if ( pJoint ) { - pJoint->setId( LLUUID::null ); - pJoint->removeAttachmentPosOverride(mesh_id, avString()); + bool dummy; // unused + pJoint->removeAttachmentPosOverride(mesh_id, avString(),dummy); + pJoint->removeAttachmentScaleOverride(mesh_id, avString()); } if ( pJoint && pJoint == pJointPelvis) { removePelvisFixup( mesh_id ); + // SL-315 pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) ); } } @@ -5372,83 +5914,99 @@ BOOL LLVOAvatar::loadSkeletonNode () return FALSE; } - // ATTACHMENTS - { - LLAvatarXmlInfo::attachment_info_list_t::iterator iter; - for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); - iter != sAvatarXmlInfo->mAttachmentInfoList.end(); - ++iter) - { - LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter; - if (!isSelf() && info->mJointName == "mScreen") - { //don't process screen joint for other avatars - continue; - } + bool ignore_hud_joints = false; + initAttachmentPoints(ignore_hud_joints); - LLViewerJointAttachment* attachment = new LLViewerJointAttachment(); + return TRUE; +} - attachment->setName(info->mName); - LLJoint *parentJoint = getJoint(info->mJointName); - if (!parentJoint) - { - LL_WARNS() << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << LL_ENDL; - delete attachment; - continue; - } +//----------------------------------------------------------------------------- +// initAttachmentPoints(): creates attachment points if needed, sets state based on avatar_lad.xml. +//----------------------------------------------------------------------------- +void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints) +{ + LLAvatarXmlInfo::attachment_info_list_t::iterator iter; + for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); + iter != sAvatarXmlInfo->mAttachmentInfoList.end(); + ++iter) + { + LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter; + if (info->mIsHUDAttachment && (!isSelf() || ignore_hud_joints)) + { + //don't process hud joint for other avatars, or when doing a skeleton reset. + continue; + } - if (info->mHasPosition) - { - attachment->setOriginalPosition(info->mPosition); - } - - if (info->mHasRotation) - { - LLQuaternion rotation; - rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD, - info->mRotationEuler.mV[VY] * DEG_TO_RAD, - info->mRotationEuler.mV[VZ] * DEG_TO_RAD); - attachment->setRotation(rotation); - } + S32 attachmentID = info->mAttachmentID; + if (attachmentID < 1 || attachmentID > 255) + { + LL_WARNS() << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << LL_ENDL; + continue; + } - int group = info->mGroup; - if (group >= 0) - { - if (group < 0 || group >= 9) - { - LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL; - } - else - { - attachment->setGroup(group); - } - } + LLViewerJointAttachment* attachment = NULL; + bool newly_created = false; + if (mAttachmentPoints.find(attachmentID) == mAttachmentPoints.end()) + { + attachment = new LLViewerJointAttachment(); + newly_created = true; + } + else + { + attachment = mAttachmentPoints[attachmentID]; + } - S32 attachmentID = info->mAttachmentID; - if (attachmentID < 1 || attachmentID > 255) - { - LL_WARNS() << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << LL_ENDL; - delete attachment; - continue; - } - if (mAttachmentPoints.find(attachmentID) != mAttachmentPoints.end()) - { - LL_WARNS() << "Attachment point redefined with id " << attachmentID << " on attachment point " << info->mName << LL_ENDL; - delete attachment; - continue; - } + attachment->setName(info->mName); + LLJoint *parent_joint = getJoint(info->mJointName); + if (!parent_joint) + { + // If the intended parent for attachment point is unavailable, avatar_lad.xml is corrupt. + LL_WARNS() << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << LL_ENDL; + LL_ERRS() << "Invalid avatar_lad.xml file" << LL_ENDL; + } - attachment->setPieSlice(info->mPieMenuSlice); - attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson); - attachment->setIsHUDAttachment(info->mIsHUDAttachment); + if (info->mHasPosition) + { + attachment->setOriginalPosition(info->mPosition); + attachment->setDefaultPosition(info->mPosition); + } + + if (info->mHasRotation) + { + LLQuaternion rotation; + rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD, + info->mRotationEuler.mV[VY] * DEG_TO_RAD, + info->mRotationEuler.mV[VZ] * DEG_TO_RAD); + attachment->setRotation(rotation); + } - mAttachmentPoints[attachmentID] = attachment; + int group = info->mGroup; + if (group >= 0) + { + if (group < 0 || group > 9) + { + LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL; + } + else + { + attachment->setGroup(group); + } + } - // now add attachment joint - parentJoint->addChild(attachment); - } - } + attachment->setPieSlice(info->mPieMenuSlice); + attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson); + attachment->setIsHUDAttachment(info->mIsHUDAttachment); + // attachment can potentially be animated, needs a number. + attachment->setJointNum(mNumBones + mNumCollisionVolumes + attachmentID - 1); - return TRUE; + if (newly_created) + { + mAttachmentPoints[attachmentID] = attachment; + + // now add attachment joint + parent_joint->addChild(attachment); + } + } } //----------------------------------------------------------------------------- @@ -5920,7 +6478,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO ) LLUUID mesh_id; if (getRiggedMeshID(pVO, mesh_id)) { - resetJointPositionsOnDetach(mesh_id); + resetJointsOnDetach(mesh_id); if ( gAgentCamera.cameraCustomizeAvatar() ) { gAgent.unpauseAnimation(); @@ -6017,6 +6575,7 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) // objects to be not rendered for new arrivals. See EXT-6835 and EXT-1655. sitDown(TRUE); mRoot->getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject + // SL-315 mRoot->setPosition(getPosition()); mRoot->updateWorldMatrixChildren(); @@ -6075,6 +6634,7 @@ void LLVOAvatar::getOffObject() sitDown(FALSE); mRoot->getXform()->setParent(NULL); // LLVOAvatar::getOffObject + // SL-315 mRoot->setPosition(cur_position_world); mRoot->setRotation(cur_rotation_world); mRoot->getXform()->update(); @@ -6118,7 +6678,6 @@ LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj ) return NULL; } -// warning: order(N) not order(1) S32 LLVOAvatar::getAttachmentCount() { S32 count = mAttachmentPoints.size(); @@ -7121,11 +7680,10 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value) wtype = vparam->getWearableType(); } S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight()); - apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\"/>\n", - viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, type_string.c_str(), - LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str() -// param_location_name(vparam->getParamLocation()).c_str() - ); + apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" display=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\" group=\"%d\"/>\n", + viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getDisplayName().c_str(), value, u8_value, type_string.c_str(), + LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str(), + viewer_param->getGroup()); } @@ -7190,7 +7748,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe U8 av_u8; mesgsys->getU8Fast(_PREHASH_AppearanceData, _PREHASH_AppearanceVersion, av_u8, 0); contents.mAppearanceVersion = av_u8; - LL_DEBUGS("Avatar") << "appversion set by AppearanceData field: " << contents.mAppearanceVersion << LL_ENDL; + //LL_DEBUGS("Avatar") << "appversion set by AppearanceData field: " << contents.mAppearanceVersion << LL_ENDL; mesgsys->getS32Fast(_PREHASH_AppearanceData, _PREHASH_CofVersion, contents.mCOFVersion, 0); // For future use: //mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0); @@ -7202,7 +7760,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe { LLVector3 hover; mesgsys->getVector3Fast(_PREHASH_AppearanceHover, _PREHASH_HoverHeight, hover); - LL_DEBUGS("Avatar") << avString() << " hover received " << hover.mV[ VX ] << "," << hover.mV[ VY ] << "," << hover.mV[ VZ ] << LL_ENDL; + //LL_DEBUGS("Avatar") << avString() << " hover received " << hover.mV[ VX ] << "," << hover.mV[ VY ] << "," << hover.mV[ VZ ] << LL_ENDL; contents.mHoverOffset = hover; contents.mHoverOffsetWasSet = true; } @@ -7212,7 +7770,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing if( num_blocks > 1 && !drop_visual_params_debug) { - LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL; + //LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL; LLVisualParam* param = getFirstVisualParam(); llassert(param); // if this ever fires, we should do the same as when num_blocks<=1 @@ -7273,7 +7831,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe { S32 index = it - contents.mParams.begin(); contents.mParamAppearanceVersion = ll_round(contents.mParamWeights[index]); - LL_DEBUGS("Avatar") << "appversion req by appearance_version param: " << contents.mParamAppearanceVersion << LL_ENDL; + //LL_DEBUGS("Avatar") << "appversion req by appearance_version param: " << contents.mParamAppearanceVersion << LL_ENDL; } } } @@ -7302,9 +7860,9 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32 { appearance_version = 1; } - LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion - << " param: " << contents.mParamAppearanceVersion - << " final: " << appearance_version << LL_ENDL; + //LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion + // << " param: " << contents.mParamAppearanceVersion + // << " final: " << appearance_version << LL_ENDL; return true; } @@ -7325,17 +7883,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) mLastAppearanceMessageTimer.reset(); - ESex old_sex = getSex(); - - LLAppearanceMessageContents contents; - parseAppearanceMessage(mesgsys, contents); + LLPointer<LLAppearanceMessageContents> contents(new LLAppearanceMessageContents); + parseAppearanceMessage(mesgsys, *contents); if (enable_verbose_dumps) { - dumpAppearanceMsgParams(dump_prefix + "appearance_msg", contents); + dumpAppearanceMsgParams(dump_prefix + "appearance_msg", *contents); } S32 appearance_version; - if (!resolve_appearance_version(contents, appearance_version)) + if (!resolve_appearance_version(*contents, appearance_version)) { LL_WARNS() << "bad appearance version info, discarding" << LL_ENDL; return; @@ -7347,7 +7903,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) return; } - S32 thisAppearanceVersion(contents.mCOFVersion); + S32 thisAppearanceVersion(contents->mCOFVersion); if (isSelf()) { // In the past this was considered to be the canonical COF version, // that is no longer the case. The canonical version is maintained @@ -7377,7 +7933,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } // SUNSHINE CLEANUP - is this case OK now? - S32 num_params = contents.mParamWeights.size(); + S32 num_params = contents->mParamWeights.size(); if (num_params <= 1) { // In this case, we have no reliable basis for knowing @@ -7389,18 +7945,30 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } // No backsies zone - if we get here, the message should be valid and usable, will be processed. + // Note: + // RequestAgentUpdateAppearanceResponder::onRequestRequested() + // assumes that cof version is only updated with server-bake + // appearance messages. LL_INFOS("Avatar") << "Processing appearance message version " << thisAppearanceVersion << LL_ENDL; - if (isSelf()) - { - // Note: - // locally the COF is maintained via LLInventoryModel::accountForUpdate - // which is called from various places. This should match the simhost's - // idea of what the COF version is. AIS however maintains its own version - // of the COF that should be considered canonical. - mLastUpdateReceivedCOFVersion = thisAppearanceVersion; - } - + // Note: + // locally the COF is maintained via LLInventoryModel::accountForUpdate + // which is called from various places. This should match the simhost's + // idea of what the COF version is. AIS however maintains its own version + // of the COF that should be considered canonical. + mLastUpdateReceivedCOFVersion = thisAppearanceVersion; + + mLastProcessedAppearance = contents; + + bool slam_params = false; + applyParsedAppearanceMessage(*contents, slam_params); +} + +void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params) +{ + S32 num_params = contents.mParamWeights.size(); + ESex old_sex = getSex(); + if (applyParsedTEMessage(contents.mTEContents) > 0 && isChanged(TEXTURE)) { updateVisualComplexity(); @@ -7430,8 +7998,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived; mFirstAppearanceMessageReceived = TRUE; - LL_DEBUGS("Avatar") << avString() << "processAvatarAppearance start " << mID - << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL; + //LL_DEBUGS("Avatar") << avString() << "processAvatarAppearance start " << mID + // << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL; if (is_first_appearance_message ) { @@ -7444,7 +8012,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) // Apply visual params if( num_params > 1) { - LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL; + //LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL; BOOL params_changed = FALSE; BOOL interp_params = FALSE; S32 params_changed_count = 0; @@ -7454,12 +8022,12 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) LLVisualParam* param = contents.mParams[i]; F32 newWeight = contents.mParamWeights[i]; - if (is_first_appearance_message || (param->getWeight() != newWeight)) + if (slam_params || is_first_appearance_message || (param->getWeight() != newWeight)) { params_changed = TRUE; params_changed_count++; - if(is_first_appearance_message) + if(is_first_appearance_message || slam_params) { //LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << LL_ENDL; param->setWeight(newWeight); @@ -7544,7 +8112,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } updateMeshTextures(); - //if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end"); } // static @@ -7675,7 +8242,7 @@ void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTextu if (selfp) { - LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << LL_ENDL; + //LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << LL_ENDL; } if (!success && selfp) @@ -7693,14 +8260,14 @@ void LLVOAvatar::onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { - LL_DEBUGS("Avatar") << "onBakedTextureLoaded: " << src_vi->getID() << LL_ENDL; + //LL_DEBUGS("Avatar") << "onBakedTextureLoaded: " << src_vi->getID() << LL_ENDL; LLUUID id = src_vi->getID(); LLUUID *avatar_idp = (LLUUID *)userdata; LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp); if (selfp) { - LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << " id " << src_vi->getID() << LL_ENDL; + //LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << " id " << src_vi->getID() << LL_ENDL; } if (selfp && !success) @@ -7809,6 +8376,40 @@ void dump_sequential_xml(const std::string outprefix, const LLSD& content) LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL; } +void LLVOAvatar::getSortedJointNames(S32 joint_type, std::vector<std::string>& result) const +{ + result.clear(); + if (joint_type==0) + { + avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); + avatar_joint_list_t::const_iterator end = mSkeleton.end(); + for (; iter != end; ++iter) + { + LLJoint* pJoint = (*iter); + result.push_back(pJoint->getName()); + } + } + else if (joint_type==1) + { + for (S32 i = 0; i < mNumCollisionVolumes; i++) + { + LLAvatarJointCollisionVolume* pJoint = &mCollisionVolumes[i]; + result.push_back(pJoint->getName()); + } + } + else if (joint_type==2) + { + for (LLVOAvatar::attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ++iter) + { + LLViewerJointAttachment* pJoint = iter->second; + if (!pJoint) continue; + result.push_back(pJoint->getName()); + } + } + std::sort(result.begin(), result.end()); +} + void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_wearables ) { std::string outprefix(prefix); @@ -7888,28 +8489,90 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara } } - avatar_joint_list_t::iterator iter = mSkeleton.begin(); - avatar_joint_list_t::iterator end = mSkeleton.end(); - for (; iter != end; ++iter) - { - LLJoint* pJoint = (*iter); + // Root joint + const LLVector3& pos = mRoot->getPosition(); + const LLVector3& scale = mRoot->getScale(); + apr_file_printf( file, "\t\t<root name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n", + mRoot->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]); + + // Bones + std::vector<std::string> bone_names, cv_names, attach_names, all_names; + getSortedJointNames(0, bone_names); + getSortedJointNames(1, cv_names); + getSortedJointNames(2, attach_names); + all_names.insert(all_names.end(), bone_names.begin(), bone_names.end()); + all_names.insert(all_names.end(), cv_names.begin(), cv_names.end()); + all_names.insert(all_names.end(), attach_names.begin(), attach_names.end()); + + for (std::vector<std::string>::iterator name_iter = bone_names.begin(); + name_iter != bone_names.end(); ++name_iter) + { + LLJoint *pJoint = getJoint(*name_iter); const LLVector3& pos = pJoint->getPosition(); const LLVector3& scale = pJoint->getScale(); - apr_file_printf( file, "\t\t<joint name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n", + apr_file_printf( file, "\t\t<bone name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n", pJoint->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]); - } + } - for (iter = mSkeleton.begin(); iter != end; ++iter) - { - LLJoint* pJoint = (*iter); + // Collision volumes + for (std::vector<std::string>::iterator name_iter = cv_names.begin(); + name_iter != cv_names.end(); ++name_iter) + { + LLJoint *pJoint = getJoint(*name_iter); + const LLVector3& pos = pJoint->getPosition(); + const LLVector3& scale = pJoint->getScale(); + apr_file_printf( file, "\t\t<collision_volume name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n", + pJoint->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]); + } + + // Attachment joints + for (std::vector<std::string>::iterator name_iter = attach_names.begin(); + name_iter != attach_names.end(); ++name_iter) + { + LLJoint *pJoint = getJoint(*name_iter); + if (!pJoint) continue; + const LLVector3& pos = pJoint->getPosition(); + const LLVector3& scale = pJoint->getScale(); + apr_file_printf( file, "\t\t<attachment_point name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n", + pJoint->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]); + } + + // Joint pos overrides + for (std::vector<std::string>::iterator name_iter = all_names.begin(); + name_iter != all_names.end(); ++name_iter) + { + LLJoint *pJoint = getJoint(*name_iter); LLVector3 pos; LLUUID mesh_id; - if (pJoint->hasAttachmentPosOverride(pos,mesh_id)) + if (pJoint && pJoint->hasAttachmentPosOverride(pos,mesh_id)) { - apr_file_printf( file, "\t\t<joint_offset name=\"%s\" position=\"%f %f %f\" mesh_id=\"%s\"/>\n", - pJoint->getName().c_str(), pos[0], pos[1], pos[2], mesh_id.asString().c_str()); + S32 num_pos_overrides; + std::set<LLVector3> distinct_pos_overrides; + pJoint->getAllAttachmentPosOverrides(num_pos_overrides, distinct_pos_overrides); + apr_file_printf( file, "\t\t<joint_offset name=\"%s\" position=\"%f %f %f\" mesh_id=\"%s\" count=\"%d\" distinct=\"%d\"/>\n", + pJoint->getName().c_str(), pos[0], pos[1], pos[2], mesh_id.asString().c_str(), + num_pos_overrides, (S32) distinct_pos_overrides.size()); + } + } + // Joint scale overrides + for (std::vector<std::string>::iterator name_iter = all_names.begin(); + name_iter != all_names.end(); ++name_iter) + { + LLJoint *pJoint = getJoint(*name_iter); + + LLVector3 scale; + LLUUID mesh_id; + + if (pJoint && pJoint->hasAttachmentScaleOverride(scale,mesh_id)) + { + S32 num_scale_overrides; + std::set<LLVector3> distinct_scale_overrides; + pJoint->getAllAttachmentPosOverrides(num_scale_overrides, distinct_scale_overrides); + apr_file_printf( file, "\t\t<joint_scale name=\"%s\" scale=\"%f %f %f\" mesh_id=\"%s\" count=\"%d\" distinct=\"%d\"/>\n", + pJoint->getName().c_str(), scale[0], scale[1], scale[2], mesh_id.asString().c_str(), + num_scale_overrides, (S32) distinct_scale_overrides.size()); } } F32 pelvis_fixup; @@ -8356,6 +9019,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() { U32 cost = VISUAL_COMPLEXITY_UNKNOWN; LLVOVolume::texture_cost_t textures; + hud_complexity_list_t hud_complexity_list; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { @@ -8432,6 +9096,63 @@ void LLVOAvatar::calculateUpdateRenderComplexity() } } } + if (isSelf() + && attached_object + && attached_object->isHUDAttachment() + && !attached_object->isTempAttachment() + && attached_object->mDrawable) + { + textures.clear(); + + const LLVOVolume* volume = attached_object->mDrawable->getVOVolume(); + if (volume) + { + LLHUDComplexity hud_object_complexity; + hud_object_complexity.objectName = attached_object->getAttachmentItemName(); + hud_object_complexity.objectId = attached_object->getAttachmentItemID(); + std::string joint_name; + gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); + hud_object_complexity.jointName = joint_name; + // get cost and individual textures + hud_object_complexity.objectsCost += volume->getRenderCost(textures); + hud_object_complexity.objectsCount++; + + LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + LLViewerObject* childp = *iter; + const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp); + if (chld_volume) + { + // get cost and individual textures + hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures); + hud_object_complexity.objectsCount++; + } + } + + hud_object_complexity.texturesCount += textures.size(); + + for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); + volume_texture != textures.end(); + ++volume_texture) + { + // add the cost of each individual texture (ignores duplicates) + hud_object_complexity.texturesCost += volume_texture->second; + LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first); + if (tex) + { + // Note: Texture memory might be incorect since texture might be still loading. + hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory(); + if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE) + { + hud_object_complexity.largeTexturesCount++; + } + } + } + hud_complexity_list.push_back(hud_object_complexity); + } + } } } @@ -8448,7 +9169,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() && (all_textures.find(image_id) == all_textures.end())) { // attachment texture not previously seen. - LL_INFOS() << "attachment_texture: " << image_id.asString() << LL_ENDL; + LL_DEBUGS("ARCdetail") << "attachment_texture: " << image_id.asString() << LL_ENDL; all_textures.insert(image_id); } } @@ -8468,7 +9189,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() continue; if (all_textures.find(image_id) == all_textures.end()) { - LL_INFOS() << "local_texture: " << texture_dict->mName << ": " << image_id << LL_ENDL; + LL_DEBUGS("ARCdetail") << "local_texture: " << texture_dict->mName << ": " << image_id << LL_ENDL; all_textures.insert(image_id); } } @@ -8493,11 +9214,15 @@ void LLVOAvatar::calculateUpdateRenderComplexity() static LLCachedControl<U32> show_my_complexity_changes(gSavedSettings, "ShowMyComplexityChanges", 20); - if (isSelf() && show_my_complexity_changes) - { - LLAvatarRenderNotifier::getInstance()->updateNotificationAgent(mVisualComplexity); - } - } + if (isSelf() && show_my_complexity_changes) + { + // Avatar complexity + LLAvatarRenderNotifier::getInstance()->updateNotificationAgent(mVisualComplexity); + + // HUD complexity + LLHUDRenderNotifier::getInstance()->updateNotificationHUD(hud_complexity_list); + } + } } void LLVOAvatar::setVisualMuteSettings(VisualMuteSettings set) diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 418cca519d..bd89d4ef23 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -68,13 +68,11 @@ class LLVoiceVisualizer; class LLHUDNameTag; class LLHUDEffectSpiral; class LLTexGlobalColor; -struct LLVOAvatarBoneInfo; -struct LLVOAvatarChildJoint; -//class LLViewerJoint; + struct LLAppearanceMessageContents; -struct LLVOAvatarSkeletonInfo; class LLViewerJointMesh; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLVOAvatar // @@ -201,11 +199,18 @@ public: void dumpAnimationState(); virtual LLJoint* getJoint(const std::string &name); + LLJoint* getJoint(S32 num); - void addAttachmentPosOverridesForObject(LLViewerObject *vo); - void resetJointPositionsOnDetach(const LLUUID& mesh_id); - void resetJointPositionsOnDetach(LLViewerObject *vo); - void clearAttachmentPosOverrides(); + void addAttachmentOverridesForObject(LLViewerObject *vo); + void resetJointsOnDetach(const LLUUID& mesh_id); + void resetJointsOnDetach(LLViewerObject *vo); + bool jointIsRiggedTo(const std::string& joint_name); + bool jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo); + void clearAttachmentOverrides(); + void rebuildAttachmentOverrides(); + void showAttachmentOverrides(bool verbose = false) const; + void getAttachmentOverrideNames(std::set<std::string>& pos_names, + std::set<std::string>& scale_names) const; /*virtual*/ const LLUUID& getID() const; /*virtual*/ void addDebugText(const std::string& text); @@ -364,10 +369,14 @@ protected: /*virtual*/ LLAvatarJointMesh* createAvatarJointMesh(); // Returns LLViewerJointMesh public: void updateHeadOffset(); + void debugBodySize() const; void postPelvisSetRecalc( void ); /*virtual*/ BOOL loadSkeletonNode(); + void initAttachmentPoints(bool ignore_hud_joints = false); /*virtual*/ void buildCharacter(); + void resetVisualParams(); + void resetSkeleton(bool reset_animations); LLVector3 mCurRootToHeadOffset; LLVector3 mTargetRootToHeadOffset; @@ -404,6 +413,7 @@ public: F32 getLastSkinTime() { return mLastSkinTime; } U32 renderTransparent(BOOL first_pass); void renderCollisionVolumes(); + void renderBones(); void renderJoints(); static void deleteCachedImages(bool clearAll=true); static void destroyGL(); @@ -668,9 +678,12 @@ protected: ** APPEARANCE **/ + LLPointer<LLAppearanceMessageContents> mLastProcessedAppearance; + public: void parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& msg); void processAvatarAppearance(LLMessageSystem* mesgsys); + void applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params); void hideSkirt(); void startAppearanceAnimation(); @@ -964,6 +977,7 @@ private: // General //-------------------------------------------------------------------- public: + void getSortedJointNames(S32 joint_type, std::vector<std::string>& result) const; void dumpArchetypeXML(const std::string& prefix, bool group_by_wearables = false); void dumpAppearanceMsgParams( const std::string& dump_prefix, const LLAppearanceMessageContents& contents); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 5f48898cb1..aa5d82a096 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -65,6 +65,7 @@ #include "llsdutil.h" #include "llstartup.h" #include "llsdserialize.h" +#include "llcallstack.h" #include "llcorehttputil.h" #if LL_MSVC @@ -192,6 +193,7 @@ bool update_avatar_rez_metrics() return true; gAgentAvatarp->updateAvatarRezMetrics(false); + return false; } @@ -219,7 +221,6 @@ void LLVOAvatarSelf::initInstance() { mDebugBakedTextureTimes[i][0] = -1.0f; mDebugBakedTextureTimes[i][1] = -1.0f; - mInitialBakeIDs[i] = LLUUID::null; } status &= buildMenus(); @@ -340,6 +341,7 @@ BOOL LLVOAvatarSelf::buildSkeletonSelf(const LLAvatarSkeletonInfo *info) F32 aspect = LLViewerCamera::getInstance()->getAspect(); LLVector3 scale(1.f, aspect, 1.f); mScreenp->setScale(scale); + // SL-315 mScreenp->setWorldPosition(LLVector3::zero); // need to update screen agressively when sidebar opens/closes, for example mScreenp->mUpdateXform = TRUE; @@ -381,6 +383,10 @@ BOOL LLVOAvatarSelf::buildMenus() params.name(params.label); gAttachBodyPartPieMenus[7] = LLUICtrlFactory::create<LLContextMenu> (params); + params.label(LLTrans::getString("BodyPartsEnhancedSkeleton")); + params.name(params.label); + gAttachBodyPartPieMenus[8] = LLUICtrlFactory::create<LLContextMenu>(params); + gDetachBodyPartPieMenus[0] = NULL; params.label(LLTrans::getString("BodyPartsRightArm")); @@ -409,7 +415,11 @@ BOOL LLVOAvatarSelf::buildMenus() params.name(params.label); gDetachBodyPartPieMenus[7] = LLUICtrlFactory::create<LLContextMenu> (params); - for (S32 i = 0; i < 8; i++) + params.label(LLTrans::getString("BodyPartsEnhancedSkeleton")); + params.name(params.label); + gDetachBodyPartPieMenus[8] = LLUICtrlFactory::create<LLContextMenu>(params); + + for (S32 i = 0; i < 9; i++) { if (gAttachBodyPartPieMenus[i]) { @@ -494,7 +504,7 @@ BOOL LLVOAvatarSelf::buildMenus() ++iter) { LLViewerJointAttachment* attachment = iter->second; - if (attachment && attachment->getGroup() == 8) + if (attachment->getGroup() == 9) { LLMenuItemCallGL::Params item_params; std::string sub_piemenu_name = attachment->getName(); @@ -580,7 +590,7 @@ BOOL LLVOAvatarSelf::buildMenus() } } - for (S32 group = 0; group < 8; group++) + for (S32 group = 0; group < 9; group++) { // skip over groups that don't have sub menus if (!gAttachBodyPartPieMenus[group] || !gDetachBodyPartPieMenus[group]) @@ -690,13 +700,23 @@ void LLVOAvatarSelf::idleUpdate(LLAgent &agent, const F64 &time) // virtual LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) { - if (mScreenp) + LLJoint *jointp = NULL; + jointp = LLVOAvatar::getJoint(name); + if (!jointp && mScreenp) { - LLJoint* jointp = mScreenp->findJoint(name); - if (jointp) return jointp; + jointp = mScreenp->findJoint(name); + if (jointp) + { + mJointMap[name] = jointp; + } } - return LLVOAvatar::getJoint(name); + if (jointp && jointp != mScreenp && jointp != mRoot) + { + llassert(LLVOAvatar::getJoint((S32)jointp->getJointNum())==jointp); + } + return jointp; } + // virtual BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight) { diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index a9c4ab26a9..f9f90bb323 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -103,17 +103,6 @@ private: // helper function. Passed in param is assumed to be in avatar's parameter list. BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight); - - -/** Initialization - ** ** - *******************************************************************************/ - -private: - LLUUID mInitialBakeIDs[6]; - //bool mInitialBakesLoaded; - - /******************************************************************************** ** ** ** STATE diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index e69a8d1d1d..657babd92c 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -54,6 +54,7 @@ #include "llspatialpartition.h" #include "llhudmanager.h" #include "llflexibleobject.h" +#include "llskinningutil.h" #include "llsky.h" #include "lltexturefetch.h" #include "llvector4a.h" @@ -80,7 +81,7 @@ const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; -U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 20; +U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 1; BOOL gAnimateTextures = TRUE; //extern BOOL gHideSelectedObjects; @@ -4180,27 +4181,11 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons } //build matrix palette - static const size_t kMaxJoints = 52; + static const size_t kMaxJoints = LL_MAX_JOINTS_PER_MESH_OBJECT; - LLMatrix4a mp[kMaxJoints]; - LLMatrix4* mat = (LLMatrix4*) mp; - - U32 maxJoints = llmin(skin->mJointNames.size(), kMaxJoints); - for (U32 j = 0; j < maxJoints; ++j) - { - LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); - if (!joint) - { - // Fall back to a point inside the avatar if mesh is - // rigged to an unknown joint. - joint = avatar->getJoint("mPelvis"); - } - if (joint) - { - mat[j] = skin->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } + LLMatrix4a mat[kMaxJoints]; + U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar); for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { @@ -4212,6 +4197,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons if ( weight ) { + LLSkinningUtil::checkSkinWeights(weight, dst_face.mNumVertices, skin); LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); @@ -4221,40 +4207,11 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons { LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED); + U32 max_joints = LLSkinningUtil::getMaxJointCount(); for (U32 j = 0; j < dst_face.mNumVertices; ++j) { LLMatrix4a final_mat; - final_mat.clear(); - - S32 idx[4]; - - LLVector4 wght; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j][k]; - - idx[k] = (S32) floorf(w); - wght[k] = w - floorf(w); - scale += wght[k]; - } - // This is enforced in unpackVolumeFaces() - llassert(scale>0.f); - wght *= 1.f / scale; - - for (U32 k = 0; k < 4; k++) - { - F32 w = wght[k]; - - LLMatrix4a src; - // Insure ref'd bone is in our clamped array of mats - // clamp idx to maxJoints to avoid reading garbage off stack in release - S32 index = llclamp((S32)idx[k],(S32)0,(S32)kMaxJoints-1); - src.setMul(mp[index], w); - final_mat.add(src); - } - + LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints); LLVector4a& v = vol_face.mPositions[j]; LLVector4a t; @@ -4429,7 +4386,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, LL_RECORD_BLOCK_TIME(FTM_REGISTER_FACE); if (type == LLRenderPass::PASS_ALPHA && facep->getTextureEntry()->getMaterialParams().notNull() && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT)) { - LL_WARNS("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL; + LL_WARNS_ONCE("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL; } if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) @@ -4812,13 +4769,23 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) drawablep->clearState(LLDrawable::HAS_ALPHA); bool rigged = vobj->isAttachment() && - vobj->isMesh() && - gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); + vobj->isMesh() && + gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); bool is_rigged = false; + if (rigged && pAvatarVO) + { + pAvatarVO->addAttachmentOverridesForObject(vobj); + if (!LLApp::isExiting() && pAvatarVO->isSelf() && debugLoggingEnabled("AvatarAttachments")) + { + bool verbose = true; + pAvatarVO->showAttachmentOverrides(verbose); + } + } + //for each face for (S32 i = 0; i < drawablep->getNumFaces(); i++) { @@ -4835,8 +4802,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) //sum up face verts and indices drawablep->updateFaceSize(i); - - if (rigged) { if (!facep->isState(LLFace::RIGGED)) @@ -4850,13 +4815,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) //get drawpool of avatar with rigged face LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); - // FIXME should this be inside the face loop? - // doesn't seem to depend on any per-face state. - if ( pAvatarVO ) - { - pAvatarVO->addAttachmentPosOverridesForObject(vobj); - } - if (pool) { const LLTextureEntry* te = facep->getTextureEntry(); diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index b37e41fb85..8026dc3ea8 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -104,10 +104,10 @@ void LLWeb::loadURL(const std::string& url, const std::string& target, const std // static // Explicitly open a Web URL using the Web content floater -void LLWeb::loadURLInternal(const std::string &url, const std::string& target, const std::string& uuid) +void LLWeb::loadURLInternal(const std::string &url, const std::string& target, const std::string& uuid, bool dev_mode) { LLFloaterWebContent::Params p; - p.url(url).target(target).id(uuid); + p.url(url).target(target).id(uuid).dev_mode(dev_mode); LLFloaterReg::showInstance("web_content", p); } diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h index 7c90badbfe..7149ce9baf 100644 --- a/indra/newview/llweb.h +++ b/indra/newview/llweb.h @@ -57,7 +57,7 @@ public: static void loadURL(const std::string& url, const std::string& target = LLStringUtil::null, const std::string& uuid = LLStringUtil::null); // load content using built-in browser - static void loadURLInternal(const std::string &url, const std::string& target = LLStringUtil::null, const std::string& uuid = LLStringUtil::null); + static void loadURLInternal(const std::string &url, const std::string& target = LLStringUtil::null, const std::string& uuid = LLStringUtil::null, bool dev_mode = false); /// Returns escaped url (eg, " " to "%20") - used by all loadURL methods static std::string escapeURL(const std::string& url); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 11d3706821..cee47a591e 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -957,10 +957,10 @@ void LLWorld::updateWaterObjects() center_y = min_y + (wy >> 1); S32 add_boundary[4] = { - 512 - (max_x - region_x), - 512 - (max_y - region_y), - 512 - (region_x - min_x), - 512 - (region_y - min_y) }; + (S32)(512 - (max_x - region_x)), + (S32)(512 - (max_y - region_y)), + (S32)(512 - (region_x - min_x)), + (S32)(512 - (region_y - min_y)) }; S32 dir; for (dir = 0; dir < 8; dir++) diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index 97a9eb7f5f..cc3645131d 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -322,7 +322,7 @@ public: mBoundListener = LLEventPumps::instance(). obtain("mainloop"). - listen(LLEventPump::inventName(), boost::bind(&Poller::poll, this, _1)); + listen(LLEventPump::ANONYMOUS, boost::bind(&Poller::poll, this, _1)); LL_INFOS("LLXMLRPCListener") << mMethod << " request sent to " << mUri << LL_ENDL; } diff --git a/indra/newview/skins/default/textures/icons/Video_URL_Off.png b/indra/newview/skins/default/textures/icons/Video_URL_Off.png Binary files differnew file mode 100644 index 0000000000..40e5df7d81 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Video_URL_Off.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index a9a4913b21..f2da22256c 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -676,7 +676,10 @@ with the same filename but different name <texture name="Unread_Chiclet" file_name="bottomtray/Unread_Chiclet.png" preload="false" /> <texture name="UpArrow_Off" file_name="icons/UpArrow_Off.png" preload="false" /> - <texture name="Vertical Drag Handle" file_name="widgets/vertical_drag_handle.png" scale.left="2" scale.right="7" scale.bottom="8" scale.top="120" scale_type="scale_outer"/> + + <texture name="Video_URL_Off" file_name="icons/Video_URL_Off.png" preload="true" /> + + <texture name="Vertical Drag Handle" file_name="widgets/vertical_drag_handle.png" scale.left="2" scale.right="7" scale.bottom="8" scale.top="120" scale_type="scale_outer"/> <texture name="Volume_Background" file_name="windows/Volume_Background.png" preload="false" scale.left="6" scale.top="33" scale.right="63" scale.bottom="10" /> @@ -774,6 +777,9 @@ with the same filename but different name <texture name="default_land_picture.j2c" /> <texture name="default_profile_picture.j2c" /> <texture name="locked_image.j2c" /> + <texture name="badge_note.j2c" /> + <texture name="badge_warn.j2c" /> + <texture name="badge_ok.j2c" /> <texture name="materials_ui_x_24.png" /> <texture name="Progress_1" file_name="icons/Progress_1.png" preload="true" /> diff --git a/indra/newview/skins/default/xui/de/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/de/floater_preferences_graphics_advanced.xml index 2c141f616f..65a7e255f9 100644 --- a/indra/newview/skins/default/xui/de/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/de/floater_preferences_graphics_advanced.xml @@ -15,7 +15,7 @@ <text name="AvatarText"> Avatar </text> - <slider label="Maximale Komplexität:" name="IndirectMaxComplexity" tool_tip="Bestimmt, an welchem Punkt ein visuell komplexer Avatar als „Gummibärchen“ dargestellt wird"/> + <slider label="Maximale Komplexität:" name="IndirectMaxComplexity" tool_tip="Bestimmt, an welchem Punkt ein visuell komplexer Avatar als JellyDoll dargestellt wird"/> <text name="IndirectMaxComplexityText"> 0 </text> diff --git a/indra/newview/skins/default/xui/de/menu_attachment_other.xml b/indra/newview/skins/default/xui/de/menu_attachment_other.xml index ddb1e7b0b1..ba1b36db06 100644 --- a/indra/newview/skins/default/xui/de/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/de/menu_attachment_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="Anrufen" name="Call"/> <menu_item_call label="In Gruppe einladen" name="Invite..."/> + <menu_item_call label="Skelett zurücksetzen" name="Reset Skeleton"/> <menu_item_call label="Ignorieren" name="Avatar Mute"/> <menu_item_call label="Melden" name="abuse"/> <menu_item_call label="Einfrieren" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/de/menu_attachment_self.xml b/indra/newview/skins/default/xui/de/menu_attachment_self.xml index e0f37b28af..cd24e6ad3f 100644 --- a/indra/newview/skins/default/xui/de/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/de/menu_attachment_self.xml @@ -9,6 +9,7 @@ <menu_item_call label="Mein Outfit bearbeiten" name="Edit Outfit"/> <menu_item_call label="Meine Form bearbeiten" name="Edit My Shape"/> <menu_item_call label="Schwebehöhe" name="Hover Height"/> + <menu_item_call label="Skelett zurücksetzen" name="Reset Skeleton"/> <menu_item_call label="Meine Freunde" name="Friends..."/> <menu_item_call label="Meine Gruppen" name="Groups..."/> <menu_item_call label="Mein Profil" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/de/menu_avatar_other.xml b/indra/newview/skins/default/xui/de/menu_avatar_other.xml index 7242ba1495..447655cde7 100644 --- a/indra/newview/skins/default/xui/de/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/de/menu_avatar_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="Anrufen" name="Call"/> <menu_item_call label="In Gruppe einladen" name="Invite..."/> + <menu_item_call label="Skelett zurücksetzen" name="Reset Skeleton"/> <menu_item_call label="Ignorieren" name="Avatar Mute"/> <menu_item_call label="Melden" name="abuse"/> <menu_item_call label="Einfrieren" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/de/menu_avatar_self.xml b/indra/newview/skins/default/xui/de/menu_avatar_self.xml index b53f8cd6af..f4a3cc17b8 100644 --- a/indra/newview/skins/default/xui/de/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/de/menu_avatar_self.xml @@ -26,6 +26,7 @@ <menu_item_call label="Mein Outfit bearbeiten" name="Edit Outfit"/> <menu_item_call label="Meine Form bearbeiten" name="Edit My Shape"/> <menu_item_call label="Schwebehöhe" name="Hover Height"/> + <menu_item_call label="Skelett zurücksetzen" name="Reset Skeleton"/> <menu_item_call label="Meine Freunde" name="Friends..."/> <menu_item_call label="Meine Gruppen" name="Groups..."/> <menu_item_call label="Mein Profil" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index d83a6071f6..319162db34 100644 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -22,7 +22,6 @@ <menu_item_check label="Nicht stören" name="Do Not Disturb"/> </menu> <menu_item_call label="L$ kaufen..." name="Buy and Sell L$"/> - <menu_item_call label="Händler-Outbox..." name="MerchantOutbox"/> <menu_item_call label="Marktplatz-Auflistungen..." name="MarketplaceListings"/> <menu_item_call label="Kontoübersicht..." name="Manage My Account"> <menu_item_call.on_click name="ManageMyAccount_url" parameter="WebLaunchJoinNow,http://secondlife.com/account/index.php?lang=de"/> @@ -415,6 +414,7 @@ <menu_item_check label="LOD deaktiveren" name="Disable LOD"/> <menu_item_check label="Fehler für sichtbare Agenten beseitigen" name="Debug Character Vis"/> <menu_item_check label="Gelenkpunkte anzeigen" name="Show Collision Skeleton"/> + <menu_item_check label="Knochen anzeigen" name="Show Bones"/> <menu_item_check label="Agent-Ziel anzeigen" name="Display Agent Target"/> <menu_item_call label="Anhänge ausgeben" name="Dump Attachments"/> <menu_item_call label="Fehler in Avatar-Texturen beseitigen" name="Debug Avatar Textures"/> diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 6fcd025a94..0af00ab705 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -487,6 +487,9 @@ Der Outfit-Ordner enthält keine Kleidung, Körperteile oder Anhänge. <notification name="CannotWearInfoNotComplete"> Sie können das Objekt nicht anziehen, weil es noch nicht geladen wurde. Warten Sie kurz und versuchen Sie es dann noch einmal. </notification> + <notification name="MustEnterPasswordToLogIn"> + Bitte geben Sie zur Anmeldung Ihr Kennwort ein. + </notification> <notification name="MustHaveAccountToLogIn"> Sue haben ein Feld leer gelassen. Sie müssen den Benutzernamen Ihres Avatars eingeben. @@ -555,6 +558,9 @@ Hinweis: Der Cache wird dabei gelöscht/geleert. <notification name="ChangeConnectionPort"> Die Port-Einstellungen werden nach einem Neustart von [APP_NAME] wirksam. </notification> + <notification name="ChangeDeferredDebugSetting"> + Die Debug-Einstellung tritt nach Neustart von [APP_NAME] in Kraft. + </notification> <notification name="ChangeSkin"> Die neue Benutzeroberfläche wird nach einem Neustart von [APP_NAME] angezeigt. </notification> @@ -1380,12 +1386,13 @@ Sie können [SECOND_LIFE] normal verwenden. Andere Benutzer können Sie korrekt <ignore name="ignore" text="Das Herunterladen der Kleidung dauert lange"/> </form> </notification> - <notification name="RegionAndAgentComplexity"> - Ihre [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 visuelle Komplexität] ist [AGENT_COMPLEXITY]. + <notification name="AgentComplexityWithVisibility"> + Ihre [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 Avatarkomplexität] ist [AGENT_COMPLEXITY]. [OVERLIMIT_MSG] + <usetemplate ignoretext="Warnen, falls Avatarkomplexität zu hoch ist" name="notifyignore"/> </notification> <notification name="AgentComplexity"> - Ihre [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 visuelle Komplexität] ist [AGENT_COMPLEXITY]. + Ihre [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 Avatarkomplexität] ist [AGENT_COMPLEXITY]. </notification> <notification name="FirstRun"> Installation von [APP_NAME] vollständig abgeschlossen. @@ -1501,6 +1508,10 @@ Ersetzen Sie die Textur [TEXTURE_NUM] mit einer Bilddatei von maximal 512x512 un Möchten Sie das aktuelle Terrain formen, es zum Mittelpunkt der oberen und unteren Terraingrenzen und zum Standard des „Zurücksetzen“-Tools machen? <usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="OK"/> </notification> + <notification name="ConfirmTextureHeights"> + Sie sind dabei, für Höhenbereiche untere Werte anzugeben, die größer sind als die oberen Werte. Fortfahren? + <usetemplate canceltext="Nicht fragen" name="yesnocancelbuttons" notext="Abbrechen" yestext="OK"/> + </notification> <notification name="MaxAllowedAgentOnRegion"> Es sind maximal [MAX_AGENTS] zulässige Einwohner erlaubt. </notification> @@ -1735,14 +1746,6 @@ Diese Gruppe verlassen? Sie können die Gruppe nicht verlassen, da Sie der letzte Besitzer der Gruppe sind. Weisen Sie die Besitzerrolle zuerst einem anderen Mitglied zu. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="GroupDepartError"> - Kann Gruppe nicht verlassen: [reason]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> - <notification name="GroupDepart"> - Sie haben die Gruppe „[group_name]“ verlassen. - <usetemplate name="okbutton" yestext="OK"/> - </notification> <notification name="ConfirmKick"> Möchten Sie WIRKLICH alle Benutzer aus dem Grid werfen? <usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="Alle Benutzer hinauswerfen"/> @@ -2415,6 +2418,10 @@ Möchten Sie den Nicht-stören-Modus deaktivieren, bevor Sie diese Transaktion a Sind Sie sicher, dass Sie den Inhalt Ihres Papierkorbs löschen möchten? <usetemplate ignoretext="Bestätigen, bevor der Ordner Papierkorb im Inventar geleert wird" name="okcancelignore" notext="Abbrechen" yestext="OK"/> </notification> + <notification name="TrashIsFull"> + Ihr Papierkorb läuft über. Dies kann zu Anmeldeproblemen führen. + <usetemplate name="okcancelbuttons" notext="Papierkorb später leeren" yestext="Papierkorb jetzt leeren"/> + </notification> <notification name="ConfirmClearBrowserCache"> Sind Sie sicher, dass Sie Ihren Reise-, Internet- und Suchverlauf löschen möchten? <usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="OK"/> @@ -3272,11 +3279,15 @@ Diese werden für ein paar Sekunden sicherheitshalber gesperrt. <notification name="AttachmentSaved"> Der Anhang wurde gespeichert. </notification> - <notification name="PresetNotSaved"> - Fehler beim Speichern der Voreinstellung [NAME]. + <notification name="AppearanceToXMLSaved"> + Erscheinungsbild als XML in [PATH] gespeichert </notification> - <notification name="PresetNotDeleted"> - Fehler beim Löschen der Voreinstellung [NAME]. + <notification name="AppearanceToXMLFailed"> + Fehler beim Speichern des Erscheinungsbilds als XML. + icon="notifytip.tga" + name="PresetNotDeleted" + type="notifytip"> +Fehler beim Löschen der Voreinstellung [NAME]. </notification> <notification name="UnableToFindHelpTopic"> Hilfethema für dieses Element wurde nicht gefunden. @@ -4089,6 +4100,9 @@ Warten Sie kurz und versuchen Sie es noch einmal. <notification name="CantAttachNotEnoughScriptResources"> Nicht genügend Skriptressourcen verfügbar, um Objekt anzuhängen. </notification> + <notification name="IllegalAttachment"> + Der Anhang hat einen nicht vorhandenen Punkt auf dem Avatar angefordert. Der Anhang wurde stattdessen auf der Brust angebracht. + </notification> <notification name="CantDropItemTrialUser"> Ablegen von Objekten hier nicht möglich; versuchen Sie es mit dem kostenlosen Testbereich. </notification> diff --git a/indra/newview/skins/default/xui/de/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/de/panel_preferences_alerts.xml index fcb45e26be..508e87a8b7 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_alerts.xml @@ -3,8 +3,9 @@ <text name="tell_me_label"> Anzeigen: </text> - <check_box label="Wenn ich L$ ausgebe oder erhalte" name="notify_money_change_checkbox"/> + <check_box label="Wenn ich L$ ausgebe" name="notify_money_spend_checkbox"/> <check_box label="Wenn meine Freunde sich an- oder abmelden" name="friends_online_notify_checkbox"/> + <check_box label="Wenn ich L$ erhalte" name="notify_money_received_checkbox"/> <text name="show_label"> Immer anzeigen: </text> diff --git a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml index 06fd22141f..74fb4d0f85 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml @@ -24,10 +24,15 @@ <text name="BetterText"> Besser </text> + <slider label="Maximale Avatarkomplexität:" name="IndirectMaxComplexity" tool_tip="Bestimmt, an welchem Punkt ein visuell komplexer Avatar als JellyDoll dargestellt wird"/> + <text name="IndirectMaxComplexityText"> + 0 + </text> <check_box initial_value="true" label="Atmosphären-Shader" name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="Erweitertes Beleuchtungsmodell" name="UseLightShaders"/> <button label="Einstellungen als Voreinstellung speichern..." name="PrefSaveButton"/> <button label="Voreinstellung laden..." name="PrefLoadButton"/> + min_val="0.125" <button label="Voreinstellung löschen..." name="PrefDeleteButton"/> <button label="Auf empfohlene Einstellungen zurücksetzen" name="Defaults"/> <button label="Erweiterte Einstellungen..." name="AdvancedSettings"/> diff --git a/indra/newview/skins/default/xui/de/panel_sound_devices.xml b/indra/newview/skins/default/xui/de/panel_sound_devices.xml index b739b6197f..df4b30383e 100644 --- a/indra/newview/skins/default/xui/de/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/de/panel_sound_devices.xml @@ -16,9 +16,9 @@ Ausgabe </text> <text name="My volume label"> - Meine Lautstärke: + Mikrofonlautstärke: </text> - <slider_bar initial_value="1,0" name="mic_volume_slider" tool_tip="Lautstärke mit diesem Regler ändern"/> + <slider_bar initial_value="1,0" name="mic_volume_slider" tool_tip="Mit diesem Schieberegler können Sie den Mikrofonpegel ändern"/> <text name="wait_text"> Bitte warten </text> diff --git a/indra/newview/skins/default/xui/de/panel_status_bar.xml b/indra/newview/skins/default/xui/de/panel_status_bar.xml index d3d85de3c3..b0cb1e0592 100644 --- a/indra/newview/skins/default/xui/de/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/de/panel_status_bar.xml @@ -5,7 +5,7 @@ <panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string> <panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string> <panel.string name="buycurrencylabel">[AMT] L$</panel.string> - <panel left="-415" name="balance_bg" width="205"> + <panel left="-436" name="balance_bg" width="205"> <text name="balance" tool_tip="Klicken, um L$-Guthaben zu aktualisieren" value="L$ ??"/> <button label="L$ kaufen" name="buyL" tool_tip="Hier klicken, um mehr L$ zu kaufen"/> <button label="Einkaufen" name="goShop" tool_tip="Second Life-Marktplatz öffnen" width="85"/> diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 810022525a..9dd94d2230 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -41,6 +41,9 @@ [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL]) [[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]) SLURL: <nolink>[SLURL]</nolink> @@ -72,6 +75,9 @@ Voice-Server-Version: [VOICE_VERSION] <string name="ErrorFetchingServerReleaseNotesURL"> Fehler beim Abrufen der URL für die Server-Versionshinweise. </string> + <string name="BuildConfiguration"> + Build-Konfiguration + </string> <string name="ProgressRestoring"> Wird wiederhergestellt... </string> @@ -1390,6 +1396,9 @@ Warten Sie kurz und versuchen Sie dann noch einmal, sich anzumelden. <string name="BodyPartsRightLeg"> Rechtes Bein </string> + <string name="BodyPartsEnhancedSkeleton"> + Erweitertes Skelett + </string> <string name="GraphicsQualityLow"> Niedrig </string> @@ -1838,6 +1847,51 @@ Warten Sie kurz und versuchen Sie dann noch einmal, sich anzumelden. <string name="Avatar Center"> Avatar-Mitte </string> + <string name="Left Ring Finger"> + Linker Ringfinger + </string> + <string name="Right Ring Finger"> + Rechter Ringfinger + </string> + <string name="Tail Base"> + Schwanzansatz + </string> + <string name="Tail Tip"> + Schwanzspitze + </string> + <string name="Left Wing"> + Linker Flügel + </string> + <string name="Right Wing"> + Rechter Flügel + </string> + <string name="Jaw"> + Kiefer + </string> + <string name="Alt Left Ear"> + Alt. linkes Ohr + </string> + <string name="Alt Right Ear"> + Alt. rechtes Ohr + </string> + <string name="Alt Left Eye"> + Alt. linkes Auge + </string> + <string name="Alt Right Eye"> + Alt. rechtes Auge + </string> + <string name="Tongue"> + Zunge + </string> + <string name="Groin"> + Leiste + </string> + <string name="Left Hind Foot"> + Linker hinterer Fuß + </string> + <string name="Right Hind Foot"> + Rechter hinterer Fuß + </string> <string name="Invalid Attachment"> Ungültige Stelle für Anhang </string> @@ -2227,12 +2281,12 @@ Warten Sie kurz und versuchen Sie dann noch einmal, sich anzumelden. <string name="ATTACH_BELLY"> Bauch </string> - <string name="ATTACH_RPEC"> - Rechts - </string> - <string name="ATTACH_LPEC"> + <string name="ATTACH_LEFT_PEC"> Linke Brust </string> + <string name="ATTACH_RIGHT_PEC"> + Rechte Brust + </string> <string name="ATTACH_HUD_CENTER_2"> HUD Mitte 2 </string> @@ -2263,6 +2317,51 @@ Warten Sie kurz und versuchen Sie dann noch einmal, sich anzumelden. <string name="ATTACH_AVATAR_CENTER"> Avatar-Mitte </string> + <string name="ATTACH_LHAND_RING1"> + Linker Ringfinger + </string> + <string name="ATTACH_RHAND_RING1"> + Rechter Ringfinger + </string> + <string name="ATTACH_TAIL_BASE"> + Schwanzansatz + </string> + <string name="ATTACH_TAIL_TIP"> + Schwanzspitze + </string> + <string name="ATTACH_LWING"> + Linker Flügel + </string> + <string name="ATTACH_RWING"> + Rechter Flügel + </string> + <string name="ATTACH_FACE_JAW"> + Kiefer + </string> + <string name="ATTACH_FACE_LEAR"> + Alt. linkes Ohr + </string> + <string name="ATTACH_FACE_REAR"> + Alt. rechtes Ohr + </string> + <string name="ATTACH_FACE_LEYE"> + Alt. linkes Auge + </string> + <string name="ATTACH_FACE_REYE"> + Alt. rechtes Auge + </string> + <string name="ATTACH_FACE_TONGUE"> + Zunge + </string> + <string name="ATTACH_GROIN"> + Leiste + </string> + <string name="ATTACH_HIND_LFOOT"> + Linker hinterer Fuß + </string> + <string name="ATTACH_HIND_RFOOT"> + Rechter hinterer Fuß + </string> <string name="CursorPos"> Zeile [LINE], Spalte [COLUMN] </string> @@ -4252,6 +4351,12 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_ <string name="OfflineStatus"> Offline </string> + <string name="not_online_msg"> + Benutzer nicht online – Nachricht wird gespeichert und später zugestellt. + </string> + <string name="not_online_inventory"> + Benutzer nicht online – Inventar gespeichert. + </string> <string name="answered_call"> Ihr Anruf wurde entgegengenommen </string> diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index d2c8dddfe1..2750316f2e 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1217,6 +1217,13 @@ label_text.text_color="White" name="upload_joints" top_pad="15"/> + <check_box + follows="top|left" + height="15" + label="Lock scale if joint position defined" + label_text.text_color="White" + name="lock_scale_if_joint_position" + top_pad="15"/> <text follows="top|left" height="15" diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml index 638a4e2da8..9a9101e0da 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences.xml @@ -3,7 +3,7 @@ legacy_header_height="18" positioning="centered" default_tab_group="1" - height="460" + height="512" layout="topleft" name="Preferences" help_topic="preferences" @@ -19,7 +19,7 @@ layout="topleft" right="-105" name="OK" - top="433" + top="473" width="90"> <button.commit_callback function="Pref.OK" /> @@ -40,7 +40,7 @@ <tab_container follows="all" halign="left" - height="410" + height="440" layout="topleft" left="0" name="pref core" diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index 2bd3aa8bcc..c6b91a8b2f 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -117,7 +117,7 @@ <slider control_name="IndirectMaxComplexity" - tool_tip="Controls at what point a visually complex avatar is drawn as a jelly doll" + tool_tip="Controls at what point a visually complex avatar is drawn as a JellyDoll" follows="left|top" height="16" initial_value="101" diff --git a/indra/newview/skins/default/xui/en/floater_report_abuse.xml b/indra/newview/skins/default/xui/en/floater_report_abuse.xml index af62c7a9bc..225266af86 100644 --- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml +++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml @@ -21,14 +21,6 @@ name="screenshot" top="15" width="220" /> - <check_box - height="15" - label="Use this screenshot" - layout="topleft" - left="8" - name="screen_check" - top_pad="-12" - width="116" /> <text type="string" length="1" @@ -39,7 +31,7 @@ layout="topleft" left="10" name="reporter_title" - top_pad="0" + top_pad="-2" width="100"> Reporter: </text> diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml index a80440e844..4473ce0cda 100644 --- a/indra/newview/skins/default/xui/en/floater_web_content.xml +++ b/indra/newview/skins/default/xui/en/floater_web_content.xml @@ -154,6 +154,136 @@ </button> </layout_panel> <layout_panel + height="22" + layout="topleft" + left_delta="0" + name="debug_controls" + top_delta="0" + auto_resize="false" + width="585"> + <button + image_overlay="Home_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + chrome="true" + tool_tip="Web tests home page" + enabled="true" + follows="left|top" + height="22" + layout="topleft" + left="1" + name="web_test_home_page" + top="0" + width="22"> + <button.commit_callback + function="WebContent.TestURL" + parameter="https://callum-linden.s3.amazonaws.com/ceftests.html"/> + </button> + + <button + image_overlay="Video_URL_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + chrome="true" + tool_tip="MPEG4 Video Test" + enabled="true" + follows="left|top" + height="22" + layout="topleft" + left="27" + name="VLC Plugin Test" + top="0" + width="22"> + <button.commit_callback + function="WebContent.TestURL" + parameter="https://callum-linden.s3.amazonaws.com/sample_media/ss.mp4"/> + </button> + <button + image_overlay="Video_URL_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + chrome="true" + tool_tip="MKV Video Test" + enabled="true" + follows="left|top" + height="22" + layout="topleft" + left="51" + name="VLC Plugin Test" + top="0" + width="22"> + <button.commit_callback + function="WebContent.TestURL" + parameter="https://callum-linden.s3.amazonaws.com/sample_media/jellyfish.mkv"/> + </button> + <button + image_overlay="Video_URL_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + chrome="true" + tool_tip="WebM Video Test" + enabled="true" + follows="left|top" + height="22" + layout="topleft" + left="75" + name="VLC Plugin Test" + top="0" + width="22"> + <button.commit_callback + function="WebContent.TestURL" + parameter="https://callum-linden.s3.amazonaws.com/sample_media/jumprope.webm"/> + </button> + <button + image_overlay="Video_URL_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + chrome="true" + tool_tip="MP3 audio Test" + enabled="true" + follows="left|top" + height="22" + layout="topleft" + left="99" + name="VLC Plugin Test" + top="0" + width="22"> + <button.commit_callback + function="WebContent.TestURL" + parameter="https://callum-linden.s3.amazonaws.com/alegria.mp3"/> + </button> + <button + image_overlay="Video_URL_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + chrome="true" + tool_tip="FLV Test" + enabled="true" + follows="left|top" + height="22" + layout="topleft" + left="123" + name="VLC Plugin Test" + top="0" + width="22"> + <button.commit_callback + function="WebContent.TestURL" + parameter="https://callum-linden.s3.amazonaws.com/sample_media/vandal.flv"/> + </button> + </layout_panel> + <layout_panel height="40" layout="topleft" left_delta="0" diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml index 5d05ecf127..550af03683 100644 --- a/indra/newview/skins/default/xui/en/fonts.xml +++ b/indra/newview/skins/default/xui/en/fonts.xml @@ -10,6 +10,7 @@ <file>ArialUni.ttf</file> </os> <os name="Mac"> + <file>ヒラギノ角ゴシック W3.ttc</file> <file>ヒラギノ角ゴ Pro W3.otf</file> <file>ヒラギノ角ゴ ProN W3.otf</file> <file>ヒラギノ明朝 ProN W3.ttc</file> diff --git a/indra/newview/skins/default/xui/en/inspect_group.xml b/indra/newview/skins/default/xui/en/inspect_group.xml index 324ff3eabd..a69585074c 100644 --- a/indra/newview/skins/default/xui/en/inspect_group.xml +++ b/indra/newview/skins/default/xui/en/inspect_group.xml @@ -66,7 +66,7 @@ Fear the moose! Fear it! And the mongoose too! width="220"> L$123 to join </text> - <icon + <group_icon follows="all" height="38" right="-10" diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml index 9e520b2d31..2f60bab0b7 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml @@ -40,6 +40,22 @@ function="Avatar.InviteToGroup" /> </menu_item_call> <menu_item_separator /> + + <menu_item_call label="Reset Skeleton" + layout="topleft" + name="Reset Skeleton"> + <menu_item_call.on_click + function="Avatar.ResetSkeleton" /> + </menu_item_call> + + <menu_item_call label="Reset Skeleton And Animations" + layout="topleft" + name="Reset Skeleton And Animations"> + <menu_item_call.on_click + function="Avatar.ResetSkeletonAndAnimations" /> + </menu_item_call> + + <menu_item_separator /> <menu_item_call enabled="false" label="Block" diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml index c6ae844d67..59faf6a9f5 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml @@ -99,6 +99,19 @@ name="Edit Outfit"> <menu_item_call.on_enable function="Edit.EnableHoverHeight" /> </menu_item_call> + <menu_item_call label="Reset Skeleton" + layout="topleft" + name="Reset Skeleton"> + <menu_item_call.on_click + function="Avatar.ResetSkeleton" /> + </menu_item_call> + <menu_item_call label="Reset Skeleton And Animations" + layout="topleft" + name="Reset Skeleton And Animations"> + <menu_item_call.on_click + function="Avatar.ResetSkeletonAndAnimations" /> + </menu_item_call> + <menu_item_call label="My Friends" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml index fadacbf3cb..ddfff23410 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml @@ -41,6 +41,22 @@ </menu_item_call> <menu_item_separator /> + + <menu_item_call label="Reset Skeleton" + layout="topleft" + name="Reset Skeleton"> + <menu_item_call.on_click + function="Avatar.ResetSkeleton" /> + </menu_item_call> + + <menu_item_call label="Reset Skeleton And Animations" + layout="topleft" + name="Reset Skeleton And Animations"> + <menu_item_call.on_click + function="Avatar.ResetSkeletonAndAnimations" /> + </menu_item_call> + + <menu_item_separator /> <menu_item_call enabled="false" diff --git a/indra/newview/skins/default/xui/en/menu_avatar_self.xml b/indra/newview/skins/default/xui/en/menu_avatar_self.xml index d3b0b07f70..9e181d0b6d 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_self.xml @@ -237,6 +237,18 @@ <menu_item_call.on_enable function="Edit.EnableHoverHeight" /> </menu_item_call> + <menu_item_call label="Reset Skeleton" + layout="topleft" + name="Reset Skeleton"> + <menu_item_call.on_click + function="Avatar.ResetSkeleton" /> + </menu_item_call> + <menu_item_call label="Reset Skeleton And Animations" + layout="topleft" + name="Reset Skeleton And Animations"> + <menu_item_call.on_click + function="Avatar.ResetSkeletonAndAnimations" /> + </menu_item_call> <menu_item_call label="My Friends" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index dcf2da52f1..a39ee5fddd 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -225,11 +225,11 @@ parameter="message_critical" /> </menu_item_call> <menu_item_call - label="Web Content Floater Debug Test" - name="Web Content Floater Debug Test"> + label="Media Browser" + name="Media Browser"> <menu_item_call.on_click function="Advanced.WebContentTest" - parameter="https://callum-linden.s3.amazonaws.com/ceftests.html"/> + parameter="http://google.com"/> </menu_item_call> <menu create_jump_keys="true" diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index b189d1038f..ea826d2243 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3141,30 +3141,13 @@ label="UI" name="UI" tear_off="true"> - <!-- <menu_item_check - label="New Bottom Bar" - name="New Bottom Bar"> - <menu_item_check.on_check - function="CheckControl" - parameter="BottomPanelNew" /> - <menu_item_check.on_click - function="ToggleControl" - parameter="BottomPanelNew" /> - </menu_item_check>--> - <menu_item_call - label="Media Browser Test" - name="Web Browser Test"> - <menu_item_call.on_click - function="Advanced.WebBrowserTest" - parameter="http://secondlife.com/app/search/slurls.html"/> - </menu_item_call> <menu_item_call - label="Web Content Browser" - name="Web Content Browser" - shortcut="control|shift|Z"> + label="Media Browser" + name="Media Browser" + shortcut="control|alt|shift|Z"> <menu_item_call.on_click function="Advanced.WebContentTest" - parameter="https://callum-linden.s3.amazonaws.com/ceftests.html"/> + parameter="http://google.com"/> </menu_item_call> <menu_item_call label="FB Connect Test" @@ -3528,6 +3511,16 @@ parameter="collision skeleton" /> </menu_item_check> <menu_item_check + label="Show Bones" + name="Show Bones"> + <menu_item_check.on_check + function="Advanced.CheckInfoDisplay" + parameter="joints" /> + <menu_item_check.on_click + function="Advanced.ToggleInfoDisplay" + parameter="joints" /> + </menu_item_check> + <menu_item_check label="Display Agent Target" name="Display Agent Target"> <menu_item_check.on_check diff --git a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml index 44b2727671..75c1de24aa 100644 --- a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml @@ -28,6 +28,13 @@ function="Wearing.Edit" /> </menu_item_call> <menu_item_call + label="Edit" + layout="topleft" + name="edit_item"> + <on_click + function="Wearing.EditItem" /> + </menu_item_call> + <menu_item_call label="Show Original" layout="topleft" name="show_original"> diff --git a/indra/newview/skins/default/xui/en/mime_types.xml b/indra/newview/skins/default/xui/en/mime_types.xml index 7cb4a6e53b..8d8d546b24 100644 --- a/indra/newview/skins/default/xui/en/mime_types.xml +++ b/indra/newview/skins/default/xui/en/mime_types.xml @@ -130,10 +130,21 @@ movie </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </scheme> - <mimetype name="blank"> + <scheme name="libvlc"> + <label name="libvlc_label"> + LibVLC supported media + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_libvlc + </impl> + </scheme> + <mimetype name="blank"> <label name="blank_label"> - None - </label> @@ -163,7 +174,7 @@ audio </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> <mimetype name="video/*"> @@ -174,7 +185,7 @@ movie </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> <mimetype name="image/*"> @@ -196,7 +207,7 @@ movie </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> <mimetype name="application/javascript"> @@ -218,7 +229,7 @@ audio </widgettype> <impl> - media_plugin_quicktime + media_plugin_cef </impl> </mimetype> <mimetype name="application/pdf"> @@ -295,7 +306,7 @@ audio </widgettype> <impl> - media_plugin_quicktime + media_plugin_cef </impl> </mimetype> <mimetype name="audio/mpeg"> @@ -306,7 +317,7 @@ audio </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> <mimetype name="audio/x-aiff"> @@ -317,7 +328,7 @@ audio </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> <mimetype name="audio/x-wav"> @@ -328,7 +339,7 @@ audio </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> <mimetype menu="1" name="image/bmp"> @@ -438,7 +449,7 @@ movie </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> <mimetype name="video/mp4"> @@ -449,10 +460,21 @@ movie </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> - <mimetype menu="1" name="video/quicktime"> + <mimetype name="application/octet-stream"> + <label name="video/octet-stream"> + Movie + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_libvlc + </impl> + </mimetype> + <mimetype menu="1" name="video/quicktime"> <label name="video/quicktime_label"> Movie (QuickTime) </label> @@ -460,7 +482,7 @@ movie </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> <mimetype name="video/x-ms-asf"> @@ -471,7 +493,7 @@ movie </widgettype> <impl> - media_plugin_quicktime + media_plugin_libvlc </impl> </mimetype> <mimetype name="video/x-ms-wmv"> @@ -482,7 +504,7 @@ movie </widgettype> <impl> - media_plugin_quicktime + media_plugin_cef </impl> </mimetype> <mimetype menu="1" name="video/x-msvideo"> @@ -493,7 +515,7 @@ movie </widgettype> <impl> - media_plugin_quicktime + media_plugin_cef </impl> </mimetype> </mimetypes> diff --git a/indra/newview/skins/default/xui/en/mime_types_linux.xml b/indra/newview/skins/default/xui/en/mime_types_linux.xml index 84aeaf3b54..7188b1e699 100644 --- a/indra/newview/skins/default/xui/en/mime_types_linux.xml +++ b/indra/newview/skins/default/xui/en/mime_types_linux.xml @@ -130,7 +130,7 @@ movie </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </scheme> <mimetype name="blank"> @@ -163,7 +163,7 @@ audio </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="video/*"> @@ -174,7 +174,7 @@ movie </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="image/*"> @@ -196,7 +196,7 @@ movie </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="application/javascript"> @@ -218,7 +218,7 @@ audio </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="application/pdf"> @@ -295,7 +295,7 @@ audio </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="audio/mpeg"> @@ -306,7 +306,7 @@ audio </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="audio/x-aiff"> @@ -317,7 +317,7 @@ audio </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="audio/x-wav"> @@ -328,7 +328,7 @@ audio </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype menu="1" name="image/bmp"> @@ -438,7 +438,7 @@ movie </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="video/mp4"> @@ -449,7 +449,7 @@ movie </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype menu="1" name="video/quicktime"> @@ -460,7 +460,7 @@ movie </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="video/x-ms-asf"> @@ -471,7 +471,7 @@ movie </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype name="video/x-ms-wmv"> @@ -482,7 +482,7 @@ movie </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> <mimetype menu="1" name="video/x-msvideo"> @@ -493,7 +493,7 @@ movie </widgettype> <impl> - media_plugin_gstreamer + media_plugin_libvlc </impl> </mimetype> </mimetypes> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index b2425649a4..11e019e153 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -832,6 +832,13 @@ If you no longer wish to have these abilities granted to this role, disable them </notification> <notification + icon="notify.tga" + name="GroupBanUserOnBanlist" + type="notify"> +Some residents have not been sent an invite due to being banned from the group. + </notification> + + <notification icon="alertmodal.tga" name="AttachmentDrop" type="alertmodal"> @@ -1432,6 +1439,13 @@ Port settings take effect after you restart [APP_NAME]. <notification icon="alertmodal.tga" + name="ChangeDeferredDebugSetting" + type="alertmodal"> +This debug setting change will take effect after you restart [APP_NAME]. + </notification> + + <notification + icon="alertmodal.tga" name="ChangeSkin" type="alertmodal"> The new skin will appear after you restart [APP_NAME]. @@ -1476,6 +1490,7 @@ Save Changes? icon="alertmodal.tga" name="DeleteNotecard" type="alertmodal"> + <unique/> Delete Notecard? <tag>confirm</tag> <usetemplate @@ -1631,52 +1646,14 @@ Visit [_URL] for more information? <notification icon="alertmodal.tga" - name="IntelOldDriver" + name="OldGPUDriver" type="alertmodal"> There is likely a newer driver for your graphics chip. Updating graphics drivers can substantially improve performance. - Visit [_URL] to check for driver updates? - <tag>confirm</tag> - <url option="0" name="url"> - http://www.intel.com/p/en_US/support/detect/graphics - </url> - <usetemplate - ignoretext="My graphics driver is out of date" - name="okcancelignore" - notext="No" - yestext="Yes"/> - <tag>fail</tag> - </notification> - - <notification - icon="alertmodal.tga" - name="AMDOldDriver" - type="alertmodal"> - There is likely a newer driver for your graphics chip. Updating graphics drivers can substantially improve performance. - - Visit [_URL] to check for driver updates? - <tag>confirm</tag> - <url option="0" name="url"> - http://support.amd.com/us/Pages/AMDSupportHub.aspx - </url> - <usetemplate - ignoretext="My graphics driver is out of date" - name="okcancelignore" - notext="No" - yestext="Yes"/> - <tag>fail</tag> - </notification> - - <notification - icon="alertmodal.tga" - name="NVIDIAOldDriver" - type="alertmodal"> - There is likely a newer driver for your graphics chip. Updating graphics drivers can substantially improve performance. - - Visit [_URL] to check for driver updates? + Visit [URL] to check for driver updates? <tag>confirm</tag> <url option="0" name="url"> - http://www.nvidia.com/Download/index.aspx?lang=en-us + [URL] </url> <usetemplate ignoretext="My graphics driver is out of date" @@ -1686,7 +1663,6 @@ Visit [_URL] for more information? <tag>fail</tag> </notification> - <notification icon="alertmodal.tga" name="UnknownGPU" @@ -3349,6 +3325,23 @@ Your [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Renderin <context>AgentComplexityNotice</context> </unique> Your [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 avatar complexity] is [AGENT_COMPLEXITY]. + <usetemplate + ignoretext="Warn me about my avatar complexity changes" + name="notifyignore"/> + </notification> + + <notification + icon = "notifytip.tga" + name = "HUDComplexityWarning" + type = "notifytip" + log_to_chat = "false"> + <unique combine = "cancel_old"> + <context>HUDComplexityWarning</context> + </unique> + [HUD_REASON], it is likely to negatively affect your performance. + <usetemplate + ignoretext="Warn me when my HUD complexity is too high" + name="notifyignore"/> </notification> <notification @@ -3665,6 +3658,13 @@ Can't add estate owner to estate 'Banned Resident' list. <notification icon="alertmodal.tga" + name="ProblemAddingEstateManagerBanned" + type="alertmodal"> +Unable to add banned resident to estate manager list. + </notification> + + <notification + icon="alertmodal.tga" name="CanNotChangeAppearanceUntilLoaded" type="alertmodal"> Can't change appearance until clothing and shape are loaded. @@ -4059,6 +4059,18 @@ Do you want to open your Web browser to view this content? <notification icon="alertmodal.tga" + name="SystemUIScaleFactorChanged" + type="alertmodal"> +System UI size factor has changed since last run. Do you want to open UI size adjustment settings page? + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="WebLaunchJoinNow" type="alertmodal"> Go to your [http://secondlife.com/account/ Dashboard] to manage your account? @@ -4178,6 +4190,14 @@ Leave Group? </notification> <notification + icon="notify.tga" + name="GroupDepart" + type="notify"> +You have left the group '[group_name]'. + <tag>group</tag> + </notification> + + <notification icon="alertmodal.tga" name="OwnerCannotLeaveGroup" type="alertmodal"> @@ -4189,6 +4209,17 @@ Leave Group? </notification> <notification + icon="alertmodal.tga" + name="GroupDepartError" + type="alertmodal"> + Unable to leave group. + <tag>group</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification icon="alert.tga" name="ConfirmKick" type="alert"> @@ -5310,6 +5341,17 @@ There are too many prims selected. Please select [MAX_PRIM_COUNT] or fewer prim </notification> <notification + icon="alertmodal.tga" + name="TooManyScriptsSelected" + type="alertmodal"> +Too many scripts in the objects selected. Please select fewer objects and try again + <tag>fail</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification icon="alertmodal.tga" name="ProblemImportingEstateCovenant" type="alertmodal"> @@ -5728,6 +5770,17 @@ Warning: The 'Pay object' click action has been set, but it will only <notification icon="alertmodal.tga" + name="PaymentBlockedButtonMismatch" + type="alertmodal"> + Payment stopped: the price paid does not match any of the pay buttons set for this object. + <tag>fail</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="OpenObjectCannotCopy" type="alertmodal"> There are no items in this object that you are allowed to copy. @@ -5830,7 +5883,20 @@ You cannot undo this action. notext="Cancel" yestext="Unlink"/> </notification> - + + <notification + icon="alertmodal.tga" + name="HelpReportAbuseConfirm" + type="alertmodal"> + <unique/> +Thank you for taking the time to inform us of this issue. +We will review your report for possible violations and take +the appropriate action. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + <notification icon="alertmodal.tga" name="HelpReportAbuseSelectCategory" @@ -7339,7 +7405,8 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th name="TeleportOffered_MaturityExceeded" log_to_im="true" log_to_chat="false" - type="offer"> + type="offer" + sound="UISndNewIncomingIMSession"> [NAME_SLURL] has offered to teleport you to their location: “[MESSAGE]” @@ -7364,7 +7431,8 @@ This region contains [REGION_CONTENT_MATURITY] content, but your current prefere name="TeleportOffered_MaturityBlocked" log_to_im="true" log_to_chat="false" - type="notifytip"> + type="notifytip" + sound="UISndNewIncomingIMSession"> [NAME_SLURL] has offered to teleport you to their location: “[MESSAGE]” @@ -8804,23 +8872,6 @@ Click and drag anywhere on the world to rotate your view </notification> <notification - name="PopupAttempt" - icon="Popup_Caution" - type="browser"> - A pop-up was prevented from opening. - <form name="form"> - <ignore name="ignore" - control="MediaEnablePopups" - invert_control="true" - text="Enable all pop-ups"/> - <button default="true" - index="0" - name="open" - text="Open pop-up window"/> - </form> - </notification> - - <notification icon="alertmodal.tga" name="SOCKS_NOT_PERMITTED" type="alertmodal"> @@ -9802,6 +9853,14 @@ Can't move object '[OBJECT_NAME]' to <notification icon="alertmodal.tga" + name="NoParcelPermsNoObject" + type="notify"> + <tag>fail</tag> +Copy failed because you lack access to that parcel. + </notification> + + <notification + icon="alertmodal.tga" name="CantMoveObjectRegionVersion" type="notify"> <tag>fail</tag> @@ -9837,6 +9896,17 @@ You don't have permission to modify that object <notification icon="alertmodal.tga" + name="TooMuchObjectInventorySelected" + type="alertmodal"> + <tag>fail</tag> + Too many objects with large inventory are selected. Please select fewer objects and try again. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="CantEnablePhysObjContributesToNav" type="notify"> <tag>fail</tag> @@ -9934,6 +10004,22 @@ Cannot save to object contents: This would modify the attachment permissions. <notification icon="alertmodal.tga" + name="AttachmentHasTooMuchInventory" + type="notify"> + <tag>fail</tag> +Your attachments contain too much inventory to add more. + </notification> + + <notification + icon="alertmodal.tga" + name="IllegalAttachment" + type="notify"> + <tag>fail</tag> +The attachment has requested a nonexistent point on the avatar. It has been attached to the chest instead. + </notification> + + <notification + icon="alertmodal.tga" name="TooManyScripts" type="notify"> <tag>fail</tag> @@ -10183,6 +10269,22 @@ You have been teleported by the object '[OBJECT_NAME]' owned by an unknown user. <notification icon="alertmodal.tga" + name="StandDeniedByObject" + type="notify"> + <tag>fail</tag> +'[OBJECT_NAME]' will not allow you to stand at this time. + </notification> + + <notification + icon="alertmodal.tga" + name="ResitDeniedByObject" + type="notify"> + <tag>fail</tag> +'[OBJECT_NAME]' will not allow you to change your seat at this time. + </notification> + + <notification + icon="alertmodal.tga" name="CantCreateObjectRegionFull" type="notify"> <tag>fail</tag> @@ -10406,6 +10508,14 @@ Not enough script resources available to attach object! </notification> <notification + icon="alertmodal.tga" + name="IllegalAttachment" + type="notify"> + <tag>fail</tag> + The attachment has requested a nonexistent point on the avatar. It has been attached to the chest instead. + </notification> + + <notification icon="alertmodal.tga" name="CantDropItemTrialUser" type="notify"> @@ -10972,6 +11082,14 @@ Money transfers to objects are currently disabled in this region. <notification icon="alertmodal.tga" + name="DroppedMoneyTransferRequest" + type="notify"> + <tag>fail</tag> +Unable to make payment due to system load. + </notification> + + <notification + icon="alertmodal.tga" name="CantPayNoAgent" type="notify"> <tag>fail</tag> diff --git a/indra/newview/skins/default/xui/en/panel_notification.xml b/indra/newview/skins/default/xui/en/panel_notification.xml index 94c468e1bb..756b8f8102 100644 --- a/indra/newview/skins/default/xui/en/panel_notification.xml +++ b/indra/newview/skins/default/xui/en/panel_notification.xml @@ -10,7 +10,6 @@ left="0" name="notification_panel" chrome="true" - show_title="false" top="0" height="140" translate="false" diff --git a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml index d85b778db2..42a7974316 100644 --- a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml +++ b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml @@ -9,6 +9,26 @@ name="Wearing" top="0" width="312"> +<panel.string + name="no_attachments"> + No attachments worn. + </panel.string> + <accordion + fit_parent="true" + follows="all" + height="400" + layout="topleft" + left="0" + single_expansion="true" + top="0" + name="wearables_accordion" + background_visible="true" + bg_alpha_color="DkGray2" + width="309"> + <accordion_tab + layout="topleft" + name="tab_wearables" + title="Wearables"> <wearable_items_list follows="all" height="400" @@ -20,6 +40,27 @@ top="0" width="309" worn_indication_enabled="false" /> + </accordion_tab> + <accordion_tab + layout="topleft" + name="tab_temp_attachments" + title="Temporary attachments"> + <scroll_list + draw_heading="false" + left="3" + width="309" + height="400" + follows="all" + name="temp_attachments_list"> + <scroll_list.columns + name="icon" + width="15" /> + <scroll_list.columns + name="text" + width="210" /> + </scroll_list> + </accordion_tab> + </accordion> <panel background_visible="true" follows="bottom|left|right" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 4a5117adac..0deb1d03cf 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -138,7 +138,7 @@ initial_value="1" layout="topleft" left_pad="0" - max_val="2.0" + max_val="4.0" min_val="0.75" name="ui_scale_slider" top_pad="-14" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index a9b8e197bc..32cbbff8b7 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -2,7 +2,7 @@ <panel border="true" follows="left|top|right|bottom" - height="418" + height="438" label="Graphics" layout="topleft" left="102" @@ -233,7 +233,7 @@ <slider control_name="IndirectMaxComplexity" - tool_tip="Controls at what point a visually complex avatar is drawn as a jelly doll" + tool_tip="Controls at what point a visually complex avatar is drawn as a JellyDoll" follows="left|top" height="16" initial_value="101" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml index 323da2be38..284688d4d1 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml @@ -16,7 +16,7 @@ </panel.string> <button - follows="left|bottom" + follows="left|top" height="23" label="Clear History" tool_tip="Clear login image, last location, teleport history, web, and texture cache" @@ -75,7 +75,7 @@ top_pad="10" width="350" /> <button - follows="left|bottom" + follows="left|top" height="23" label="Block list" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 0b605cf6f7..c20f9b2c51 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -273,6 +273,18 @@ name="update_willing_to_test" width="400" top_pad="5"/> + <check_box + top_delta="4" + enabled="true" + follows="left|top" + height="14" + control_name="UpdaterShowReleaseNotes" + label="Show Release Notes after update" + left_delta="0" + mouse_opaque="true" + name="update_show_release_notes" + width="400" + top_pad="5"/> <text type="string" length="1" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml index 615abbaa89..53b74fa645 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -2,7 +2,7 @@ <panel border="true" follows="all" - height="408" + height="438" label="Sounds" layout="topleft" left="102" diff --git a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml index eb67d07601..068e4420bc 100644 --- a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml +++ b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml @@ -374,9 +374,11 @@ layout="topleft" tool_tip="Movie play progress" width="200"> - <slider_bar.commit_callback - function="MediaCtrl.JumpProgress" /> - </slider_bar> + <slider_bar.mouse_down_callback + function="MediaCtrl.MouseDown" /> + <slider_bar.mouse_up_callback + function="MediaCtrl.MouseUp" /> + </slider_bar> </layout_panel> <layout_panel name="skip_back" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 8988c3e028..dcb259f2bb 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -51,13 +51,14 @@ OpenGL Version: [OPENGL_VERSION] J2C Decoder Version: [J2C_VERSION] Audio Driver Version: [AUDIO_DRIVER_VERSION] LLCEFLib/CEF Version: [LLCEFLIB_VERSION] +LibVLC Version: [LIBVLC_VERSION] Voice Server Version: [VOICE_VERSION] </string> <string name="AboutTraffic">Packets Lost: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%)</string> <string name="AboutTime">[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second,datetime,slt]</string> <string name="ErrorFetchingServerReleaseNotesURL">Error fetching server release notes URL.</string> <string name="BuildConfiguration">Build Configuration</string> - + <!-- progress --> <string name="ProgressRestoring">Restoring...</string> <string name="ProgressChangingResolution">Changing resolution...</string> @@ -499,6 +500,7 @@ Please try logging in again in a minute.</string> <string name="TeleportYourAgent">Teleport you</string> <string name="ManageEstateSilently">Manage your estates silently</string> <string name="ChangeYourDefaultAnimations">Change your default animations</string> + <string name="ForceSitAvatar">Force your avatar to sit</string> <string name="NotConnected">Not Connected</string> <string name="AgentNameSubst">(You)</string> <!-- Substitution for agent name --> @@ -2256,6 +2258,7 @@ For AI Character: Get the closest navigable point to the point provided. <string name="BodyPartsLeftLeg">Left Leg</string> <string name="BodyPartsTorso">Torso</string> <string name="BodyPartsRightLeg">Right Leg</string> + <string name="BodyPartsEnhancedSkeleton">Enhanced Skeleton</string> <!-- slider --> <string name="GraphicsQualityLow">Low</string> @@ -2477,8 +2480,23 @@ This feature is currently in Beta. Please add your name to this [http://goo.gl/f <string name="Stomach">Stomach</string> <string name="Left Pec">Left Pec</string> <string name="Right Pec">Right Pec</string> - <string name="Neck">Neck</string> - <string name="Avatar Center">Avatar Center</string> + <string name="Neck">Neck</string> + <string name="Avatar Center">Avatar Center</string> + <string name="Left Ring Finger">Left Ring Finger</string> + <string name="Right Ring Finger">Right Ring Finger</string> + <string name="Tail Base">Tail Base</string> + <string name="Tail Tip">Tail Tip</string> + <string name="Left Wing">Left Wing</string> + <string name="Right Wing">Right Wing</string> + <string name="Jaw">Jaw</string> + <string name="Alt Left Ear">Alt Left Ear</string> + <string name="Alt Right Ear">Alt Right Ear</string> + <string name="Alt Left Eye">Alt Left Eye</string> + <string name="Alt Right Eye">Alt Right Eye</string> + <string name="Tongue">Tongue</string> + <string name="Groin">Groin</string> + <string name="Left Hind Foot">Left Hind Foot</string> + <string name="Right Hind Foot">Right Hind Foot</string> <string name="Invalid Attachment">Invalid Attachment Point</string> <string name="ATTACHMENT_MISSING_ITEM">Error: missing item</string> <string name="ATTACHMENT_MISSING_BASE_ITEM">Error: missing base item</string> @@ -2499,6 +2517,15 @@ This feature is currently in Beta. Please add your name to this [http://goo.gl/f <string name="av_render_most_of">You may not be rendered by most of those around you.</string> <string name="av_render_anyone">You may not be rendered by anyone around you.</string> + <!-- HUD complexity rendering messages, see llavatarrendernotifier. --> + <string name="hud_description_total">Your HUD</string> + <string name="hud_name_with_joint">[OBJ_NAME] (worn on [JNT_NAME])</string> + <string name="hud_render_memory_warning">[HUD_DETAILS] uses a lot of texture memory</string> + <string name="hud_render_cost_warning">[HUD_DETAILS] contains a lot of expensive objects and textures</string> + <string name="hud_render_heavy_textures_warning">[HUD_DETAILS] contains a lot of large textures</string> + <string name="hud_render_cramped_warning">[HUD_DETAILS] contains too many objects</string> + <string name="hud_render_textures_warning">[HUD_DETAILS] contains too many textures</string> + <!-- AgeYearsA = singular, AgeYearsB = plural, AgeYearsC = plural for non-English languages like Russian @@ -2566,7 +2593,8 @@ This feature is currently in Beta. Please add your name to this [http://goo.gl/f <string name="SaveComplete">Save complete.</string> <string name="UploadFailed">File upload failed: </string> <string name="ObjectOutOfRange">Script (object out of range)</string> - + <string name="ScriptWasDeleted">Script (deleted from inventory)</string> + <!-- god tools --> <string name="GodToolsObjectOwnedBy">Object [OBJECT] owned by [OWNER]</string> @@ -2654,8 +2682,8 @@ This feature is currently in Beta. Please add your name to this [http://goo.gl/f <string name="ATTACH_LULEG">Left Upper Leg</string> <string name="ATTACH_LLLEG">Left Lower Leg</string> <string name="ATTACH_BELLY">Belly</string> - <string name="ATTACH_RPEC">Right Pec</string> - <string name="ATTACH_LPEC">Left Pec</string> + <string name="ATTACH_LEFT_PEC">Left Pec</string> + <string name="ATTACH_RIGHT_PEC">Right Pec</string> <string name="ATTACH_HUD_CENTER_2">HUD Center 2</string> <string name="ATTACH_HUD_TOP_RIGHT">HUD Top Right</string> <string name="ATTACH_HUD_TOP_CENTER">HUD Top Center</string> @@ -2666,6 +2694,21 @@ This feature is currently in Beta. Please add your name to this [http://goo.gl/f <string name="ATTACH_HUD_BOTTOM_RIGHT">HUD Bottom Right</string> <string name="ATTACH_NECK">Neck</string> <string name="ATTACH_AVATAR_CENTER">Avatar Center</string> + <string name="ATTACH_LHAND_RING1">Left Ring Finger</string> + <string name="ATTACH_RHAND_RING1">Right Ring Finger</string> + <string name="ATTACH_TAIL_BASE">Tail Base</string> + <string name="ATTACH_TAIL_TIP">Tail Tip</string> + <string name="ATTACH_LWING">Left Wing</string> + <string name="ATTACH_RWING">Right Wing</string> + <string name="ATTACH_FACE_JAW">Jaw</string> + <string name="ATTACH_FACE_LEAR">Alt Left Ear</string> + <string name="ATTACH_FACE_REAR">Alt Right Ear</string> + <string name="ATTACH_FACE_LEYE">Alt Left Eye</string> + <string name="ATTACH_FACE_REYE">Alt Right Eye</string> + <string name="ATTACH_FACE_TONGUE">Tongue</string> + <string name="ATTACH_GROIN">Groin</string> + <string name="ATTACH_HIND_LFOOT">Left Hind Foot</string> + <string name="ATTACH_HIND_RFOOT">Right Hind Foot</string> <!-- script editor --> <string name="CursorPos">Line [LINE], Column [COLUMN]</string> @@ -2834,6 +2877,12 @@ Expected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh <string name="Multiple Media">Multiple Media</string> <string name="Play Media">Play/Pause Media</string> + <!-- Drivers support/update pages --> + <string name="IntelDriverPage">http://www.intel.com/p/en_US/support/detect/graphics</string> + <string name="NvidiaDriverPage">http://www.nvidia.com/Download/index.aspx?lang=en-us</string> + <string name="AMDDriverPage">http://support.amd.com/us/Pages/AMDSupportHub.aspx</string> + + <!-- OSMessageBox messages --> <string name="MBCmdLineError"> An error was found parsing the command line. diff --git a/indra/newview/skins/default/xui/es/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/es/floater_preferences_graphics_advanced.xml index dda95ad070..84b256c8e3 100644 --- a/indra/newview/skins/default/xui/es/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/es/floater_preferences_graphics_advanced.xml @@ -15,7 +15,7 @@ <text name="AvatarText"> Avatar </text> - <slider label="Complejidad máxima:" name="IndirectMaxComplexity" tool_tip="Controla en qué momento un avatar visualmente complejo se dibuja como una sombra de color sólido"/> + <slider label="Complejidad máxima:" name="IndirectMaxComplexity" tool_tip="Controla en qué momento un avatar visualmente complejo se dibuja como un "JellyDoll""/> <text name="IndirectMaxComplexityText"> 0 </text> diff --git a/indra/newview/skins/default/xui/es/menu_attachment_other.xml b/indra/newview/skins/default/xui/es/menu_attachment_other.xml index 772b27c9ba..c92583cfc3 100644 --- a/indra/newview/skins/default/xui/es/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/es/menu_attachment_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="MI" name="Send IM..."/> <menu_item_call label="Llamada" name="Call"/> <menu_item_call label="Invitar al grupo" name="Invite..."/> + <menu_item_call label="Restablecer esqueleto" name="Reset Skeleton"/> <menu_item_call label="Ignorar" name="Avatar Mute"/> <menu_item_call label="Denunciar" name="abuse"/> <menu_item_call label="Congelar" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/es/menu_attachment_self.xml b/indra/newview/skins/default/xui/es/menu_attachment_self.xml index 02819e6816..a4d09a44ab 100644 --- a/indra/newview/skins/default/xui/es/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/es/menu_attachment_self.xml @@ -9,6 +9,7 @@ <menu_item_call label="Editar mi vestuario" name="Edit Outfit"/> <menu_item_call label="Editar mi anatomía" name="Edit My Shape"/> <menu_item_call label="Altura del avatar" name="Hover Height"/> + <menu_item_call label="Restablecer esqueleto" name="Reset Skeleton"/> <menu_item_call label="Mis amigos" name="Friends..."/> <menu_item_call label="Mis grupos" name="Groups..."/> <menu_item_call label="Mi perfil" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/es/menu_avatar_other.xml b/indra/newview/skins/default/xui/es/menu_avatar_other.xml index 75cbf5a022..e5aef03911 100644 --- a/indra/newview/skins/default/xui/es/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/es/menu_avatar_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="MI" name="Send IM..."/> <menu_item_call label="Llamada" name="Call"/> <menu_item_call label="Invitar al grupo" name="Invite..."/> + <menu_item_call label="Restablecer esqueleto" name="Reset Skeleton"/> <menu_item_call label="Ignorar" name="Avatar Mute"/> <menu_item_call label="Denunciar" name="abuse"/> <menu_item_call label="Congelar" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/es/menu_avatar_self.xml b/indra/newview/skins/default/xui/es/menu_avatar_self.xml index d60a3434cf..ab14966217 100644 --- a/indra/newview/skins/default/xui/es/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/es/menu_avatar_self.xml @@ -26,6 +26,7 @@ <menu_item_call label="Editar mi vestuario" name="Edit Outfit"/> <menu_item_call label="Editar mi anatomía" name="Edit My Shape"/> <menu_item_call label="Altura del avatar" name="Hover Height"/> + <menu_item_call label="Restablecer esqueleto" name="Reset Skeleton"/> <menu_item_call label="Mis amigos" name="Friends..."/> <menu_item_call label="Mis grupos" name="Groups..."/> <menu_item_call label="Mi perfil" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml index fd248116b8..07c358615c 100644 --- a/indra/newview/skins/default/xui/es/menu_viewer.xml +++ b/indra/newview/skins/default/xui/es/menu_viewer.xml @@ -367,6 +367,7 @@ <menu_item_check label="Animation Info" name="Animation Info"/> <menu_item_check label="Disable Level Of Detail" name="Disable LOD"/> <menu_item_check label="Show Collision Skeleton" name="Show Collision Skeleton"/> + <menu_item_check label="Mostrar los huesos" name="Show Bones"/> <menu_item_check label="Display Agent Target" name="Display Agent Target"/> <menu_item_call label="Debug Avatar Textures" name="Debug Avatar Textures"/> </menu> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index b52497eb85..a67e410814 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -477,6 +477,9 @@ Se ha superado el límite máximo de [MAX_ATTACHMENTS] objetos. Por favor, quít <notification name="CannotWearInfoNotComplete"> No puedes vestirte este ítem porque aún no se ha cargado. Por favor, inténtalo de nuevo en un minuto. </notification> + <notification name="MustEnterPasswordToLogIn"> + Escribe la contraseña para poder iniciar sesión. + </notification> <notification name="MustHaveAccountToLogIn"> Lo sentimos. Se ha quedado algún espacio en blanco. Tienes que volver a introducir el nombre de usuario de tu avatar. @@ -545,6 +548,9 @@ Nota: esto vaciará la caché. <notification name="ChangeConnectionPort"> La configuración del puerto tendrá efecto cuando reinicies [APP_NAME]. </notification> + <notification name="ChangeDeferredDebugSetting"> + El cambio de configuración del depurador se activará cuando reinicies [APP_NAME]. + </notification> <notification name="ChangeSkin"> Verás la nueva apariencia cuando reinicies [APP_NAME]. </notification> @@ -1370,12 +1376,13 @@ Puedes usar [SECOND_LIFE] de forma normal; los demás residentes te verán corre <ignore name="ignore" text="La ropa está tardando mucho en descargarse"/> </form> </notification> - <notification name="RegionAndAgentComplexity"> - Tu [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complejidad visual] es [AGENT_COMPLEXITY]. + <notification name="AgentComplexityWithVisibility"> + La [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complejidad de tu avatar] es [AGENT_COMPLEXITY]. [OVERLIMIT_MSG] + <usetemplate ignoretext="Avisarme si la complejidad de mi avatar puede ser excesiva" name="notifyignore"/> </notification> <notification name="AgentComplexity"> - Tu [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complejidad visual] es [AGENT_COMPLEXITY]. + La [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complejidad de tu avatar] es [AGENT_COMPLEXITY]. </notification> <notification name="FirstRun"> Se ha completado la instalación de [SECOND_LIFE]. @@ -1492,6 +1499,10 @@ Cambia la textura [TEXTURE_NUM] por una imagen de 24-bit y 512x512 o menor, y pu ¿Realmente quieres predeterminar el terreno actual, haciéndolo el centro de los limites para elevarlo y rebajarlo, y el terreno por defecto para la herramienta 'Revertir'? <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/> </notification> + <notification name="ConfirmTextureHeights"> + Vas a usar valores inferiores más grandes que los de Intervalos de elevación. ¿Quieres continuar? + <usetemplate canceltext="No preguntar" name="yesnocancelbuttons" notext="Cancelar" yestext="Aceptar"/> + </notification> <notification name="MaxAllowedAgentOnRegion"> Sólo puedes tener [MAX_AGENTS] residentes autorizados. </notification> @@ -1729,14 +1740,6 @@ Si estás impaciente por probar las nuevas funciones y correcciones, lee la pág No es posible abandonar el grupo. No puedes abandonarlo porque eres su último propietario. Antes tienes que asignar el papel de propietario a otro miembro. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="GroupDepartError"> - No se puede abandonar el grupo: [reason]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> - <notification name="GroupDepart"> - Has abandonado el grupo [group_name]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> <notification name="ConfirmKick"> ¿Quieres realmente expulsar a todos los residentes de la cuadrícula? <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Expulsar a todos los Residentes"/> @@ -2409,6 +2412,10 @@ Linden Lab ¿Estás seguro de que quieres borrar de forma permanente el contenido de la Papelera? <usetemplate ignoretext="Confirmar antes de vaciar la Papelera del inventario" name="okcancelignore" notext="Cancelar" yestext="OK"/> </notification> + <notification name="TrashIsFull"> + La papelera está completamente llena. Esto puede causar problemas a la hora de iniciar sesión. + <usetemplate name="okcancelbuttons" notext="Vaciaré la papelera más adelante" yestext="Vaciar la papelera"/> + </notification> <notification name="ConfirmClearBrowserCache"> ¿Estás seguro de que quieres borrar tu historial web, de viajes y de búsquedas? <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/> @@ -2996,7 +3003,7 @@ Si permaneces en esta región serás desconectado. [MESSAGE] -Del objeto: <nolink>[OBJECTNAME]</nolink>, propietario: [NAME_SLURL] +De objeto: <nolink>[OBJECTNAME]</nolink>, propietario: [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Cargar"/> <button name="Cancel" text="Cancelar"/> @@ -3258,11 +3265,15 @@ Por tu seguridad, serán bloqueadas durante unos segundos. <notification name="AttachmentSaved"> Se ha guardado el adjunto. </notification> - <notification name="PresetNotSaved"> - Error al guardar el valor predefinido [NAME]. + <notification name="AppearanceToXMLSaved"> + El aspecto se ha guardado como XML en [PATH] </notification> - <notification name="PresetNotDeleted"> - Error al eliminar el valor predefinido [NAME]. + <notification name="AppearanceToXMLFailed"> + Error al guardar el aspecto como XML. + icon="notifytip.tga" + name="PresetNotDeleted" + type="notifytip"> +Error al eliminar el valor predefinido [NAME]. </notification> <notification name="UnableToFindHelpTopic"> No se ha podido encontrar un tema de ayuda para este elemento. @@ -4074,6 +4085,9 @@ Prueba otra vez dentro de un minuto. <notification name="CantAttachNotEnoughScriptResources"> No hay suficientes recursos de script disponibles para anexar el objeto </notification> + <notification name="IllegalAttachment"> + El anexo ha solicitado un punto que no existe en el avatar. Por tanto, se ha anexado al pecho. + </notification> <notification name="CantDropItemTrialUser"> No se pueden soltar objetos aquí; inténtalo en la zona de prueba gratuita. </notification> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/es/panel_preferences_alerts.xml index f34edf149e..c5b27ae766 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_alerts.xml @@ -3,8 +3,9 @@ <text name="tell_me_label"> Avisarme: </text> - <check_box label="Cuando gaste o consiga L$" name="notify_money_change_checkbox"/> + <check_box label="Cuando gaste L$" name="notify_money_spend_checkbox"/> <check_box label="Cuando mis amigos se conecten o desconecten" name="friends_online_notify_checkbox"/> + <check_box label="Cuando gane L$" name="notify_money_received_checkbox"/> <text name="show_label" width="300"> Mostrar siempre: </text> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml index f7fb8ab70d..2db4274e44 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml @@ -24,10 +24,15 @@ <text name="BetterText"> Más calidad </text> + <slider label="Complejidad máxima de avatar:" name="IndirectMaxComplexity" tool_tip="Controla en qué momento un avatar visualmente complejo se dibuja como un "JellyDoll""/> + <text name="IndirectMaxComplexityText"> + 0 + </text> <check_box initial_value="true" label="Shaders de la atmósfera" name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="Modelo de iluminación avanzado" name="UseLightShaders"/> <button label="Guardar configuración como valor predefinido..." name="PrefSaveButton"/> <button label="Cargar predefinido..." name="PrefLoadButton"/> + min_val="0.125" <button label="Eliminar predefinido..." name="PrefDeleteButton"/> <button label="Restablecer la configuración recomendada" name="Defaults"/> <button label="Configuración avanzada..." name="AdvancedSettings"/> diff --git a/indra/newview/skins/default/xui/es/panel_sound_devices.xml b/indra/newview/skins/default/xui/es/panel_sound_devices.xml index 9531b99cc8..109dcb565a 100644 --- a/indra/newview/skins/default/xui/es/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/es/panel_sound_devices.xml @@ -16,9 +16,9 @@ Salida </text> <text name="My volume label"> - Mi volumen: + Volumen de mic.: </text> - <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Cambia el volumen usando este deslizable"/> + <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Cambia el volumen del micrófono con este controlador deslizante"/> <text name="wait_text"> Por favor, espera </text> diff --git a/indra/newview/skins/default/xui/es/panel_status_bar.xml b/indra/newview/skins/default/xui/es/panel_status_bar.xml index 8ea56c5262..8aaa236475 100644 --- a/indra/newview/skins/default/xui/es/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/es/panel_status_bar.xml @@ -5,7 +5,7 @@ <panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string> <panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string> <panel.string name="buycurrencylabel">[AMT] L$</panel.string> - <panel left="-410" name="balance_bg" width="200"> + <panel left="-431" name="balance_bg" width="200"> <text name="balance" tool_tip="Haz clic para actualizar tu saldo en L$" value="L$??"/> <button label="Comprar L$" name="buyL" tool_tip="Pulsa para comprar más L$"/> <button label="Comprar" name="goShop" tool_tip="Abrir el mercado de Second Life" width="80"/> diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index ea6cea060b..4e20793d86 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -32,6 +32,9 @@ [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL]) [[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]) SLURL: <nolink>[SLURL]</nolink> @@ -55,7 +58,7 @@ Tarjeta gráfica: [GRAPHICS_CARD] Versión de J2C Decoder: [J2C_VERSION] Versión de Audio Driver: [AUDIO_DRIVER_VERSION] Versión de LLCEFLib/CEF: [LLCEFLIB_VERSION] -Versión del servidor de voz: [VOICE_VERSION] +Versión de Voice Server: [VOICE_VERSION] </string> <string name="AboutTraffic"> Paquetes perdidos: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%) @@ -63,6 +66,9 @@ Versión del servidor de voz: [VOICE_VERSION] <string name="ErrorFetchingServerReleaseNotesURL"> Error al obtener la URL de las notas de la versión del servidor. </string> + <string name="BuildConfiguration"> + Configuración de constitución + </string> <string name="ProgressRestoring"> Restaurando... </string> @@ -1372,6 +1378,9 @@ Intenta iniciar sesión de nuevo en unos instantes. <string name="BodyPartsRightLeg"> Pierna der. </string> + <string name="BodyPartsEnhancedSkeleton"> + Esqueleto mejorado + </string> <string name="GraphicsQualityLow"> Bajo </string> @@ -1814,6 +1823,51 @@ Intenta iniciar sesión de nuevo en unos instantes. <string name="Avatar Center"> Centro del avatar </string> + <string name="Left Ring Finger"> + Dedo anular izquierdo + </string> + <string name="Right Ring Finger"> + Dedo anular derecho + </string> + <string name="Tail Base"> + Base de la cola + </string> + <string name="Tail Tip"> + Extremo de la cola + </string> + <string name="Left Wing"> + Ala izquierda + </string> + <string name="Right Wing"> + Ala derecha + </string> + <string name="Jaw"> + Mandíbula + </string> + <string name="Alt Left Ear"> + Oreja izquierda alternativa + </string> + <string name="Alt Right Ear"> + Oreja derecha alternativa + </string> + <string name="Alt Left Eye"> + Ojo izquierdo alternativo + </string> + <string name="Alt Right Eye"> + Ojo derecho alternativo + </string> + <string name="Tongue"> + Lengua + </string> + <string name="Groin"> + Ingle + </string> + <string name="Left Hind Foot"> + Pata trasera izquierda + </string> + <string name="Right Hind Foot"> + Pata trasera derecha + </string> <string name="Invalid Attachment"> Punto de colocación no válido </string> @@ -2203,11 +2257,11 @@ Intenta iniciar sesión de nuevo en unos instantes. <string name="ATTACH_BELLY"> Vientre </string> - <string name="ATTACH_RPEC"> - Pecho derecho + <string name="ATTACH_LEFT_PEC"> + Pectoral izquierdo </string> - <string name="ATTACH_LPEC"> - Pecho izquierdo + <string name="ATTACH_RIGHT_PEC"> + Pectoral derecho </string> <string name="ATTACH_HUD_CENTER_2"> HUD: Centro 2 @@ -2239,6 +2293,51 @@ Intenta iniciar sesión de nuevo en unos instantes. <string name="ATTACH_AVATAR_CENTER"> Centro del avatar </string> + <string name="ATTACH_LHAND_RING1"> + Dedo anular izquierdo + </string> + <string name="ATTACH_RHAND_RING1"> + Dedo anular derecho + </string> + <string name="ATTACH_TAIL_BASE"> + Base de la cola + </string> + <string name="ATTACH_TAIL_TIP"> + Extremo de la cola + </string> + <string name="ATTACH_LWING"> + Ala izquierda + </string> + <string name="ATTACH_RWING"> + Ala derecha + </string> + <string name="ATTACH_FACE_JAW"> + Mandíbula + </string> + <string name="ATTACH_FACE_LEAR"> + Oreja izquierda alternativa + </string> + <string name="ATTACH_FACE_REAR"> + Oreja derecha alternativa + </string> + <string name="ATTACH_FACE_LEYE"> + Ojo izquierdo alternativo + </string> + <string name="ATTACH_FACE_REYE"> + Ojo derecho alternativo + </string> + <string name="ATTACH_FACE_TONGUE"> + Lengua + </string> + <string name="ATTACH_GROIN"> + Ingle + </string> + <string name="ATTACH_HIND_LFOOT"> + Pata trasera izquierda + </string> + <string name="ATTACH_HIND_RFOOT"> + Pata trasera derecha + </string> <string name="CursorPos"> Línea [LINE], Columna [COLUMN] </string> @@ -4165,6 +4264,12 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE]. <string name="OfflineStatus"> Desconectado/a </string> + <string name="not_online_msg"> + El usuario no está conectado: el mensaje se almacenará para entregárselo más tarde. + </string> + <string name="not_online_inventory"> + El usuario no está conectado: el inventario se ha guardado. + </string> <string name="answered_call"> Han respondido a tu llamada </string> diff --git a/indra/newview/skins/default/xui/fr/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/fr/floater_preferences_graphics_advanced.xml index 5c5af022ca..d3c4dcfa27 100644 --- a/indra/newview/skins/default/xui/fr/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/fr/floater_preferences_graphics_advanced.xml @@ -15,7 +15,7 @@ <text name="AvatarText"> Avatar </text> - <slider label="Complexité max. :" name="IndirectMaxComplexity" tool_tip="Contrôle à quel moment un avatar complexe est représenté comme un « jelly doll » (forme de couleur unie)"/> + <slider label="Complexité max. :" name="IndirectMaxComplexity" tool_tip="Contrôle à quel moment un avatar complexe est représenté comme un « jelly baby »"/> <text name="IndirectMaxComplexityText"> 0 </text> diff --git a/indra/newview/skins/default/xui/fr/menu_attachment_other.xml b/indra/newview/skins/default/xui/fr/menu_attachment_other.xml index 20de34250a..fd8112429e 100644 --- a/indra/newview/skins/default/xui/fr/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/fr/menu_attachment_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="Appeler" name="Call"/> <menu_item_call label="Inviter dans le groupe" name="Invite..."/> + <menu_item_call label="Réinitialiser le squelette" name="Reset Skeleton"/> <menu_item_call label="Ignorer" name="Avatar Mute"/> <menu_item_call label="Signaler" name="abuse"/> <menu_item_call label="Figer" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/fr/menu_attachment_self.xml b/indra/newview/skins/default/xui/fr/menu_attachment_self.xml index 1ccba08099..f3089ad3bb 100644 --- a/indra/newview/skins/default/xui/fr/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/fr/menu_attachment_self.xml @@ -9,6 +9,7 @@ <menu_item_call label="Modifier ma tenue" name="Edit Outfit"/> <menu_item_call label="Modifier ma silhouette" name="Edit My Shape"/> <menu_item_call label="Hauteur de sustentation" name="Hover Height"/> + <menu_item_call label="Réinitialiser le squelette" name="Reset Skeleton"/> <menu_item_call label="Mes amis" name="Friends..."/> <menu_item_call label="Mes groupes" name="Groups..."/> <menu_item_call label="Mon profil" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/fr/menu_avatar_other.xml b/indra/newview/skins/default/xui/fr/menu_avatar_other.xml index d31f205efb..b97c4b0f48 100644 --- a/indra/newview/skins/default/xui/fr/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/fr/menu_avatar_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="Appeler" name="Call"/> <menu_item_call label="Inviter dans le groupe" name="Invite..."/> + <menu_item_call label="Réinitialiser le squelette" name="Reset Skeleton"/> <menu_item_call label="Ignorer" name="Avatar Mute"/> <menu_item_call label="Signaler" name="abuse"/> <menu_item_call label="Figer" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/fr/menu_avatar_self.xml b/indra/newview/skins/default/xui/fr/menu_avatar_self.xml index 1c768a078c..a4c1df8cee 100644 --- a/indra/newview/skins/default/xui/fr/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/fr/menu_avatar_self.xml @@ -26,6 +26,7 @@ <menu_item_call label="Modifier ma tenue" name="Edit Outfit"/> <menu_item_call label="Modifier ma silhouette" name="Edit My Shape"/> <menu_item_call label="Hauteur de sustentation" name="Hover Height"/> + <menu_item_call label="Réinitialiser le squelette" name="Reset Skeleton"/> <menu_item_call label="Mes amis" name="Friends..."/> <menu_item_call label="Mes groupes" name="Groups..."/> <menu_item_call label="Mon profil" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml index 9b1f195391..3c9f5c2aa9 100644 --- a/indra/newview/skins/default/xui/fr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml @@ -22,7 +22,6 @@ <menu_item_check label="Ne pas déranger" name="Do Not Disturb"/> </menu> <menu_item_call label="Acheter des L$..." name="Buy and Sell L$"/> - <menu_item_call label="Boîte d'envoi vendeur..." name="MerchantOutbox"/> <menu_item_call label="Annonces de Place du marché..." name="MarketplaceListings"/> <menu_item_call label="Page d'accueil du compte..." name="Manage My Account"> <menu_item_call.on_click name="ManageMyAccount_url" parameter="WebLaunchJoinNow,http://secondlife.com/account/index.php?lang=fr"/> @@ -421,6 +420,7 @@ <menu_item_check label="Désactiver LOD" name="Disable LOD"/> <menu_item_check label="Debogage Character Vis" name="Debug Character Vis"/> <menu_item_check label="Afficher le squelette de collision" name="Show Collision Skeleton"/> + <menu_item_check label="Voir les os" name="Show Bones"/> <menu_item_check label="Afficher la cible de l'avatar" name="Display Agent Target"/> <menu_item_call label="Dump Attachments" name="Dump Attachments"/> <menu_item_call label="Débogage des textures des avatars" name="Debug Avatar Textures"/> diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index 080ea741c5..2310fc5611 100644 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -479,6 +479,9 @@ La limite de [MAX_ATTACHMENTS] objets joints a été dépassée. Veuillez commen <notification name="CannotWearInfoNotComplete"> Vous ne pouvez pas porter cet article car il n'a pas encore été chargé. Veuillez réessayer dans une minute. </notification> + <notification name="MustEnterPasswordToLogIn"> + Veuillez saisir votre mot de passe pour vous connecter. + </notification> <notification name="MustHaveAccountToLogIn"> Zut ! Vous avez oublié de fournir certaines informations. Vous devez saisir le nom d'utilisateur de votre avatar. @@ -547,6 +550,9 @@ Remarque : cela videra le cache. <notification name="ChangeConnectionPort"> Les paramètres du port prendront effet après le redémarrage de [APP_NAME]. </notification> + <notification name="ChangeDeferredDebugSetting"> + Le changement de paramètre de débogage sera effectué au redémarrage de [APP_NAME]. + </notification> <notification name="ChangeSkin"> Le nouveau thème apparaîtra après le redémarrage de [APP_NAME]. </notification> @@ -1361,12 +1367,13 @@ Vous pouvez utiliser [SECOND_LIFE] normalement, les autres résidents vous voien <ignore name="ignore" text="Vos habits prennent du temps à télécharger"/> </form> </notification> - <notification name="RegionAndAgentComplexity"> - Votre [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complexité visuelle] est [AGENT_COMPLEXITY]. + <notification name="AgentComplexityWithVisibility"> + Votre [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complexité de l'avatar] est [AGENT_COMPLEXITY]. [OVERLIMIT_MSG] + <usetemplate ignoretext="M'avertir si la complexité de l'avatar est trop élevée" name="notifyignore"/> </notification> <notification name="AgentComplexity"> - Votre [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complexité visuelle] est [AGENT_COMPLEXITY]. + Votre [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complexité de l'avatar] est [AGENT_COMPLEXITY]. </notification> <notification name="FirstRun"> L'installation de [APP_NAME] est terminée. @@ -1483,6 +1490,10 @@ suivant votre vitesse de connexion. Etes-vous sûr(e) de vouloir figer le relief actuel, en faire le point central des limites d'élévation/abaissement de relief et la valeur par défaut du bouton Annuler modification ? <usetemplate name="okcancelbuttons" notext="Annuler" yestext="OK"/> </notification> + <notification name="ConfirmTextureHeights"> + Vous vous apprêtez à utiliser des valeurs plus élevées que les limites d'élévation supérieures. Continuer ? + <usetemplate canceltext="Ne pas demander" name="yesnocancelbuttons" notext="Annuler" yestext="OK"/> + </notification> <notification name="MaxAllowedAgentOnRegion"> Vous ne pouvez pas autoriser plus de [MAX_AGENTS] résidents. </notification> @@ -1720,14 +1731,6 @@ Quitter le groupe ? Impossible de quitter le groupe. Vous ne pouvez pas quitter le groupe car vous en êtes le dernier propriétaire. Vous devez d'abord affecter le rôle de propriétaire à un autre membre. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="GroupDepartError"> - Impossible de quitter le groupe : [reason]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> - <notification name="GroupDepart"> - Vous avez quitté le groupe [group_name]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> <notification name="ConfirmKick"> Souhaitez-vous vraiment éjecter tous les résidents de la grille ? <usetemplate name="okcancelbuttons" notext="Annuler" yestext="Éjecter tous les résidents"/> @@ -2400,6 +2403,10 @@ Voulez-vous désactiver Ne pas déranger avant de terminer cette transaction ? Êtes-vous certain de vouloir supprimer le contenu de votre corbeille de manière permanente ? <usetemplate ignoretext="Confirmer avant de vider la corbeille" name="okcancelignore" notext="Annuler" yestext="OK"/> </notification> + <notification name="TrashIsFull"> + Votre corbeille déborde. Cela risque de provoquer des problèmes lors de la connexion. + <usetemplate name="okcancelbuttons" notext="Je viderai la corbeille plus tard" yestext="Vider la corbeille"/> + </notification> <notification name="ConfirmClearBrowserCache"> Êtes-vous certain de vouloir supprimer l'historique de vos visites et recherches ? <usetemplate name="okcancelbuttons" notext="Annuler" yestext="OK"/> @@ -2984,11 +2991,11 @@ Si vous restez dans cette région, vous serez déconnecté(e). Si vous restez dans cette région, vous serez déconnecté(e). </notification> <notification name="LoadWebPage"> - Charger la page Web [URL] ? + Charger la page Web [URL] ? [MESSAGE] -Venant de l'objet : <nolink>[OBJECTNAME]</nolink>, propriétaire : [NAME_SLURL] +Venant de l'objet : <nolink>[OBJECTNAME]</nolink>, propriétaire : [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Charger"/> <button name="Cancel" text="Annuler"/> @@ -3257,11 +3264,15 @@ Elles vont être bloquées pendant quelques secondes pour votre sécurité. <notification name="AttachmentSaved"> L'élément joint a été sauvegardé. </notification> - <notification name="PresetNotSaved"> - Erreur d’enregistrement du préréglage [NAME]. + <notification name="AppearanceToXMLSaved"> + L'apparence a été enregistrée en XML vers [PATH] </notification> - <notification name="PresetNotDeleted"> - Erreur de suppression du préréglage [NAME]. + <notification name="AppearanceToXMLFailed"> + Échec d'enregistrement de l'apparence en XML. + icon="notifytip.tga" + name="PresetNotDeleted" + type="notifytip"> +Erreur de suppression du préréglage [NAME]. </notification> <notification name="UnableToFindHelpTopic"> Impossible de trouver l'aide. @@ -4075,6 +4086,9 @@ Veuillez réessayer dans une minute. <notification name="CantAttachNotEnoughScriptResources"> Ressources de script insuffisantes pour attacher cet objet. </notification> + <notification name="IllegalAttachment"> + La pièce jointe a demandé un point non existant sur l'avatar. Il a été fixé sur la poitrine. + </notification> <notification name="CantDropItemTrialUser"> Vous ne pouvez pas déposer d'objets ici. Essayez la zone de période d'essai gratuite. </notification> diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/fr/panel_preferences_alerts.xml index 901a92ed1b..85cd958f49 100644 --- a/indra/newview/skins/default/xui/fr/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/fr/panel_preferences_alerts.xml @@ -3,8 +3,9 @@ <text name="tell_me_label"> Me prévenir : </text> - <check_box label="Quand je dépense ou que je reçois des L$" name="notify_money_change_checkbox"/> + <check_box label="Quand je dépense des L$" name="notify_money_spend_checkbox"/> <check_box label="Quand mes amis se connectent ou se déconnectent" name="friends_online_notify_checkbox"/> + <check_box label="Quand je reçois des L$" name="notify_money_received_checkbox"/> <text name="show_label"> Toujours afficher : </text> diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml index 01d89f03f8..2b1e613fe4 100644 --- a/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml @@ -24,10 +24,15 @@ <text name="BetterText"> Meilleure </text> + <slider label="Complexité max. de l'avatar :" name="IndirectMaxComplexity" tool_tip="Contrôle à quel moment un avatar complexe est représenté comme un « jelly baby »"/> + <text name="IndirectMaxComplexityText"> + 0 + </text> <check_box initial_value="true" label="Effets atmosphériques" name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="Modèle d’éclairage avancé" name="UseLightShaders"/> <button label="Enregistrer les paramètres comme préréglage..." name="PrefSaveButton"/> <button label="Charger un préréglage..." name="PrefLoadButton"/> + min_val="0,125" <button label="Supprimer un préréglage..." name="PrefDeleteButton"/> <button label="Réinitialiser les paramètres recommandés" name="Defaults"/> <button label="Paramètres avancés" name="AdvancedSettings"/> diff --git a/indra/newview/skins/default/xui/fr/panel_sound_devices.xml b/indra/newview/skins/default/xui/fr/panel_sound_devices.xml index 460b269f7c..720aaaf3e0 100644 --- a/indra/newview/skins/default/xui/fr/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/fr/panel_sound_devices.xml @@ -16,9 +16,9 @@ Sortie </text> <text name="My volume label"> - Mon volume : + Volume du micro : </text> - <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Régler le volume avec le curseur."/> + <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Régler le volume du micro avec le curseur."/> <text name="wait_text"> Veuillez patienter </text> diff --git a/indra/newview/skins/default/xui/fr/panel_status_bar.xml b/indra/newview/skins/default/xui/fr/panel_status_bar.xml index e2f05a525e..fef0379c2c 100644 --- a/indra/newview/skins/default/xui/fr/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/fr/panel_status_bar.xml @@ -5,7 +5,7 @@ <panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string> <panel.string name="timeTooltip">[weekday, datetime, slt] [sday, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string> <panel.string name="buycurrencylabel">[AMT] L$</panel.string> - <panel left="-405" name="balance_bg" width="195"> + <panel left="-426" name="balance_bg" width="195"> <text name="balance" tool_tip="Cliquer sur ce bouton pour actualiser votre solde en L$." value="L$ ??"/> <button label="Acheter L$" name="buyL" tool_tip="Cliquer pour acheter plus de L$."/> <button label="Achats" name="goShop" tool_tip="Ouvrir la Place du marché Second Life." width="75"/> diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index ae091aba39..843467df96 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -41,6 +41,9 @@ [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL]) [[VIEWER_RELEASE_NOTES_URL] [Notes de version]] </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]) SLURL : <nolink>[SLURL]</nolink> @@ -72,6 +75,9 @@ Version serveur vocal : [VOICE_VERSION] <string name="ErrorFetchingServerReleaseNotesURL"> Erreur lors de la récupération de l'URL des notes de version du serveur. </string> + <string name="BuildConfiguration"> + Configuration de la construction + </string> <string name="ProgressRestoring"> Restauration... </string> @@ -1390,6 +1396,9 @@ Veuillez réessayer de vous connecter dans une minute. <string name="BodyPartsRightLeg"> Jambe droite </string> + <string name="BodyPartsEnhancedSkeleton"> + Squelette amélioré + </string> <string name="GraphicsQualityLow"> Faible </string> @@ -1838,6 +1847,51 @@ Veuillez réessayer de vous connecter dans une minute. <string name="Avatar Center"> Centre de l'avatar </string> + <string name="Left Ring Finger"> + Annulaire gauche + </string> + <string name="Right Ring Finger"> + Annulaire droit + </string> + <string name="Tail Base"> + Base de la queue + </string> + <string name="Tail Tip"> + Bout de la queue + </string> + <string name="Left Wing"> + Aile gauche + </string> + <string name="Right Wing"> + Aile droite + </string> + <string name="Jaw"> + Mâchoire + </string> + <string name="Alt Left Ear"> + Oreille gauche différente + </string> + <string name="Alt Right Ear"> + Oreille droite différente + </string> + <string name="Alt Left Eye"> + Œil gauche différent + </string> + <string name="Alt Right Eye"> + Œil droit différent + </string> + <string name="Tongue"> + Langue + </string> + <string name="Groin"> + Aine + </string> + <string name="Left Hind Foot"> + Pied arrière gauche + </string> + <string name="Right Hind Foot"> + Pied arrière droit + </string> <string name="Invalid Attachment"> Point d'attache non valide </string> @@ -2227,12 +2281,12 @@ Veuillez réessayer de vous connecter dans une minute. <string name="ATTACH_BELLY"> Ventre </string> - <string name="ATTACH_RPEC"> - Pectoral droit - </string> - <string name="ATTACH_LPEC"> + <string name="ATTACH_LEFT_PEC"> Pectoral gauche </string> + <string name="ATTACH_RIGHT_PEC"> + Pectoral droit + </string> <string name="ATTACH_HUD_CENTER_2"> HUD centre 2 </string> @@ -2263,6 +2317,51 @@ Veuillez réessayer de vous connecter dans une minute. <string name="ATTACH_AVATAR_CENTER"> Centre de l'avatar </string> + <string name="ATTACH_LHAND_RING1"> + Annulaire gauche + </string> + <string name="ATTACH_RHAND_RING1"> + Annulaire droit + </string> + <string name="ATTACH_TAIL_BASE"> + Base de la queue + </string> + <string name="ATTACH_TAIL_TIP"> + Bout de la queue + </string> + <string name="ATTACH_LWING"> + Aile gauche + </string> + <string name="ATTACH_RWING"> + Aile droite + </string> + <string name="ATTACH_FACE_JAW"> + Mâchoire + </string> + <string name="ATTACH_FACE_LEAR"> + Oreille gauche différente + </string> + <string name="ATTACH_FACE_REAR"> + Oreille droite différente + </string> + <string name="ATTACH_FACE_LEYE"> + Œil gauche différent + </string> + <string name="ATTACH_FACE_REYE"> + Œil droit différent + </string> + <string name="ATTACH_FACE_TONGUE"> + Langue + </string> + <string name="ATTACH_GROIN"> + Aine + </string> + <string name="ATTACH_HIND_LFOOT"> + Pied arrière gauche + </string> + <string name="ATTACH_HIND_RFOOT"> + Pied arrière droit + </string> <string name="CursorPos"> Ligne [LINE], colonne [COLUMN] </string> @@ -4252,6 +4351,12 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE]. <string name="OfflineStatus"> Hors ligne </string> + <string name="not_online_msg"> + Utilisateur non connecté - le message sera enregistré et livré plus tard. + </string> + <string name="not_online_inventory"> + Utilisateur non connecté - l'inventaire a été enregistré + </string> <string name="answered_call"> Votre appel a fait l'objet d'une réponse </string> diff --git a/indra/newview/skins/default/xui/it/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/it/floater_preferences_graphics_advanced.xml index 5baba9fced..0568891264 100644 --- a/indra/newview/skins/default/xui/it/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/it/floater_preferences_graphics_advanced.xml @@ -15,7 +15,7 @@ <text name="AvatarText"> Avatar </text> - <slider label="Complessità massima:" name="IndirectMaxComplexity" tool_tip="Definisce il punto in cui un avatar dall'aspetto complesso viene visualizzato come una forma senza dettagli"/> + <slider label="Complessità massima:" name="IndirectMaxComplexity" tool_tip="Definisce il punto in cui un avatar dall'aspetto complesso viene visualizzato come JellyDoll"/> <text name="IndirectMaxComplexityText"> 0 </text> diff --git a/indra/newview/skins/default/xui/it/menu_attachment_other.xml b/indra/newview/skins/default/xui/it/menu_attachment_other.xml index 60cdd2a91d..5c017a92b5 100644 --- a/indra/newview/skins/default/xui/it/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/it/menu_attachment_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="Chiama" name="Call"/> <menu_item_call label="Invita al gruppo" name="Invite..."/> + <menu_item_call label="Ripristina scheletro" name="Reset Skeleton"/> <menu_item_call label="Blocca" name="Avatar Mute"/> <menu_item_call label="Segnala" name="abuse"/> <menu_item_call label="Congela" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/it/menu_attachment_self.xml b/indra/newview/skins/default/xui/it/menu_attachment_self.xml index 1539fbafa1..b1ca55b093 100644 --- a/indra/newview/skins/default/xui/it/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/it/menu_attachment_self.xml @@ -9,6 +9,7 @@ <menu_item_call label="Modifica il mio vestiario" name="Edit Outfit"/> <menu_item_call label="Modifica la figura corporea" name="Edit My Shape"/> <menu_item_call label="Altezza di volo" name="Hover Height"/> + <menu_item_call label="Ripristina scheletro" name="Reset Skeleton"/> <menu_item_call label="I miei amici..." name="Friends..."/> <menu_item_call label="I miei gruppi" name="Groups..."/> <menu_item_call label="Il mio profilo" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/it/menu_avatar_other.xml b/indra/newview/skins/default/xui/it/menu_avatar_other.xml index 7042e52943..12e808195e 100644 --- a/indra/newview/skins/default/xui/it/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/it/menu_avatar_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="Chiama" name="Call"/> <menu_item_call label="Invita al gruppo" name="Invite..."/> + <menu_item_call label="Ripristina scheletro" name="Reset Skeleton"/> <menu_item_call label="Blocca" name="Avatar Mute"/> <menu_item_call label="Segnala" name="abuse"/> <menu_item_call label="Congela" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/it/menu_avatar_self.xml b/indra/newview/skins/default/xui/it/menu_avatar_self.xml index 0c9663fd4c..e48449a04c 100644 --- a/indra/newview/skins/default/xui/it/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/it/menu_avatar_self.xml @@ -26,6 +26,7 @@ <menu_item_call label="Modifica il mio vestiario" name="Edit Outfit"/> <menu_item_call label="Modifica la figura corporea" name="Edit My Shape"/> <menu_item_call label="Altezza di volo" name="Hover Height"/> + <menu_item_call label="Ripristina scheletro" name="Reset Skeleton"/> <menu_item_call label="I miei amici..." name="Friends..."/> <menu_item_call label="I miei gruppi" name="Groups..."/> <menu_item_call label="Il mio profilo" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml index d52b022c49..90ea601259 100644 --- a/indra/newview/skins/default/xui/it/menu_viewer.xml +++ b/indra/newview/skins/default/xui/it/menu_viewer.xml @@ -22,7 +22,6 @@ <menu_item_check label="Non disturbare" name="Do Not Disturb"/> </menu> <menu_item_call label="Acquista L$..." name="Buy and Sell L$"/> - <menu_item_call label="Casella venditore in uscita..." name="MerchantOutbox"/> <menu_item_call label="Annunci Marketplace..." name="MarketplaceListings"/> <menu_item_call label="Dashboard dell'account..." name="Manage My Account"> <menu_item_call.on_click name="ManageMyAccount_url" parameter="WebLaunchJoinNow,http://secondlife.com/account/index.php?lang=it"/> @@ -368,6 +367,7 @@ <menu_item_check label="Informazioni sull'animazione" name="Animation Info"/> <menu_item_check label="Disabilita livello di dettaglio" name="Disable LOD"/> <menu_item_check label="Mostra schemi collisione" name="Show Collision Skeleton"/> + <menu_item_check label="Mostra ossa" name="Show Bones"/> <menu_item_check label="Mostra bersaglio" name="Display Agent Target"/> <menu_item_call label="Debug texture dell'avatar" name="Debug Avatar Textures"/> </menu> diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml index 358f38a137..3a29e4d32f 100644 --- a/indra/newview/skins/default/xui/it/notifications.xml +++ b/indra/newview/skins/default/xui/it/notifications.xml @@ -480,6 +480,9 @@ Superato il limite di oggetti collegati [MAX_ATTACHMENTS]. Per favore prima stac <notification name="CannotWearInfoNotComplete"> Non puoi indossare quell'elemento perchè non è ancora stato caricato. Riprova fra un minuto. </notification> + <notification name="MustEnterPasswordToLogIn"> + Inserisci la tua password per accedere. + </notification> <notification name="MustHaveAccountToLogIn"> Spiacenti. Un campo è vuoto. Inserisci il Nome utente del tuo avatar. @@ -548,6 +551,9 @@ Nota: questa operazione cancellerà la cache. <notification name="ChangeConnectionPort"> Le impostazioni della porta avranno effetto dopo il riavvio di [APP_NAME]. </notification> + <notification name="ChangeDeferredDebugSetting"> + La modifica della impostazione di debug avrà effetto dopo il riavvio di [APP_NAME]. + </notification> <notification name="ChangeSkin"> La nuova pelle comparirà dopo il riavvio di [APP_NAME]. </notification> @@ -1366,12 +1372,13 @@ Puoi comunque usare [SECOND_LIFE] normalmente e gli altri residenti ti vedranno <ignore name="ignore" text="Lo scaricamento sta richiedendo parecchio tempo"/> </form> </notification> - <notification name="RegionAndAgentComplexity"> - La tua [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complessità visiva] è [AGENT_COMPLEXITY]. + <notification name="AgentComplexityWithVisibility"> + La [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complessità del tuo avatar] è [AGENT_COMPLEXITY]. [OVERLIMIT_MSG] + <usetemplate ignoretext="Avvisami se la complessità del mio avatar è eccessiva" name="notifyignore"/> </notification> <notification name="AgentComplexity"> - La tua [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complessità visiva] è [AGENT_COMPLEXITY]. + La [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complessità del tuo avatar] è [AGENT_COMPLEXITY]. </notification> <notification name="FirstRun"> L'installazione di [APP_NAME] è terminata. @@ -1486,6 +1493,10 @@ Sostituisci la texture [TEXTURE_NUM] con una a 24-bit 512x512 oppure con una imm Vuoi veramente impostare come base il terreno corrente, impostarlo come riferimento per i limiti dei rialzi/abbassamenti di tutto il territorio ed il suo valore impostato come base per lo strumento 'Ripristina'? <usetemplate name="okcancelbuttons" notext="Annulla" yestext="OK"/> </notification> + <notification name="ConfirmTextureHeights"> + Stai per usare valori bassi maggiori dei valori alti di Intervalli altitudine. Vuoi procedere? + <usetemplate canceltext="Non chiedere" name="yesnocancelbuttons" notext="Annulla" yestext="OK"/> + </notification> <notification name="MaxAllowedAgentOnRegion"> Puoi avere al massimo [MAX_AGENTS] residenti consentiti. </notification> @@ -1724,14 +1735,6 @@ Lasciare il gruppo? Impossibile abbandonare il gruppo. Non puoi abbandonare il gruppo perché sei l'ultimo proprietario del gruppo. Devi prima assegnare a un altro membro il ruolo di proprietario. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="GroupDepartError"> - Impossibile abbandonare il gruppo: [reason]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> - <notification name="GroupDepart"> - Hai abbandonato il gruppo [group_name]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> <notification name="ConfirmKick"> Vuoi veramente espellere tutti i residenti dalla griglia? <usetemplate name="okcancelbuttons" notext="Annulla" yestext="Espelli tutti i residenti"/> @@ -2406,6 +2409,10 @@ Vuoi disattivare la modalità Non disturbare prima di completare questa transazi Vuoi veramente eliminare in modo permanente il contenuto del tuo Cestino? <usetemplate ignoretext="Conferma prima di svuotare la cartella del Cestino inventario" name="okcancelignore" notext="Annulla" yestext="OK"/> </notification> + <notification name="TrashIsFull"> + Il cestino è troppo pieno. Ciò potrebbe causare problemi durante l'accesso. + <usetemplate name="okcancelbuttons" notext="Svuota il cestino più tardi" yestext="Svuota il cestino adesso"/> + </notification> <notification name="ConfirmClearBrowserCache"> Vuoi veramente eliminare la cronologia viaggi, web e ricerche fatte? <usetemplate name="okcancelbuttons" notext="Annulla" yestext="OK"/> @@ -3262,11 +3269,15 @@ Per sicurezza, verranno bloccati per alcuni secondi. <notification name="AttachmentSaved"> L'elemento da collegare è stato salvato. </notification> - <notification name="PresetNotSaved"> - Errore durante il salvataggio del valore predefinito [NAME]. + <notification name="AppearanceToXMLSaved"> + L'aspetto è stato salvato in XML su [PATH] </notification> - <notification name="PresetNotDeleted"> - Errore durante l'eliminazione del valore predefinito [NAME]. + <notification name="AppearanceToXMLFailed"> + L'aspetto non è stato salvato in XML. + icon="notifytip.tga" + name="PresetNotDeleted" + type="notifytip"> +Errore nella cancellazione del valore predefinito [NAME]. </notification> <notification name="UnableToFindHelpTopic"> Impossibile trovare l'argomento nell'aiuto per questo elemento. @@ -4081,6 +4092,9 @@ Riprova tra un minuto. <notification name="CantAttachNotEnoughScriptResources"> Risorse di script non sufficienti per collegare l'oggetto. </notification> + <notification name="IllegalAttachment"> + Il collegamento ha richiesto un punto sull'avatar che non esiste. È stato collegato al petto. + </notification> <notification name="CantDropItemTrialUser"> Non puoi lasciare oggetti qui, prova la zona Prova gratuita. </notification> diff --git a/indra/newview/skins/default/xui/it/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/it/panel_preferences_alerts.xml index fd1fd57761..ca83490b02 100644 --- a/indra/newview/skins/default/xui/it/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/it/panel_preferences_alerts.xml @@ -3,8 +3,9 @@ <text name="tell_me_label"> Avvisami: </text> - <check_box label="Quando spendo o ottengo L$" name="notify_money_change_checkbox"/> + <check_box label="Quando spendo $" name="notify_money_spend_checkbox"/> <check_box label="Quando i miei amici entrano o escono da Second Life" name="friends_online_notify_checkbox"/> + <check_box label="Quando ottengo $" name="notify_money_received_checkbox"/> <text name="show_label"> Mostra sempre: </text> diff --git a/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml index a042c43431..4fa1835b0e 100644 --- a/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml @@ -24,10 +24,15 @@ <text name="BetterText"> Migliore </text> + <slider label="Massima conplessità dell'avatar:" name="IndirectMaxComplexity" tool_tip="Definisce il punto in cui un avatar dall'aspetto complesso viene visualizzato come JellyDoll"/> + <text name="IndirectMaxComplexityText"> + 0 + </text> <check_box initial_value="true" label="Shader atmosfera..." name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="Modello illuminazione avanzato" name="UseLightShaders"/> <button label="Salva impostazioni come valori predefiniti..." name="PrefSaveButton"/> <button label="Carica valore predefinito..." name="PrefLoadButton"/> + min_val="0.125" <button label="Elimina valore predefinito..." name="PrefDeleteButton"/> <button label="Ripristina impostazioni consigliate" name="Defaults"/> <button label="Impostazioni avanzate..." name="AdvancedSettings"/> diff --git a/indra/newview/skins/default/xui/it/panel_sound_devices.xml b/indra/newview/skins/default/xui/it/panel_sound_devices.xml index b1934fd515..83df46f381 100644 --- a/indra/newview/skins/default/xui/it/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/it/panel_sound_devices.xml @@ -16,9 +16,9 @@ Output </text> <text name="My volume label"> - Il mio volume: + Volume microfono: </text> - <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Cambia il volume utilizzando questa barra"/> + <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Cambia il livello del microfono utilizzando questa barra"/> <text name="wait_text"> Attendi </text> diff --git a/indra/newview/skins/default/xui/it/panel_status_bar.xml b/indra/newview/skins/default/xui/it/panel_status_bar.xml index 83d2ae5bab..295ca8d9f2 100644 --- a/indra/newview/skins/default/xui/it/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/it/panel_status_bar.xml @@ -5,7 +5,7 @@ <panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string> <panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string> <panel.string name="buycurrencylabel">L$ [AMT]</panel.string> - <panel left="-405" name="balance_bg" width="195"> + <panel left="-426" name="balance_bg" width="195"> <text name="balance" tool_tip="Clicca per aggiornare il tuo saldo in L$" value="L$ ??"/> <button label="Acquista L$" name="buyL" tool_tip="Clicca per acquistare più L$"/> <button label="Acquisti" name="goShop" tool_tip="Apri Mercato Second Life" width="75"/> diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index effd6f5040..bb2f221db9 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -38,6 +38,9 @@ [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL]) [[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]) SLURL: <nolink>[SLURL]</nolink> @@ -69,6 +72,9 @@ Versione server voce: [VOICE_VERSION] <string name="ErrorFetchingServerReleaseNotesURL"> Errore nel recupero URL note rilascio versione </string> + <string name="BuildConfiguration"> + Costruisci configurazione + </string> <string name="ProgressRestoring"> Ripristino in corso... </string> @@ -1381,6 +1387,9 @@ Prova ad accedere nuovamente tra un minuto. <string name="BodyPartsRightLeg"> Gamba destra </string> + <string name="BodyPartsEnhancedSkeleton"> + Scheletro avanzato + </string> <string name="GraphicsQualityLow"> Basso </string> @@ -1823,6 +1832,51 @@ Prova ad accedere nuovamente tra un minuto. <string name="Avatar Center"> Centro avatar </string> + <string name="Left Ring Finger"> + Anulare sinistro + </string> + <string name="Right Ring Finger"> + Anulare destro + </string> + <string name="Tail Base"> + Base della coda + </string> + <string name="Tail Tip"> + Punta della coda + </string> + <string name="Left Wing"> + Ala sinistra + </string> + <string name="Right Wing"> + Ala destra + </string> + <string name="Jaw"> + Mandibola + </string> + <string name="Alt Left Ear"> + Altro orecchio sinistro + </string> + <string name="Alt Right Ear"> + Altro orecchio destro + </string> + <string name="Alt Left Eye"> + Altro occhio sinistro + </string> + <string name="Alt Right Eye"> + Altro occhio destro + </string> + <string name="Tongue"> + Lingua + </string> + <string name="Groin"> + Inguine + </string> + <string name="Left Hind Foot"> + Piede posteriore sinistro + </string> + <string name="Right Hind Foot"> + Piede posteriore destro + </string> <string name="Invalid Attachment"> Punto di collegamento non valido </string> @@ -2212,12 +2266,12 @@ Prova ad accedere nuovamente tra un minuto. <string name="ATTACH_BELLY"> Addome </string> - <string name="ATTACH_RPEC"> - Petto destro - </string> - <string name="ATTACH_LPEC"> + <string name="ATTACH_LEFT_PEC"> Petto sinistro </string> + <string name="ATTACH_RIGHT_PEC"> + Petto destro + </string> <string name="ATTACH_HUD_CENTER_2"> HUD in centro 2 </string> @@ -2248,6 +2302,51 @@ Prova ad accedere nuovamente tra un minuto. <string name="ATTACH_AVATAR_CENTER"> Centro avatar </string> + <string name="ATTACH_LHAND_RING1"> + Anulare sinistro + </string> + <string name="ATTACH_RHAND_RING1"> + Anulare destro + </string> + <string name="ATTACH_TAIL_BASE"> + Base della coda + </string> + <string name="ATTACH_TAIL_TIP"> + Punta della coda + </string> + <string name="ATTACH_LWING"> + Ala sinistra + </string> + <string name="ATTACH_RWING"> + Ala destra + </string> + <string name="ATTACH_FACE_JAW"> + Mandibola + </string> + <string name="ATTACH_FACE_LEAR"> + Altro orecchio sinistro + </string> + <string name="ATTACH_FACE_REAR"> + Altro orecchio destro + </string> + <string name="ATTACH_FACE_LEYE"> + Altro occhio sinistro + </string> + <string name="ATTACH_FACE_REYE"> + Altro occhio destro + </string> + <string name="ATTACH_FACE_TONGUE"> + Lingua + </string> + <string name="ATTACH_GROIN"> + Inguine + </string> + <string name="ATTACH_HIND_LFOOT"> + Piede posteriore sinistro + </string> + <string name="ATTACH_HIND_RFOOT"> + Piede posteriore destro + </string> <string name="CursorPos"> Riga [LINE], Colonna [COLUMN] </string> @@ -4174,6 +4273,12 @@ Se il messaggio persiste, contatta [SUPPORT_SITE]. <string name="OfflineStatus"> Offline </string> + <string name="not_online_msg"> + Utente non online - il messaggio verrà memorizzato e inviato più tardi. + </string> + <string name="not_online_inventory"> + Utente non online - l'inventario è stato salvato + </string> <string name="answered_call"> Risposto alla chiamata </string> diff --git a/indra/newview/skins/default/xui/ja/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/ja/floater_preferences_graphics_advanced.xml index a95c45c275..db4e086c13 100644 --- a/indra/newview/skins/default/xui/ja/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/ja/floater_preferences_graphics_advanced.xml @@ -15,7 +15,7 @@ <text name="AvatarText"> アバター </text> - <slider label="最大の複雑さ:" name="IndirectMaxComplexity" tool_tip="どの時点で複雑な表示のアバターをベタ色の人形として表示するかを管理します"/> + <slider label="最大の複雑さ:" name="IndirectMaxComplexity" tool_tip="どの点で視覚的に複雑なアバターを JellyDoll として描くかを制御します"/> <text name="IndirectMaxComplexityText"> 0 </text> diff --git a/indra/newview/skins/default/xui/ja/menu_attachment_other.xml b/indra/newview/skins/default/xui/ja/menu_attachment_other.xml index 7705dd9090..78c36a4392 100644 --- a/indra/newview/skins/default/xui/ja/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/ja/menu_attachment_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="コール" name="Call"/> <menu_item_call label="グループに招待" name="Invite..."/> + <menu_item_call label="スケルトンをリセット" name="Reset Skeleton"/> <menu_item_call label="ブロック" name="Avatar Mute"/> <menu_item_call label="報告" name="abuse"/> <menu_item_call label="フリーズ" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/ja/menu_attachment_self.xml b/indra/newview/skins/default/xui/ja/menu_attachment_self.xml index e7aa3cfc30..ba46f91504 100644 --- a/indra/newview/skins/default/xui/ja/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/ja/menu_attachment_self.xml @@ -9,6 +9,7 @@ <menu_item_call label="アウトフィットの編集" name="Edit Outfit"/> <menu_item_call label="シェイプの編集" name="Edit My Shape"/> <menu_item_call label="ホバー高さ" name="Hover Height"/> + <menu_item_call label="スケルトンをリセット" name="Reset Skeleton"/> <menu_item_call label="フレンド" name="Friends..."/> <menu_item_call label="グループ" name="Groups..."/> <menu_item_call label="プロフィール" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/ja/menu_avatar_other.xml b/indra/newview/skins/default/xui/ja/menu_avatar_other.xml index 482f2bdaa5..b7e0537866 100644 --- a/indra/newview/skins/default/xui/ja/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/ja/menu_avatar_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="コール" name="Call"/> <menu_item_call label="グループに招待" name="Invite..."/> + <menu_item_call label="スケルトンをリセット" name="Reset Skeleton"/> <menu_item_call label="ブロック" name="Avatar Mute"/> <menu_item_call label="報告" name="abuse"/> <menu_item_call label="フリーズ" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/ja/menu_avatar_self.xml b/indra/newview/skins/default/xui/ja/menu_avatar_self.xml index a14cfd5876..a3847ed555 100644 --- a/indra/newview/skins/default/xui/ja/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/ja/menu_avatar_self.xml @@ -26,6 +26,7 @@ <menu_item_call label="アウトフィットを編集" name="Edit Outfit"/> <menu_item_call label="シェイプを編集" name="Edit My Shape"/> <menu_item_call label="ホバー高さ" name="Hover Height"/> + <menu_item_call label="スケルトンをリセット" name="Reset Skeleton"/> <menu_item_call label="フレンド" name="Friends..."/> <menu_item_call label="グループ" name="Groups..."/> <menu_item_call label="プロフィール" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml index 3c2e294868..c2ae77bef2 100644 --- a/indra/newview/skins/default/xui/ja/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml @@ -22,7 +22,6 @@ <menu_item_check label="着信拒否" name="Do Not Disturb"/> </menu> <menu_item_call label="L$ の購入..." name="Buy and Sell L$"/> - <menu_item_call label="マーチャントアウトボックス..." name="MerchantOutbox"/> <menu_item_call label="マーケティングプレイスのリスト..." name="MarketplaceListings"/> <menu_item_call label="マイアカウント..." name="Manage My Account"> <menu_item_call.on_click name="ManageMyAccount_url" parameter="WebLaunchJoinNow,http://secondlife.com/account/index.php?lang=ja"/> @@ -421,6 +420,7 @@ <menu_item_check label="LOD を無効にする" name="Disable LOD"/> <menu_item_check label="キャラクター Vis のデバッグ" name="Debug Character Vis"/> <menu_item_check label="骨組みの衝突判定を表示する" name="Show Collision Skeleton"/> + <menu_item_check label="骨を表示" name="Show Bones"/> <menu_item_check label="エージェントのターゲットを表示する" name="Display Agent Target"/> <menu_item_call label="アタッチメントをダンプ" name="Dump Attachments"/> <menu_item_call label="アバターテクスチャをデバッグ" name="Debug Avatar Textures"/> diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml index a573e86e5f..54e5f29621 100644 --- a/indra/newview/skins/default/xui/ja/notifications.xml +++ b/indra/newview/skins/default/xui/ja/notifications.xml @@ -498,6 +498,9 @@ L$ が不足しているのでこのグループに参加することができ <notification name="CannotWearInfoNotComplete"> まだ読み込まれていないため、そのアイテムを装着できません。後でやり直してください。 </notification> + <notification name="MustEnterPasswordToLogIn"> + ログインするためにパスワードを入力してください + </notification> <notification name="MustHaveAccountToLogIn"> 注意:記入漏れの箇所があります。 アバターのユーザー名を入力してください。 @@ -566,6 +569,9 @@ L$ が不足しているのでこのグループに参加することができ <notification name="ChangeConnectionPort"> ポートの設定は [APP_NAME] を再起動後に反映されます。 </notification> + <notification name="ChangeDeferredDebugSetting"> + デバッグ設定の変更は [APP_NAME] を再起動後に反映されます。 + </notification> <notification name="ChangeSkin"> 新しいスキンは [APP_NAME] を再起動後に表示されます。 </notification> @@ -1395,12 +1401,13 @@ https://wiki.secondlife.com/wiki/Adding_Spelling_Dictionaries を参照してく <ignore name="ignore" text="衣類がダウンロードされるまで時間がかかっているとき"/> </form> </notification> - <notification name="RegionAndAgentComplexity"> - ご使用の [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 表示の複雑さ] は [AGENT_COMPLEXITY] です。 + <notification name="AgentComplexityWithVisibility"> + あなたの [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 avatar complexity] は [AGENT_COMPLEXITY] です。 [OVERLIMIT_MSG] + <usetemplate ignoretext="アバターの複雑度が高すぎる場合は警告する" name="notifyignore"/> </notification> <notification name="AgentComplexity"> - ご使用の [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 表示の複雑さ] は [AGENT_COMPLEXITY] です。 + あなたの [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 avatar complexity] は [AGENT_COMPLEXITY] です。 </notification> <notification name="FirstRun"> [APP_NAME] のインストールが完了しました。 @@ -1519,6 +1526,10 @@ SHA1 フィンガープリント: [MD5_DIGEST] 操作を続行しますか? <usetemplate name="okcancelbuttons" notext="取り消し" yestext="OK"/> </notification> + <notification name="ConfirmTextureHeights"> + 使用しようとしている隆起範囲の低い値は高い値よりも大きくなっています。それでも続けますか? + <usetemplate canceltext="聞かないでください" name="yesnocancelbuttons" notext="取り消し" yestext="Ok"/> + </notification> <notification name="MaxAllowedAgentOnRegion"> 許可住人は [MAX_AGENTS] 人までです。 </notification> @@ -1754,14 +1765,6 @@ http://secondlife.com/download から最新バージョンをダウンロード グループを抜けることができません。グループの最後のオーナーであるため、グループを抜けることができません。最初に、別のメンバーをオーナーの役割に割り当ててください。 <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="GroupDepartError"> - グループを抜けることができません: [reason]。 - <usetemplate name="okbutton" yestext="OK"/> - </notification> - <notification name="GroupDepart"> - グループ [group_name] を抜けました。 - <usetemplate name="okbutton" yestext="OK"/> - </notification> <notification name="ConfirmKick"> 本当に住人全員をグリッドから追い出しますか? <usetemplate name="okcancelbuttons" notext="キャンセル" yestext="住人全員を追い出す"/> @@ -2442,6 +2445,10 @@ Linden Lab ごみ箱の中身をすべて削除しますか? <usetemplate ignoretext="インベントリのごみ箱フォルダを空にする前の確認" name="okcancelignore" notext="キャンセル" yestext="OK"/> </notification> + <notification name="TrashIsFull"> + ゴミ箱があふれています。これはログイン時に問題を引き起こします。 + <usetemplate name="okcancelbuttons" notext="後でゴミ箱を空にする" yestext="今すぐゴミ箱を空にする"/> + </notification> <notification name="ConfirmClearBrowserCache"> トラベル、Web、検索の履歴をすべて削除しますか? <usetemplate name="okcancelbuttons" notext="キャンセル" yestext="OK"/> @@ -3032,7 +3039,7 @@ Web ページにリンクすると、他人がこの場所に簡単にアクセ [MESSAGE] -送信元のオブジェクト:<nolink>[OBJECTNAME]</nolink>、所有者:[NAME_SLURL] +送信元のオブジェクト:<nolink>[OBJECTNAME]</nolink>、所有者:[NAME_SLURL] <form name="form"> <button name="Gotopage" text="ページに移動"/> <button name="Cancel" text="取り消し"/> @@ -3298,11 +3305,15 @@ M キーを押して変更します。 <notification name="AttachmentSaved"> アタッチメントが保存されました。 </notification> - <notification name="PresetNotSaved"> - プリセット [NAME] の保存中にエラーが発生しました。 + <notification name="AppearanceToXMLSaved"> + 外観が XML で [PATH] に保存されました </notification> - <notification name="PresetNotDeleted"> - プリセット [NAME] の削除中にエラーが発生しました。 + <notification name="AppearanceToXMLFailed"> + 外観を XML に保存できませんでした。 + icon="notifytip.tga" + name="PresetNotDeleted" + type="notifytip"> +プリセット [NAME] の削除エラー。 </notification> <notification name="UnableToFindHelpTopic"> ヘルプトピックが見つかりませんでした。 @@ -4111,6 +4122,9 @@ M キーを押して変更します。 <notification name="CantAttachNotEnoughScriptResources"> オブジェクトの着用に使用できるスクリプトリソースが足りません。 </notification> + <notification name="IllegalAttachment"> + 添付ファイルはアバターの存在しない点を要求しました。代わりに胸に添付されていました。 + </notification> <notification name="CantDropItemTrialUser"> オブジェクトをここにドロップできません。フリートライアル領域をお試しください。 </notification> diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/ja/panel_preferences_alerts.xml index 7fd2e31698..4c2906cc18 100644 --- a/indra/newview/skins/default/xui/ja/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/ja/panel_preferences_alerts.xml @@ -3,8 +3,9 @@ <text name="tell_me_label"> 知らせる: </text> - <check_box label="リンデンドルを使用・受け取るとき" name="notify_money_change_checkbox"/> + <check_box label="L$ を使用する場合" name="notify_money_spend_checkbox"/> <check_box label="フレンドがログイン・ログアウトするとき" name="friends_online_notify_checkbox"/> + <check_box label="L$ を手に入れる場合" name="notify_money_received_checkbox"/> <text name="show_label" width="300"> 常に表示するメッセージ: </text> diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml index 8fbe9b56b9..61d914135d 100644 --- a/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml @@ -24,10 +24,15 @@ <text name="BetterText"> 遅い </text> + <slider label="アバターの最大複雑度:" name="IndirectMaxComplexity" tool_tip="どの点で視覚的に複雑なアバターを JellyDoll として描くかを制御します"/> + <text name="IndirectMaxComplexityText"> + 0 + </text> <check_box initial_value="true" label="周囲 (大気) シェーダー" name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="高度なライティングモデル" name="UseLightShaders"/> <button label="設定をプリセットとして保存..." name="PrefSaveButton"/> <button label="プリセットをロード..." name="PrefLoadButton"/> + min_val="0.125" <button label="事前設定を削除..." name="PrefDeleteButton"/> <button label="推奨設定にリセット" name="Defaults"/> <button label="詳細設定..." name="AdvancedSettings"/> diff --git a/indra/newview/skins/default/xui/ja/panel_sound_devices.xml b/indra/newview/skins/default/xui/ja/panel_sound_devices.xml index 0824504235..d57e6c796c 100644 --- a/indra/newview/skins/default/xui/ja/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/ja/panel_sound_devices.xml @@ -16,9 +16,9 @@ 出力 </text> <text name="My volume label"> - 私の音量: + マイク音量: </text> - <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="スライダーを使って音量を調節します"/> + <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="スライダーを使ってマイクレベルを調節します"/> <text name="wait_text"> しばらくお待ちください。 </text> diff --git a/indra/newview/skins/default/xui/ja/panel_status_bar.xml b/indra/newview/skins/default/xui/ja/panel_status_bar.xml index 2e1446d450..3f3845e491 100644 --- a/indra/newview/skins/default/xui/ja/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/ja/panel_status_bar.xml @@ -5,7 +5,7 @@ <panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string> <panel.string name="timeTooltip">[year, datetime, slt] [month, datetime, slt] [day, datetime, slt] ([weekday, datetime, slt])</panel.string> <panel.string name="buycurrencylabel">L$ [AMT]</panel.string> - <panel left="-370" name="balance_bg" width="160"> + <panel left="-391" name="balance_bg" width="160"> <text name="balance" tool_tip="クリックして L$ 残高を更新" value="L$??"/> <button label="L$ の購入" name="buyL" tool_tip="クリックして L$ を購入します"/> <button label="店" name="goShop" tool_tip="Second Life マーケットプレイスを開く" width="40"/> diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index 1ad977fe88..904ce3880a 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -38,7 +38,11 @@ グラフィックを初期化できませんでした。グラフィックドライバを更新してください。 </string> <string name="AboutHeader"> - [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL])[[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]] + [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL]) +[[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]] + </string> + <string name="BuildConfig"> + ビルド構成 [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]) @@ -62,8 +66,8 @@ OS バージョン:[OS_VERSION] J2C デコーダバージョン:[J2C_VERSION] オーディオドライババージョン:[AUDIO_DRIVER_VERSION] -LLCEFLib/CEF バージョン: [LLCEFLIB_VERSION] -ボイスサーバーバージョン: [VOICE_VERSION] +LLCEFLib/CEF バージョン: [LLCEFLIB_VERSION] +ボイスサーバーバージョン:[VOICE_VERSION] </string> <string name="AboutTraffic"> パケットロス:[PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%) @@ -71,6 +75,9 @@ LLCEFLib/CEF バージョン: [LLCEFLIB_VERSION] <string name="ErrorFetchingServerReleaseNotesURL"> サーバーのリリースノートの URL を取得中にエラーが発生しました。 </string> + <string name="BuildConfiguration"> + ビルド構成 + </string> <string name="ProgressRestoring"> 復元中です... </string> @@ -1389,6 +1396,9 @@ support@secondlife.com にお問い合わせください。 <string name="BodyPartsRightLeg"> 右脚 </string> + <string name="BodyPartsEnhancedSkeleton"> + 拡張スケルトン + </string> <string name="GraphicsQualityLow"> 低 </string> @@ -1837,6 +1847,51 @@ support@secondlife.com にお問い合わせください。 <string name="Avatar Center"> アバターの中央 </string> + <string name="Left Ring Finger"> + 左薬指 + </string> + <string name="Right Ring Finger"> + 右薬指 + </string> + <string name="Tail Base"> + しっぽのベース + </string> + <string name="Tail Tip"> + しっぽの先 + </string> + <string name="Left Wing"> + 左の翼 + </string> + <string name="Right Wing"> + 右の翼 + </string> + <string name="Jaw"> + 顎 + </string> + <string name="Alt Left Ear"> + 代わりの左耳 + </string> + <string name="Alt Right Ear"> + 代わりの右耳 + </string> + <string name="Alt Left Eye"> + 代わりの左目 + </string> + <string name="Alt Right Eye"> + 代わりの右目 + </string> + <string name="Tongue"> + 舌 + </string> + <string name="Groin"> + 脚の付け根 + </string> + <string name="Left Hind Foot"> + 左後足 + </string> + <string name="Right Hind Foot"> + 右後足 + </string> <string name="Invalid Attachment"> 装着先が正しくありません </string> @@ -2226,12 +2281,12 @@ support@secondlife.com にお問い合わせください。 <string name="ATTACH_BELLY"> お腹 </string> - <string name="ATTACH_RPEC"> - 右胸筋 - </string> - <string name="ATTACH_LPEC"> + <string name="ATTACH_LEFT_PEC"> 左胸筋 </string> + <string name="ATTACH_RIGHT_PEC"> + 右胸筋 + </string> <string name="ATTACH_HUD_CENTER_2"> HUD(中央 2) </string> @@ -2262,6 +2317,51 @@ support@secondlife.com にお問い合わせください。 <string name="ATTACH_AVATAR_CENTER"> アバターの中央 </string> + <string name="ATTACH_LHAND_RING1"> + 左薬指 + </string> + <string name="ATTACH_RHAND_RING1"> + 右薬指 + </string> + <string name="ATTACH_TAIL_BASE"> + しっぽのベース + </string> + <string name="ATTACH_TAIL_TIP"> + しっぽの先 + </string> + <string name="ATTACH_LWING"> + 左の翼 + </string> + <string name="ATTACH_RWING"> + 右の翼 + </string> + <string name="ATTACH_FACE_JAW"> + 顎 + </string> + <string name="ATTACH_FACE_LEAR"> + 代わりの左耳 + </string> + <string name="ATTACH_FACE_REAR"> + 代わりの右耳 + </string> + <string name="ATTACH_FACE_LEYE"> + 代わりの左目 + </string> + <string name="ATTACH_FACE_REYE"> + 代わりの右目 + </string> + <string name="ATTACH_FACE_TONGUE"> + 舌 + </string> + <string name="ATTACH_GROIN"> + 脚の付け根 + </string> + <string name="ATTACH_HIND_LFOOT"> + 左後足 + </string> + <string name="ATTACH_HIND_RFOOT"> + 右後足 + </string> <string name="CursorPos"> [LINE] 行目、[COLUMN] 列目 </string> @@ -4251,6 +4351,12 @@ www.secondlife.com から最新バージョンをダウンロードしてくだ <string name="OfflineStatus"> オフライン </string> + <string name="not_online_msg"> + ユーザーがオンラインでありません - メッセージは保存され、後で配信されます。 + </string> + <string name="not_online_inventory"> + ユーザーがオンラインでありません - インベントリが保存されました。 + </string> <string name="answered_call"> 相手がコールを受けました </string> diff --git a/indra/newview/skins/default/xui/pt/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/pt/floater_preferences_graphics_advanced.xml index c5e19b2281..6fa25262ea 100644 --- a/indra/newview/skins/default/xui/pt/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/pt/floater_preferences_graphics_advanced.xml @@ -15,7 +15,7 @@ <text name="AvatarText"> Avatar </text> - <slider label="Complexidade máxima:" name="IndirectMaxComplexity" tool_tip="Controla o ponto no qual um avatar visualmente complexo é desenhado como avatar de cor sólida"/> + <slider label="Complexidade máxima:" name="IndirectMaxComplexity" tool_tip="Controla o ponto no qual um avatar visualmente complexo é desenhado como uma JellyDoll"/> <text name="IndirectMaxComplexityText"> 0 </text> diff --git a/indra/newview/skins/default/xui/pt/menu_attachment_other.xml b/indra/newview/skins/default/xui/pt/menu_attachment_other.xml index 031f6b605a..760197cfb9 100644 --- a/indra/newview/skins/default/xui/pt/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/pt/menu_attachment_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="MI" name="Send IM..."/> <menu_item_call label="Ligar" name="Call"/> <menu_item_call label="Convidar para entrar no grupo" name="Invite..."/> + <menu_item_call label="Redefinir esqueleto" name="Reset Skeleton"/> <menu_item_call label="Bloquear" name="Avatar Mute"/> <menu_item_call label="Denunciar" name="abuse"/> <menu_item_call label="Congelar" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/pt/menu_attachment_self.xml b/indra/newview/skins/default/xui/pt/menu_attachment_self.xml index ac79422110..766c8b9754 100644 --- a/indra/newview/skins/default/xui/pt/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/pt/menu_attachment_self.xml @@ -9,6 +9,7 @@ <menu_item_call label="Editar meu look" name="Edit Outfit"/> <menu_item_call label="Editar meu corpo" name="Edit My Shape"/> <menu_item_call label="Altura de foco" name="Hover Height"/> + <menu_item_call label="Redefinir esqueleto" name="Reset Skeleton"/> <menu_item_call label="Meus amigos" name="Friends..."/> <menu_item_call label="Meus grupos" name="Groups..."/> <menu_item_call label="Meu perfil" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/pt/menu_avatar_other.xml b/indra/newview/skins/default/xui/pt/menu_avatar_other.xml index e32f9059f5..170525cbe6 100644 --- a/indra/newview/skins/default/xui/pt/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/pt/menu_avatar_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="MI" name="Send IM..."/> <menu_item_call label="Ligar" name="Call"/> <menu_item_call label="Convidar para entrar no grupo" name="Invite..."/> + <menu_item_call label="Redefinir esqueleto" name="Reset Skeleton"/> <menu_item_call label="Bloquear" name="Avatar Mute"/> <menu_item_call label="Denunciar" name="abuse"/> <menu_item_call label="Congelar" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/pt/menu_avatar_self.xml b/indra/newview/skins/default/xui/pt/menu_avatar_self.xml index a0ac71e018..e826a57b46 100644 --- a/indra/newview/skins/default/xui/pt/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/pt/menu_avatar_self.xml @@ -26,6 +26,7 @@ <menu_item_call label="Editar meu look" name="Edit Outfit"/> <menu_item_call label="Editar meu corpo" name="Edit My Shape"/> <menu_item_call label="Altura de foco" name="Hover Height"/> + <menu_item_call label="Redefinir esqueleto" name="Reset Skeleton"/> <menu_item_call label="Meus amigos" name="Friends..."/> <menu_item_call label="Meus grupos" name="Groups..."/> <menu_item_call label="Meu perfil" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml index 2df78c6287..7bdcb74a54 100644 --- a/indra/newview/skins/default/xui/pt/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml @@ -22,7 +22,6 @@ <menu_item_check label="Não perturbe" name="Do Not Disturb"/> </menu> <menu_item_call label="Comprar L$..." name="Buy and Sell L$"/> - <menu_item_call label="Caixa de saída do lojista..." name="MerchantOutbox"/> <menu_item_call label="Listagens do Marketplace..." name="MarketplaceListings"/> <menu_item_call label="Painel da conta..." name="Manage My Account"> <menu_item_call.on_click name="ManageMyAccount_url" parameter="WebLaunchJoinNow,http://secondlife.com/account/index.php?lang=pt"/> @@ -368,6 +367,7 @@ <menu_item_check label="Dados da animação" name="Animation Info"/> <menu_item_check label="Disable Level Of Detail" name="Disable LOD"/> <menu_item_check label="Show Collision Skeleton" name="Show Collision Skeleton"/> + <menu_item_check label="Exibir ossos" name="Show Bones"/> <menu_item_check label="Display Agent Target" name="Display Agent Target"/> <menu_item_call label="Depurar texturas do avatar" name="Debug Avatar Textures"/> </menu> diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index cf7400117d..bb428ad5a5 100644 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -477,6 +477,9 @@ Ele ultrapassa o limite de anexos, de [MAX_ATTACHMENTS] objetos. Remova um objet <notification name="CannotWearInfoNotComplete"> Você não pode vestir este item porque ele ainda não carregou. Tente novamente em um minuto. </notification> + <notification name="MustEnterPasswordToLogIn"> + Informe sua senha para fazer o login. + </notification> <notification name="MustHaveAccountToLogIn"> Opa! Alguma coisa ficou em branco. Digite o nome de usuário de seu avatar. @@ -545,6 +548,9 @@ Nota: Este procedimento limpa o cache. <notification name="ChangeConnectionPort"> Reinicie o [APP_NAME] para ativar a reconfiguração da porta. </notification> + <notification name="ChangeDeferredDebugSetting"> + Essa alteração nas configurações de depuração será aplicada depois que você reiniciar o [APP_NAME]. + </notification> <notification name="ChangeSkin"> Reinicie o [APP_NAME] para ativar a pele nova. </notification> @@ -1359,12 +1365,13 @@ Enquando isso, use o [SECOND_LIFE] normalmente. Seu visual será exibido correta <ignore name="ignore" text="A roupa está demorando para chegar"/> </form> </notification> - <notification name="RegionAndAgentComplexity"> - Sua [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complexidade visual] é [AGENT_COMPLEXITY]. + <notification name="AgentComplexityWithVisibility"> + Sua [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 avatar complexity] é [AGENT_COMPLEXITY]. [OVERLIMIT_MSG] + <usetemplate ignoretext="Avise-me se a complexidade do meu avatar for muito alta" name="notifyignore"/> </notification> <notification name="AgentComplexity"> - Sua [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 complexidade visual] é [AGENT_COMPLEXITY]. + Sua [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 avatar complexity] é [AGENT_COMPLEXITY]. </notification> <notification name="FirstRun"> A instalação do [APP_NAME] está pronta. @@ -1478,6 +1485,10 @@ Substituir textura [TEXTURE_NUM], com uma imagem de 24-bit 512x512 ou menor e em Você realmente deseja nivelar o terreno selecionado a partir do centro elevando/reduzindo os limites e o padrão para a ferramenta ´Reverter´? <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Executar"/> </notification> + <notification name="ConfirmTextureHeights"> + Você está prestes a usar valores baixos maiores que os valores altos para os intervalos de elevação. Deseja prosseguir? + <usetemplate canceltext="Não perguntar" name="yesnocancelbuttons" notext="Cancelar" yestext="Ok"/> + </notification> <notification name="MaxAllowedAgentOnRegion"> Você pode ter somente [MAX_AGENTS] residentes permitidos. </notification> @@ -1714,14 +1725,6 @@ Se você estiver muito ansioso para experimentar os novos recursos e correções Não foi possível deixar o grupo. Você não pode deixar o grupo pois é o último proprietário dele. Primeiramente, atribua outro membro à função de proprietário. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="GroupDepartError"> - Não foi possível deixar o grupo: [reason]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> - <notification name="GroupDepart"> - Você deixou o grupo [group_name]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> <notification name="ConfirmKick"> Tem CERTEZA de que deseja expulsar todos os residentes do grid? <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Chutar todos"/> @@ -2393,6 +2396,10 @@ Deseja desativar o Não perturbe antes de concluir esta transação? Tem certeza de que deseja excluir o conteúdo da Lixeira? Para sempre? <usetemplate ignoretext="Confirmar antes de esvaziar a pasta Lixeira" name="okcancelignore" notext="Não" yestext="Sim"/> </notification> + <notification name="TrashIsFull"> + Sua lixeira está transbordando. Isso pode causar problemas no logon. + <usetemplate name="okcancelbuttons" notext="Esvaziarei a lixeira mais tarde" yestext="Esvaziar lixeira agora"/> + </notification> <notification name="ConfirmClearBrowserCache"> Tem certeza de que quer apagar todo o histórico de viagens, web e buscas? <usetemplate name="okcancelbuttons" notext="Não" yestext="OK"/> @@ -2977,7 +2984,7 @@ Se permanecer aqui, você será desconectado. [MESSAGE] -Do objeto: <nolink>[OBJECTNAME]</nolink>, de: [NAME_SLURL] +Do objeto: <nolink>[OBJECTNAME]</nolink>, proprietário: [NAME_SLURL] <form name="form"> <button name="Gotopage" text="Carregar"/> <button name="Cancel" text="Cancelar"/> @@ -3246,11 +3253,15 @@ Para sua segurança, os SLurls serão bloqueados por alguns instantes. <notification name="AttachmentSaved"> Anexo salvo. </notification> - <notification name="PresetNotSaved"> - Erro ao salvar predefinição [NAME]. + <notification name="AppearanceToXMLSaved"> + A aparência foi salva como XML em [PATH] </notification> - <notification name="PresetNotDeleted"> - Erro ao excluir a predefinição [NAME]. + <notification name="AppearanceToXMLFailed"> + Falha ao salvar a aparência como XML. + icon="notifytip.tga" + name="PresetNotDeleted" + type="notifytip"> +Erro ao excluir a predefinição [NAME]. </notification> <notification name="UnableToFindHelpTopic"> Nenhum tópico de ajuda foi encontrado com relação a este elemento. @@ -4063,6 +4074,9 @@ Tente novamente em instantes. <notification name="CantAttachNotEnoughScriptResources"> Não há recursos de script disponíveis suficientes para anexar objeto! </notification> + <notification name="IllegalAttachment"> + O anexo solicitou um ponto não existente no avatar. Ele foi anexado ao peito. + </notification> <notification name="CantDropItemTrialUser"> Não é possível largar objetos aqui. Tente a área de Avaliação grátis. </notification> diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/pt/panel_preferences_alerts.xml index 2ffe720ccf..c865de0d08 100644 --- a/indra/newview/skins/default/xui/pt/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/pt/panel_preferences_alerts.xml @@ -3,8 +3,9 @@ <text name="tell_me_label"> Avisar: </text> - <check_box label="Quando eu gasto ou recebo L$" name="notify_money_change_checkbox"/> + <check_box label="Quando eu gastar L$" name="notify_money_spend_checkbox"/> <check_box label="Quando meus amigos entram e saem" name="friends_online_notify_checkbox"/> + <check_box label="Quando eu receber L$" name="notify_money_received_checkbox"/> <text name="show_label"> Mostrar sempre: </text> diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml index 4d3fb89b37..fa17a4ff11 100644 --- a/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml @@ -25,10 +25,15 @@ rápido <text name="BetterText"> Melhor </text> + <slider label="Complexidade máxima do avatar:" name="IndirectMaxComplexity" tool_tip="Controla o ponto no qual um avatar visualmente complexo é desenhado como uma JellyDoll"/> + <text name="IndirectMaxComplexityText"> + 0 + </text> <check_box initial_value="true" label="Tonalidades atmosféricas" name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="Modelo avançado de luzes" name="UseLightShaders"/> <button label="Salvar configurações como predefinição..." name="PrefSaveButton"/> <button label="Carregar predefinição..." name="PrefLoadButton"/> + min_val="0.125" <button label="Excluir predefinição..." name="PrefDeleteButton"/> <button label="Redefinir para configurações recomendadas" left="110" name="Defaults"/> <button label="Configurações avançadas..." name="AdvancedSettings"/> diff --git a/indra/newview/skins/default/xui/pt/panel_sound_devices.xml b/indra/newview/skins/default/xui/pt/panel_sound_devices.xml index 66db89f48f..97d6c0ef36 100644 --- a/indra/newview/skins/default/xui/pt/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/pt/panel_sound_devices.xml @@ -16,9 +16,9 @@ Saída </text> <text name="My volume label"> - Meu volume: + Volume do microfone: </text> - <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Mude o volume usando o controle deslizante"/> + <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Mude o volume do microfone usando o controle deslizante"/> <text name="wait_text"> Aguarde </text> diff --git a/indra/newview/skins/default/xui/pt/panel_status_bar.xml b/indra/newview/skins/default/xui/pt/panel_status_bar.xml index cfe52ff404..c35863734f 100644 --- a/indra/newview/skins/default/xui/pt/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/pt/panel_status_bar.xml @@ -5,7 +5,7 @@ <panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string> <panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string> <panel.string name="buycurrencylabel">L$ [AMT]</panel.string> - <panel left="-410" name="balance_bg" width="200"> + <panel left="-431" name="balance_bg" width="200"> <text name="balance" tool_tip="Atualizar saldo de L$" value="L$??"/> <button label="Comprar L$" name="buyL" tool_tip="Comprar mais L$"/> <button label="Comprar" name="goShop" tool_tip="Abrir Mercado do Second Life" width="80"/> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index 50bb9b7e66..b3cb50a01e 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -30,7 +30,10 @@ </string> <string name="AboutHeader"> [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL]) -[[VIEWER_RELEASE_NOTES_URL] [Notas da versão]] +[[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]) @@ -63,6 +66,9 @@ Versão do servidor de voz: [VOICE_VERSION] <string name="ErrorFetchingServerReleaseNotesURL"> Erro ao obter URL de notas de versão do servidor. </string> + <string name="BuildConfiguration"> + Configuração do corpo + </string> <string name="ProgressRestoring"> Restaurando... </string> @@ -1336,6 +1342,9 @@ Pessoas com contas gratuitas não poderão acessar o Second Life no momento para <string name="BodyPartsRightLeg"> Perna direita </string> + <string name="BodyPartsEnhancedSkeleton"> + Esqueleto aprimorado + </string> <string name="GraphicsQualityLow"> Baixo </string> @@ -1778,6 +1787,51 @@ Pessoas com contas gratuitas não poderão acessar o Second Life no momento para <string name="Avatar Center"> Centro do avatar </string> + <string name="Left Ring Finger"> + Anelar esquerdo + </string> + <string name="Right Ring Finger"> + Anelar direito + </string> + <string name="Tail Base"> + Base do rabo + </string> + <string name="Tail Tip"> + Ponta do rabo + </string> + <string name="Left Wing"> + Asa esquerda + </string> + <string name="Right Wing"> + Asa direita + </string> + <string name="Jaw"> + Maxilar + </string> + <string name="Alt Left Ear"> + Orelha esquerda alt. + </string> + <string name="Alt Right Ear"> + Orelha direita alt. + </string> + <string name="Alt Left Eye"> + Olho esquerdo alt. + </string> + <string name="Alt Right Eye"> + Olho direito alt. + </string> + <string name="Tongue"> + Língua + </string> + <string name="Groin"> + Virilha + </string> + <string name="Left Hind Foot"> + Pata esq. traseira + </string> + <string name="Right Hind Foot"> + Pata dir. traseira + </string> <string name="Invalid Attachment"> Ponto de encaixe inválido </string> @@ -2167,12 +2221,12 @@ Pessoas com contas gratuitas não poderão acessar o Second Life no momento para <string name="ATTACH_BELLY"> Barriga </string> - <string name="ATTACH_RPEC"> - Peitorais D - </string> - <string name="ATTACH_LPEC"> + <string name="ATTACH_LEFT_PEC"> Peitorais E </string> + <string name="ATTACH_RIGHT_PEC"> + Peitorais D + </string> <string name="ATTACH_HUD_CENTER_2"> HUD Central 2 </string> @@ -2203,6 +2257,51 @@ Pessoas com contas gratuitas não poderão acessar o Second Life no momento para <string name="ATTACH_AVATAR_CENTER"> Centro do avatar </string> + <string name="ATTACH_LHAND_RING1"> + Anelar esquerdo + </string> + <string name="ATTACH_RHAND_RING1"> + Anelar direito + </string> + <string name="ATTACH_TAIL_BASE"> + Base do rabo + </string> + <string name="ATTACH_TAIL_TIP"> + Ponta do rabo + </string> + <string name="ATTACH_LWING"> + Asa esquerda + </string> + <string name="ATTACH_RWING"> + Asa direita + </string> + <string name="ATTACH_FACE_JAW"> + Maxilar + </string> + <string name="ATTACH_FACE_LEAR"> + Orelha esquerda alt. + </string> + <string name="ATTACH_FACE_REAR"> + Orelha direita alt. + </string> + <string name="ATTACH_FACE_LEYE"> + Olho esquerdo alt. + </string> + <string name="ATTACH_FACE_REYE"> + Olho direito alt. + </string> + <string name="ATTACH_FACE_TONGUE"> + Língua + </string> + <string name="ATTACH_GROIN"> + Virilha + </string> + <string name="ATTACH_HIND_LFOOT"> + Pata esq. traseira + </string> + <string name="ATTACH_HIND_RFOOT"> + Pata dir. traseira + </string> <string name="CursorPos"> Linha [LINE], Coluna [COLUMN] </string> @@ -4128,6 +4227,12 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="OfflineStatus"> Desconectado </string> + <string name="not_online_msg"> + O usuário não está online. As mensagens serão armazenadas e enviadas mais tarde. + </string> + <string name="not_online_inventory"> + O usuário não está online. O inventário foi salvo. + </string> <string name="answered_call"> Ligação atendida </string> diff --git a/indra/newview/skins/default/xui/ru/menu_attachment_other.xml b/indra/newview/skins/default/xui/ru/menu_attachment_other.xml index bd1ed8d1fa..b7ffb0e9fc 100644 --- a/indra/newview/skins/default/xui/ru/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/ru/menu_attachment_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="Звонок" name="Call"/> <menu_item_call label="Пригласить в группу" name="Invite..."/> + <menu_item_call label="Сброс скелета" name="Reset Skeleton"/> <menu_item_call label="Заблокировать" name="Avatar Mute"/> <menu_item_call label="Пожаловаться" name="abuse"/> <menu_item_call label="Заморозить" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/ru/menu_attachment_self.xml b/indra/newview/skins/default/xui/ru/menu_attachment_self.xml index 033d36484b..eb38371e28 100644 --- a/indra/newview/skins/default/xui/ru/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/ru/menu_attachment_self.xml @@ -9,6 +9,7 @@ <menu_item_call label="Изменить костюм" name="Edit Outfit"/> <menu_item_call label="Изменить фигуру" name="Edit My Shape"/> <menu_item_call label="Высота парения" name="Hover Height"/> + <menu_item_call label="Сброс скелета" name="Reset Skeleton"/> <menu_item_call label="Мои друзья" name="Friends..."/> <menu_item_call label="Мои группы" name="Groups..."/> <menu_item_call label="Мой профиль" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/ru/menu_avatar_other.xml b/indra/newview/skins/default/xui/ru/menu_avatar_other.xml index 74f1a39658..cffb4bbe7b 100644 --- a/indra/newview/skins/default/xui/ru/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/ru/menu_avatar_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="Звонок" name="Call"/> <menu_item_call label="Пригласить в группу" name="Invite..."/> + <menu_item_call label="Сброс скелета" name="Reset Skeleton"/> <menu_item_call label="Заблокировать" name="Avatar Mute"/> <menu_item_call label="Пожаловаться" name="abuse"/> <menu_item_call label="Заморозить" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/ru/menu_avatar_self.xml b/indra/newview/skins/default/xui/ru/menu_avatar_self.xml index 8feaa3b99a..97e2a8b295 100644 --- a/indra/newview/skins/default/xui/ru/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/ru/menu_avatar_self.xml @@ -26,6 +26,7 @@ <menu_item_call label="Изменить костюм" name="Edit Outfit"/> <menu_item_call label="Изменить фигуру" name="Edit My Shape"/> <menu_item_call label="Высота парения" name="Hover Height"/> + <menu_item_call label="Сброс скелета" name="Reset Skeleton"/> <menu_item_call label="Мои друзья" name="Friends..."/> <menu_item_call label="Мои группы" name="Groups..."/> <menu_item_call label="Мой профиль" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml index 2044844c58..6158363e5d 100644 --- a/indra/newview/skins/default/xui/ru/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml @@ -22,7 +22,6 @@ <menu_item_check label="Не беспокоить" name="Do Not Disturb"/> </menu> <menu_item_call label="Купить L$..." name="Buy and Sell L$"/> - <menu_item_call label="Торговые исходящие..." name="MerchantOutbox"/> <menu_item_call label="Списки товаров торгового центра..." name="MarketplaceListings"/> <menu_item_call label="Информационная панель аккаунта..." name="Manage My Account"/> <menu_item_call label="Настройки..." name="Preferences"/> @@ -418,6 +417,7 @@ <menu_item_check label="Отключить детализацию" name="Disable LOD"/> <menu_item_check label="Отладка видимости персонажа" name="Debug Character Vis"/> <menu_item_check label="Показать скелет" name="Show Collision Skeleton"/> + <menu_item_check label="Показать кости" name="Show Bones"/> <menu_item_check label="Отобразить действие агента" name="Display Agent Target"/> <menu_item_call label="Вывод присоединений" name="Dump Attachments"/> <menu_item_call label="Отладка текстур аватара" name="Debug Avatar Textures"/> diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml index fabc064525..5e7c2ed7d0 100644 --- a/indra/newview/skins/default/xui/ru/notifications.xml +++ b/indra/newview/skins/default/xui/ru/notifications.xml @@ -480,6 +480,9 @@ <notification name="CannotWearInfoNotComplete"> Нельзя надеть эту вещь, так как она еще не загружена. Повторите попытку через минуту. </notification> + <notification name="MustEnterPasswordToLogIn"> + Введите пароль для входа в мир. + </notification> <notification name="MustHaveAccountToLogIn"> Ай-яй-яй! Что-то осталось незаполненным. Необходимо ввести имя пользователя для вашего аватара. @@ -548,6 +551,9 @@ <notification name="ChangeConnectionPort"> Настройки порта начнут действовать после перезапуска [APP_NAME]. </notification> + <notification name="ChangeDeferredDebugSetting"> + Эта настройка отладки вступит в силу после перезапуска [APP_NAME]. + </notification> <notification name="ChangeSkin"> Новая кожа будет видна после перезапуска [APP_NAME]. </notification> @@ -1366,12 +1372,13 @@ <ignore name="ignore" text="Загрузка одежды занимает значительное время"/> </form> </notification> - <notification name="RegionAndAgentComplexity"> - Ваша [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 визуальная сложность]: [AGENT_COMPLEXITY]. + <notification name="AgentComplexityWithVisibility"> + Ваша [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 сложность аватара]: [AGENT_COMPLEXITY]. [OVERLIMIT_MSG] + <usetemplate ignoretext="Предупреждать о превышении сложности аватара" name="notifyignore"/> </notification> <notification name="AgentComplexity"> - Ваша [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 визуальная сложность]: [AGENT_COMPLEXITY]. + Ваша [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 сложность аватара]: [AGENT_COMPLEXITY]. </notification> <notification name="FirstRun"> Установка [APP_NAME] завершена. @@ -1486,6 +1493,10 @@ Вы действительно хотите зафиксировать текущий ландшафт, сделать его высоту средней точкой для верхней и нижней точек ландшафта и принять по умолчанию для функции «Вернуть»? <usetemplate name="okcancelbuttons" notext="Отмена" yestext="OK"/> </notification> + <notification name="ConfirmTextureHeights"> + Вы собираетесь использовать минимальные значения, которые больше, чем максимальные для диапазона высот. Начать? + <usetemplate canceltext="Не спрашивать" name="yesnocancelbuttons" notext="Отмена" yestext="OK"/> + </notification> <notification name="MaxAllowedAgentOnRegion"> У вас может быть не более [MAX_AGENTS] допущенных жителей. </notification> @@ -1723,14 +1734,6 @@ http://secondlife.com/download. Невозможно покинуть группу. Вы не можете покинуть группу, так как вы ее последний владелец. Сначала назначьте владельцем другого участника. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="GroupDepartError"> - Невозможно покинуть группу: [reason]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> - <notification name="GroupDepart"> - Вы покинули группу [group_name]. - <usetemplate name="okbutton" yestext="OK"/> - </notification> <notification name="ConfirmKick"> Вы ДЕЙСТВИТЕЛЬНО хотите выбросить всех жителей с сетки? <usetemplate name="okcancelbuttons" notext="Отмена" yestext="Выбросить всех жителей"/> @@ -2400,6 +2403,10 @@ http://secondlife.com/download. Вы действительно хотите необратимо удалить содержимое корзины? <usetemplate ignoretext="Подтверждать перед опорожнением корзины инвентаря" name="okcancelignore" notext="Отмена" yestext="OK"/> </notification> + <notification name="TrashIsFull"> + Ваша корзина переполнена. Это может вызвать проблемы при входе. + <usetemplate name="okcancelbuttons" notext="Я очищу корзину позже" yestext="Очистить корзину сейчас"/> + </notification> <notification name="ConfirmClearBrowserCache"> Вы действительно хотите удалить журнал своих перемещений, веб-страниц и поиска? <usetemplate name="okcancelbuttons" notext="Отмена" yestext="OK"/> @@ -3257,11 +3264,15 @@ http://secondlife.com/download. <notification name="AttachmentSaved"> Присоединение сохранено. </notification> - <notification name="PresetNotSaved"> - Ошибка при сохранении пресета [NAME]. + <notification name="AppearanceToXMLSaved"> + Внешность сохранена в формате XML в [PATH] </notification> - <notification name="PresetNotDeleted"> - Ошибка при удалении пресета [NAME]. + <notification name="AppearanceToXMLFailed"> + Не удалось сохранить внешность в XML. + icon="notifytip.tga" + name="PresetNotDeleted" + type="notifytip"> +Ошибка при удалении пресета [NAME]. </notification> <notification name="UnableToFindHelpTopic"> Невозможно найти раздел справки для этого элемента. @@ -4075,6 +4086,9 @@ http://secondlife.com/download. <notification name="CantAttachNotEnoughScriptResources"> Недостаточно свободных ресурсов скриптинга для присоединения объекта! </notification> + <notification name="IllegalAttachment"> + Прикрепляемый объект потребовал несуществующей точки на аватаре. Он был прикреплен к груди. + </notification> <notification name="CantDropItemTrialUser"> Здесь нельзя сбрасывать объекты; перейдите в бесплатную область для гостей. </notification> diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/ru/panel_preferences_alerts.xml index 9d7ae546fd..48e03b98e8 100644 --- a/indra/newview/skins/default/xui/ru/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/ru/panel_preferences_alerts.xml @@ -3,8 +3,9 @@ <text name="tell_me_label"> Сообщать мне: </text> - <check_box label="о расходах и доходах" name="notify_money_change_checkbox"/> + <check_box label="О расходах" name="notify_money_spend_checkbox"/> <check_box label="о входе и выходе моих друзей" name="friends_online_notify_checkbox"/> + <check_box label="О доходах" name="notify_money_received_checkbox"/> <text name="show_label"> Всегда показывать: </text> diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/ru/panel_preferences_graphics1.xml index 31c9b2135d..200241bd4d 100644 --- a/indra/newview/skins/default/xui/ru/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/ru/panel_preferences_graphics1.xml @@ -24,10 +24,15 @@ <text name="BetterText"> Качественней </text> + <slider label="Максимальная сложность аватара:" name="IndirectMaxComplexity" tool_tip="Указывает расстояние, начиная с которого визуально сложный аватар рисуется как мармеладный мишка"/> + <text name="IndirectMaxComplexityText"> + 0 + </text> <check_box initial_value="true" label="Атмосферные шейдеры" name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="Расширенная модель освещения" name="UseLightShaders"/> <button label="Сохранить настройки как пресет..." name="PrefSaveButton"/> <button label="Загрузить пресет..." name="PrefLoadButton"/> + min_val="0,125" <button label="Удалить пресет..." name="PrefDeleteButton"/> <button label="Вернуть рекомендуемые настройки" name="Defaults"/> <button label="Расширенные настройки..." name="AdvancedSettings"/> diff --git a/indra/newview/skins/default/xui/ru/panel_sound_devices.xml b/indra/newview/skins/default/xui/ru/panel_sound_devices.xml index 98dab288a3..3de84fb937 100644 --- a/indra/newview/skins/default/xui/ru/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/ru/panel_sound_devices.xml @@ -16,9 +16,9 @@ Выход </text> <text name="My volume label"> - Моя громкость: + Громкость микрофона: </text> - <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Измените значение, используя ползунок"/> + <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Измените уровень в микрофоне, используя ползунок"/> <text name="wait_text"> Подождите </text> diff --git a/indra/newview/skins/default/xui/ru/panel_status_bar.xml b/indra/newview/skins/default/xui/ru/panel_status_bar.xml index 630925fa60..49c48ae654 100644 --- a/indra/newview/skins/default/xui/ru/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/ru/panel_status_bar.xml @@ -5,7 +5,7 @@ <panel.string name="time">[hour, datetime, slt]:[min, datetime, slt] [timezone,datetime, slt]</panel.string> <panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string> <panel.string name="buycurrencylabel">L$ [AMT]</panel.string> - <panel left="-450" name="balance_bg" width="240"> + <panel left="-471" name="balance_bg" width="240"> <text name="balance" tool_tip="Щелкните для обновления вашего баланса L$" value="L$??"/> <button label="Купить L$" name="buyL" tool_tip="Щелкните для покупки L$"/> <button label="Торговый центр" name="goShop" tool_tip="Открыть торговый центр Second Life" width="121"/> diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index 04bb55c965..da03af055c 100644 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -41,6 +41,9 @@ [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL]) [[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]] </string> + <string name="BuildConfig"> + Конфигурация построения [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]) SLURL: <nolink>[SLURL]</nolink> @@ -72,6 +75,9 @@ SLURL: <nolink>[SLURL]</nolink> <string name="ErrorFetchingServerReleaseNotesURL"> Ошибка при получении URL-адреса заметок о выпуске сервера. </string> + <string name="BuildConfiguration"> + Конфигурация построения + </string> <string name="ProgressRestoring"> Восстановление... </string> @@ -1387,6 +1393,9 @@ support@secondlife.com. <string name="BodyPartsRightLeg"> Правая нога </string> + <string name="BodyPartsEnhancedSkeleton"> + Улучшенный скелет + </string> <string name="GraphicsQualityLow"> низкая </string> @@ -1835,6 +1844,51 @@ support@secondlife.com. <string name="Avatar Center"> Центр аватара </string> + <string name="Left Ring Finger"> + Левый безымянный палец + </string> + <string name="Right Ring Finger"> + Правый безымянный палец + </string> + <string name="Tail Base"> + Основание хвоста + </string> + <string name="Tail Tip"> + Кончик хвоста + </string> + <string name="Left Wing"> + Левое крыло + </string> + <string name="Right Wing"> + Правое крыло + </string> + <string name="Jaw"> + Пасть + </string> + <string name="Alt Left Ear"> + Альт. левое ухо + </string> + <string name="Alt Right Ear"> + Альт. правое ухо + </string> + <string name="Alt Left Eye"> + Альт. левый глаз + </string> + <string name="Alt Right Eye"> + Альт. правый глаз + </string> + <string name="Tongue"> + Язык + </string> + <string name="Groin"> + Пах + </string> + <string name="Left Hind Foot"> + Левая задняя нога + </string> + <string name="Right Hind Foot"> + Правая задняя нога + </string> <string name="Invalid Attachment"> Неверная точка присоединения </string> @@ -2224,12 +2278,12 @@ support@secondlife.com. <string name="ATTACH_BELLY"> Живот </string> - <string name="ATTACH_RPEC"> - Правая грудь - </string> - <string name="ATTACH_LPEC"> + <string name="ATTACH_LEFT_PEC"> Левая грудь </string> + <string name="ATTACH_RIGHT_PEC"> + Правая грудь + </string> <string name="ATTACH_HUD_CENTER_2"> Данные в игре в центре 2 </string> @@ -2260,6 +2314,51 @@ support@secondlife.com. <string name="ATTACH_AVATAR_CENTER"> Центр аватара </string> + <string name="ATTACH_LHAND_RING1"> + Левый безымянный палец + </string> + <string name="ATTACH_RHAND_RING1"> + Правый безымянный палец + </string> + <string name="ATTACH_TAIL_BASE"> + Основание хвоста + </string> + <string name="ATTACH_TAIL_TIP"> + Кончик хвоста + </string> + <string name="ATTACH_LWING"> + Левое крыло + </string> + <string name="ATTACH_RWING"> + Правое крыло + </string> + <string name="ATTACH_FACE_JAW"> + Пасть + </string> + <string name="ATTACH_FACE_LEAR"> + Альт. левое ухо + </string> + <string name="ATTACH_FACE_REAR"> + Альт. правое ухо + </string> + <string name="ATTACH_FACE_LEYE"> + Альт. левый глаз + </string> + <string name="ATTACH_FACE_REYE"> + Альт. правый глаз + </string> + <string name="ATTACH_FACE_TONGUE"> + Язык + </string> + <string name="ATTACH_GROIN"> + Пах + </string> + <string name="ATTACH_HIND_LFOOT"> + Левая задняя нога + </string> + <string name="ATTACH_HIND_RFOOT"> + Правая задняя нога + </string> <string name="CursorPos"> Строка [LINE], столбец [COLUMN] </string> @@ -4247,10 +4346,10 @@ support@secondlife.com. Оффлайн </string> <string name="not_online_msg"> - Пользователь оффлайн - сообщение будет сохранено и доставлено позже. + Пользователь не в онлайне - сообщение будет сохранено и доставлено позже. </string> <string name="not_online_inventory"> - Пользователь оффлайн - инвентарь сохранен. + Пользователь не в онлайне - инвентарь сохранен. </string> <string name="answered_call"> На ваш звонок ответили diff --git a/indra/newview/skins/default/xui/tr/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/tr/floater_preferences_graphics_advanced.xml index 53938117fd..867e15a3ca 100644 --- a/indra/newview/skins/default/xui/tr/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/tr/floater_preferences_graphics_advanced.xml @@ -15,7 +15,7 @@ <text name="AvatarText"> Avatar </text> - <slider label="Maksimum karmaşıklık:" name="IndirectMaxComplexity" tool_tip="Görsel olarak karmaşık yapıdaki bir avatarın hangi noktada jelibon gibi tek renkli olarak çizileceğini kontrol eder"/> + <slider label="Maksimum karmaşıklık:" name="IndirectMaxComplexity" tool_tip="Görsel olarak karmaşık bir avatarın hangi noktadan itibaren JellyDolll olarak çizileceğini kontrol eder"/> <text name="IndirectMaxComplexityText"> 0 </text> diff --git a/indra/newview/skins/default/xui/tr/menu_attachment_other.xml b/indra/newview/skins/default/xui/tr/menu_attachment_other.xml index 8a669a28f7..d09174dcc0 100644 --- a/indra/newview/skins/default/xui/tr/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/tr/menu_attachment_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="Aİ" name="Send IM..."/> <menu_item_call label="Ara" name="Call"/> <menu_item_call label="Gruba Davet Et" name="Invite..."/> + <menu_item_call label="İskeleti Sıfırla" name="Reset Skeleton"/> <menu_item_call label="Engelle" name="Avatar Mute"/> <menu_item_call label="Raporla" name="abuse"/> <menu_item_call label="Dondur" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/tr/menu_attachment_self.xml b/indra/newview/skins/default/xui/tr/menu_attachment_self.xml index c49f817a45..9027f09d8e 100644 --- a/indra/newview/skins/default/xui/tr/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/tr/menu_attachment_self.xml @@ -9,6 +9,7 @@ <menu_item_call label="Dış Görünümümü Düzenle" name="Edit Outfit"/> <menu_item_call label="Şeklimi Düzenle" name="Edit My Shape"/> <menu_item_call label="Konum Yüksekliği" name="Hover Height"/> + <menu_item_call label="İskeleti Sıfırla" name="Reset Skeleton"/> <menu_item_call label="Arkadaşlarım" name="Friends..."/> <menu_item_call label="Gruplarım" name="Groups..."/> <menu_item_call label="Profilim" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/tr/menu_avatar_other.xml b/indra/newview/skins/default/xui/tr/menu_avatar_other.xml index e4ba3a5616..9e95b3033a 100644 --- a/indra/newview/skins/default/xui/tr/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/tr/menu_avatar_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="Aİ" name="Send IM..."/> <menu_item_call label="Ara" name="Call"/> <menu_item_call label="Gruba Davet Et" name="Invite..."/> + <menu_item_call label="İskeleti Sıfırla" name="Reset Skeleton"/> <menu_item_call label="Engelle" name="Avatar Mute"/> <menu_item_call label="Raporla" name="abuse"/> <menu_item_call label="Dondur" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/tr/menu_avatar_self.xml b/indra/newview/skins/default/xui/tr/menu_avatar_self.xml index 4dfa42c347..3078733478 100644 --- a/indra/newview/skins/default/xui/tr/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/tr/menu_avatar_self.xml @@ -26,6 +26,7 @@ <menu_item_call label="Dış Görünümümü Düzenle" name="Edit Outfit"/> <menu_item_call label="Şeklimi Düzenle" name="Edit My Shape"/> <menu_item_call label="Konum Yüksekliği" name="Hover Height"/> + <menu_item_call label="İskeleti Sıfırla" name="Reset Skeleton"/> <menu_item_call label="Arkadaşlarım" name="Friends..."/> <menu_item_call label="Gruplarım" name="Groups..."/> <menu_item_call label="Profilim" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml index 324e549a75..39636f2ebf 100644 --- a/indra/newview/skins/default/xui/tr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml @@ -22,7 +22,6 @@ <menu_item_check label="Rahatsız Etme" name="Do Not Disturb"/> </menu> <menu_item_call label="L$ Satın Al..." name="Buy and Sell L$"/> - <menu_item_call label="Satıcı Giden Kutusu..." name="MerchantOutbox"/> <menu_item_call label="Pazaryeri ilanları..." name="MarketplaceListings"/> <menu_item_call label="Hesap kontrol paneli..." name="Manage My Account"/> <menu_item_call label="Tercihler..." name="Preferences"/> @@ -419,6 +418,7 @@ <menu_item_check label="Ayrıntı Seviyesi Bilgisini Devre Dışı Bırak" name="Disable LOD"/> <menu_item_check label="Debug Character Vis" name="Debug Character Vis"/> <menu_item_check label="Çarpışma İskeletini Göster" name="Show Collision Skeleton"/> + <menu_item_check label="Kemikleri Göster" name="Show Bones"/> <menu_item_check label="Aracı Hedefini Göster" name="Display Agent Target"/> <menu_item_call label="Aksesuarların Dökümünü Al" name="Dump Attachments"/> <menu_item_call label="Avatar Dokuları İçin Hata Ayıklama" name="Debug Avatar Textures"/> diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml index a982dc03ed..fb38486a9e 100644 --- a/indra/newview/skins/default/xui/tr/notifications.xml +++ b/indra/newview/skins/default/xui/tr/notifications.xml @@ -480,6 +480,9 @@ Dış görünüm klasöründe hiç giysi, vücut bölümü ya da aksesuar yok. <notification name="CannotWearInfoNotComplete"> Bu öğe henüz yüklenmediği için kullanamazsınız. Lütfen bir dakika sonra tekrar deneyin. </notification> + <notification name="MustEnterPasswordToLogIn"> + Oturum açmak için lütfen parolanızı girin. + </notification> <notification name="MustHaveAccountToLogIn"> Hata! Boş bırakılan alan(lar) var. Avatarınızın Kullanıcı adını girmeniz gerekmektedir. @@ -548,6 +551,9 @@ Not: Bu işlem önbelleği temizleyecek. <notification name="ChangeConnectionPort"> Port ayarları, [APP_NAME] uygulamasını yeniden başlattıktan sonra geçerli olur. </notification> + <notification name="ChangeDeferredDebugSetting"> + Bu hata ayıklama ayarı değişikliği [APP_NAME] uygulamasını yeniden başlattıktan sonra geçerli olacak. + </notification> <notification name="ChangeSkin"> Yeni dış katman [APP_NAME] uygulamasını yeniden başlattıktan sonra görüntülenecek. </notification> @@ -1366,12 +1372,13 @@ Yeni bir ana konum ayarlamak isteyebilirsiniz. <ignore name="ignore" text="Giysilerin karşıdan yüklenmesi uzun zaman alıyor"/> </form> </notification> - <notification name="RegionAndAgentComplexity"> - [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 Görsel karmaşıklık] seviyeniz: [AGENT_COMPLEXITY]. + <notification name="AgentComplexityWithVisibility"> + [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 avatar complexity] düzeyiniz [AGENT_COMPLEXITY]. [OVERLIMIT_MSG] + <usetemplate ignoretext="Avatarımın karmaşıklık düzeyi çok yüksekse beni uyar" name="notifyignore"/> </notification> <notification name="AgentComplexity"> - [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 Görsel karmaşıklık] seviyeniz: [AGENT_COMPLEXITY]. + [https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 avatar complexity] düzeyiniz [AGENT_COMPLEXITY]. </notification> <notification name="FirstRun"> [APP_NAME] yüklemesi tamamlandı. @@ -1486,6 +1493,10 @@ Lütfen sadece bir nesne seçin ve tekrar deneyin. Geçerli yüzeyi bu şekilde kaydetmeyi, yüzey yükseltme/alçaltma sınırları için merkez olarak kullanmayı ve 'Geri Çevir' aracı için varsayılan olarak ayarlamayı gerçekten istiyor musunuz? <usetemplate name="okcancelbuttons" notext="İptal" yestext="Tamam"/> </notification> + <notification name="ConfirmTextureHeights"> + Yükselti Ayarları için girdiğiniz düşük değer, yüksek değerden daha fazla. Devam edilsin mi? + <usetemplate canceltext="Tekrar Sorma" name="yesnocancelbuttons" notext="İptal Et" yestext="Tamam"/> + </notification> <notification name="MaxAllowedAgentOnRegion"> Sadece [MAX_AGENTS] tane İzin Verilen Sakin belirleyebilirsiniz. </notification> @@ -1723,14 +1734,6 @@ Gruptan ayrılmak istiyor musunuz? Gruptan ayrılınamıyor. Gruptan ayrılamazsınız çünkü grubun son sahibisiniz. Lütfen önce sahip rolüne başka bir üye atayın. <usetemplate name="okbutton" yestext="Tamam"/> </notification> - <notification name="GroupDepartError"> - Gruptan ayrılma işlemi yapılamıyor: [reason]. - <usetemplate name="okbutton" yestext="Tamam"/> - </notification> - <notification name="GroupDepart"> - [group_name] grubundan ayrıldınız. - <usetemplate name="okbutton" yestext="Tamam"/> - </notification> <notification name="ConfirmKick"> Tüm Sakinleri GERÇEKTEN ağ dışına çıkarmak istiyor musunuz? <usetemplate name="okcancelbuttons" notext="İptal Et" yestext="Tüm Sakinleri Çıkar"/> @@ -2400,6 +2403,10 @@ Bu işlemi tamamlamadan önce Rahatsız Etme'yi kapatmak ister misiniz? Çöp kutunuzun içeriğini kalıcı olarak silmek istediğinize emin misiniz? <usetemplate ignoretext="Envanter Çöp Kutusu klasörünü boşaltmadan önce doğrulama iste" name="okcancelignore" notext="İptal" yestext="Tamam"/> </notification> + <notification name="TrashIsFull"> + Çöpte yer kalmamış. Bu durum oturum açma sırasında sorun yaşamanıza neden olabilir. + <usetemplate name="okcancelbuttons" notext="Çöpü daha sonra boşaltacağım" yestext="Çöp kutusunu şimdi boşalt"/> + </notification> <notification name="ConfirmClearBrowserCache"> Seyahat, web ve arama geçmişinizi silmek istediğinize emin misiniz? <usetemplate name="okcancelbuttons" notext="İptal" yestext="Tamam"/> @@ -2984,7 +2991,7 @@ Bu bölgede kalmaya devam ederseniz oturumunuz sonlandırılacak. Bu bölgede kalmaya devam ederseniz oturumunuz sonlandırılacak. </notification> <notification name="LoadWebPage"> - [URL] web sayfası yüklensin mi? + Bu web sayfası yüklensin mi: [URL] ? [MESSAGE] @@ -3257,11 +3264,15 @@ Güvenliğiniz için birkaç saniye engellenecek. <notification name="AttachmentSaved"> Aksesuar kaydedildi. </notification> - <notification name="PresetNotSaved"> - [NAME] ön ayarı kaydedilirken hata oluştu. + <notification name="AppearanceToXMLSaved"> + Görünüm XML olarak [PATH] konumuna kaydedildi </notification> - <notification name="PresetNotDeleted"> - [NAME] ön ayarı silinirken hata oluştu. + <notification name="AppearanceToXMLFailed"> + Görünüm XML olarak kaydedilemedi. + icon="notifytip.tga" + name="PresetNotDeleted" + type="notifytip"> +[NAME] ön ayarı silinirken hata oluştu. </notification> <notification name="UnableToFindHelpTopic"> Bu öğe için yardım başlığı bulunamıyor. @@ -4069,6 +4080,9 @@ Lütfen bir dakika sonra tekrar deneyin. <notification name="CantAttachNotEnoughScriptResources"> Nesneyi iliştirmek için yeterli komut dosyası kaynağı mevcut değil! </notification> + <notification name="IllegalAttachment"> + Aksesuar avatarda var olmayan bir noktaya karşılık geliyor. Bunun yerine göğüs kısmına eklendi. + </notification> <notification name="CantDropItemTrialUser"> Buraya nesne düşüremezsiniz; Ücretsiz Deneme alanını deneyin. </notification> diff --git a/indra/newview/skins/default/xui/tr/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/tr/panel_preferences_alerts.xml index 46a4793c53..b0f026b285 100644 --- a/indra/newview/skins/default/xui/tr/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/tr/panel_preferences_alerts.xml @@ -3,8 +3,9 @@ <text name="tell_me_label"> Bana söyle: </text> - <check_box label="L$ harcadığımda veya aldığımda" name="notify_money_change_checkbox"/> + <check_box label="L$ harcadığımda" name="notify_money_spend_checkbox"/> <check_box label="Arkadaşlarım oturum açtığında veya kapattığında" name="friends_online_notify_checkbox"/> + <check_box label="L$ aldığımda" name="notify_money_received_checkbox"/> <text name="show_label"> Daima göster: </text> diff --git a/indra/newview/skins/default/xui/tr/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/tr/panel_preferences_graphics1.xml index 13984c2792..9cfa7d61f4 100644 --- a/indra/newview/skins/default/xui/tr/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/tr/panel_preferences_graphics1.xml @@ -24,10 +24,15 @@ <text name="BetterText"> Daha iyi </text> + <slider label="Avatarın Maksimum Karmaşıklığı:" name="IndirectMaxComplexity" tool_tip="Görsel olarak karmaşık bir avatarın hangi noktadan itibaren JellyDolll olarak çizileceğini kontrol eder"/> + <text name="IndirectMaxComplexityText"> + 0 + </text> <check_box initial_value="true" label="Atmosferik gölgeleyiciler" name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="Gelişmiş Aydınlatma Modeli" name="UseLightShaders"/> <button label="Ayarları ön ayar olarak kaydet..." name="PrefSaveButton"/> <button label="Ön ayarı yükle..." name="PrefLoadButton"/> + min_val="0,125" <button label="Ön ayarı sil..." name="PrefDeleteButton"/> <button label="Önerilen ayarlara dön" name="Defaults"/> <button label="Gelişmiş Ayarlar..." name="AdvancedSettings"/> diff --git a/indra/newview/skins/default/xui/tr/panel_sound_devices.xml b/indra/newview/skins/default/xui/tr/panel_sound_devices.xml index 982ef2ea3b..be3299b89c 100644 --- a/indra/newview/skins/default/xui/tr/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/tr/panel_sound_devices.xml @@ -16,9 +16,9 @@ Çıktı </text> <text name="My volume label"> - Ses düzeyim: + Mik. ses düzeyi: </text> - <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Bu kaydırıcıyı kullanarak ses düzeyini değiştirin"/> + <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Bu kaydırma butonunu kullanarak mikrofonun ses düzeyini değiştirin"/> <text name="wait_text"> Lütfen bekleyin </text> diff --git a/indra/newview/skins/default/xui/tr/panel_status_bar.xml b/indra/newview/skins/default/xui/tr/panel_status_bar.xml index 9e2669ec2b..7c7bfc7e14 100644 --- a/indra/newview/skins/default/xui/tr/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/tr/panel_status_bar.xml @@ -5,7 +5,7 @@ <panel.string name="time">[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]</panel.string> <panel.string name="timeTooltip">[weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]</panel.string> <panel.string name="buycurrencylabel">L$ [AMT]</panel.string> - <panel left="-425" name="balance_bg" width="215"> + <panel left="-446" name="balance_bg" width="215"> <text name="balance" tool_tip="L$ bakiyenizi yenilemek için buraya tıklayın" value="L$??"/> <button label="L$ Satın Al" name="buyL" tool_tip="Daha fazla L$ satın almak için tıklayın"/> <button label="Alışveriş yap" name="goShop" tool_tip="Second Life Pazaryeri Aç" width="95"/> diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index 67c9197907..6aad65da22 100644 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -39,7 +39,10 @@ </string> <string name="AboutHeader"> [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL]) -[[VIEWER_RELEASE_NOTES_URL] [Sürüm Notları]] +[[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]] + </string> + <string name="BuildConfig"> + 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 @@ -59,12 +62,12 @@ Grafik Kartı: [GRAPHICS_CARD] Windows Grafik Sürücüsü Sürümü: [GRAPHICS_DRIVER_VERSION] </string> <string name="AboutLibs"> - OpenGL Sürümü: [OPENGL_VERSION] + OpenGL Sürümü [OPENGL_VERSION] J2C Kod Çözücü Sürümü: [J2C_VERSION] Ses Sürücüsü Sürümü: [AUDIO_DRIVER_VERSION] LLCEFLib/CEF Sürümü: [LLCEFLIB_VERSION] -Ses Sunucusu Sürümü: [VOICE_VERSION] +Ses Sunucu Sürümü: [VOICE_VERSION] </string> <string name="AboutTraffic"> Kaybolan Paketler: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%) @@ -72,6 +75,9 @@ Ses Sunucusu Sürümü: [VOICE_VERSION] <string name="ErrorFetchingServerReleaseNotesURL"> Sunucu sürümü notları URL'si alınırken hata oluştu. </string> + <string name="BuildConfiguration"> + Yapı Konfigürasyonu + </string> <string name="ProgressRestoring"> Geri yükleniyor... </string> @@ -1387,6 +1393,9 @@ Lütfen bir dakika içerisinde tekrar oturum açmayı deneyin. <string name="BodyPartsRightLeg"> Sağ Bacak </string> + <string name="BodyPartsEnhancedSkeleton"> + Gelişmiş İskelet + </string> <string name="GraphicsQualityLow"> Düşük </string> @@ -1835,6 +1844,51 @@ Lütfen bir dakika içerisinde tekrar oturum açmayı deneyin. <string name="Avatar Center"> Avatar Merkezi </string> + <string name="Left Ring Finger"> + Sol Yüzük Parmağı + </string> + <string name="Right Ring Finger"> + Sağ Yüzük Parmağı + </string> + <string name="Tail Base"> + Kuyruk Tabanı + </string> + <string name="Tail Tip"> + Kuyruk Ucu + </string> + <string name="Left Wing"> + Sol Kanat + </string> + <string name="Right Wing"> + Sağ Kanat + </string> + <string name="Jaw"> + Pençe + </string> + <string name="Alt Left Ear"> + Altrntf Sol Kulak + </string> + <string name="Alt Right Ear"> + Altrntf Sağ Kulak + </string> + <string name="Alt Left Eye"> + Altrntf Sol Göz + </string> + <string name="Alt Right Eye"> + Altrntf Sağ Göz + </string> + <string name="Tongue"> + Dil + </string> + <string name="Groin"> + Kasık + </string> + <string name="Left Hind Foot"> + Sol Arka Ayak + </string> + <string name="Right Hind Foot"> + Sağ Arka Ayak + </string> <string name="Invalid Attachment"> Geçersiz Aksesuar Noktası </string> @@ -2224,12 +2278,12 @@ Lütfen bir dakika içerisinde tekrar oturum açmayı deneyin. <string name="ATTACH_BELLY"> Göbek </string> - <string name="ATTACH_RPEC"> - Sağ Göğüs - </string> - <string name="ATTACH_LPEC"> + <string name="ATTACH_LEFT_PEC"> Sol Göğüs </string> + <string name="ATTACH_RIGHT_PEC"> + Sağ Göğüs + </string> <string name="ATTACH_HUD_CENTER_2"> BÜG 2. Merkez </string> @@ -2260,6 +2314,51 @@ Lütfen bir dakika içerisinde tekrar oturum açmayı deneyin. <string name="ATTACH_AVATAR_CENTER"> Avatar Merkezi </string> + <string name="ATTACH_LHAND_RING1"> + Sol Yüzük Parmağı + </string> + <string name="ATTACH_RHAND_RING1"> + Sağ Yüzük Parmağı + </string> + <string name="ATTACH_TAIL_BASE"> + Kuyruk Tabanı + </string> + <string name="ATTACH_TAIL_TIP"> + Kuyruk Ucu + </string> + <string name="ATTACH_LWING"> + Sol Kanat + </string> + <string name="ATTACH_RWING"> + Sağ Kanat + </string> + <string name="ATTACH_FACE_JAW"> + Pençe + </string> + <string name="ATTACH_FACE_LEAR"> + Altrntf Sol Kulak + </string> + <string name="ATTACH_FACE_REAR"> + Altrntf Sağ Kulak + </string> + <string name="ATTACH_FACE_LEYE"> + Altrntf Sol Göz + </string> + <string name="ATTACH_FACE_REYE"> + Altrntf Sağ Göz + </string> + <string name="ATTACH_FACE_TONGUE"> + Dil + </string> + <string name="ATTACH_GROIN"> + Kasık + </string> + <string name="ATTACH_HIND_LFOOT"> + Sol Arka Ayak + </string> + <string name="ATTACH_HIND_RFOOT"> + Sağ Arka Ayak + </string> <string name="CursorPos"> Satır [LINE], Sütun [COLUMN] </string> @@ -4249,6 +4348,12 @@ Bu iletiyi almaya devam ederseniz, lütfen [SUPPORT_SITE] bölümüne başvurun. <string name="OfflineStatus"> Çevrimdışı </string> + <string name="not_online_msg"> + Kullanıcı çevrimiçi değil - mesaj saklanıp daha sonra iletilecek. + </string> + <string name="not_online_inventory"> + Kullanıcı çevrimiçi değil - envanter kaydedildi. + </string> <string name="answered_call"> Aramanız yanıtlandı </string> diff --git a/indra/newview/skins/default/xui/zh/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/zh/floater_preferences_graphics_advanced.xml index f9c2fe47e7..2a00bb6172 100644 --- a/indra/newview/skins/default/xui/zh/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/zh/floater_preferences_graphics_advanced.xml @@ -15,7 +15,7 @@ <text name="AvatarText"> 化身 </text> - <slider label="最大複雜度:" name="IndirectMaxComplexity" tool_tip="控制在何時機下讓複雜化身呈像為「單色軟糖娃娃」"/> + <slider label="最大複雜度:" name="IndirectMaxComplexity" tool_tip="控制在何時機下讓複雜化身呈像為 JellyDoll"/> <text name="IndirectMaxComplexityText"> 0 </text> diff --git a/indra/newview/skins/default/xui/zh/menu_attachment_other.xml b/indra/newview/skins/default/xui/zh/menu_attachment_other.xml index ace1302250..69bc4e7632 100644 --- a/indra/newview/skins/default/xui/zh/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/zh/menu_attachment_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="通話" name="Call"/> <menu_item_call label="邀請加入群組" name="Invite..."/> + <menu_item_call label="重設骨架" name="Reset Skeleton"/> <menu_item_call label="封鎖" name="Avatar Mute"/> <menu_item_call label="回報" name="abuse"/> <menu_item_call label="凍結" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/zh/menu_attachment_self.xml b/indra/newview/skins/default/xui/zh/menu_attachment_self.xml index d9e6eff897..cf56d7c86b 100644 --- a/indra/newview/skins/default/xui/zh/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/zh/menu_attachment_self.xml @@ -9,6 +9,7 @@ <menu_item_call label="編輯我的裝扮" name="Edit Outfit"/> <menu_item_call label="編輯我的體形" name="Edit My Shape"/> <menu_item_call label="懸浮高度" name="Hover Height"/> + <menu_item_call label="重設骨架" name="Reset Skeleton"/> <menu_item_call label="我的朋友" name="Friends..."/> <menu_item_call label="我的群組" name="Groups..."/> <menu_item_call label="我的個人檔案" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/zh/menu_avatar_other.xml b/indra/newview/skins/default/xui/zh/menu_avatar_other.xml index 0e0d1cc3d2..b58ec1d8cb 100644 --- a/indra/newview/skins/default/xui/zh/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/zh/menu_avatar_other.xml @@ -6,6 +6,7 @@ <menu_item_call label="IM" name="Send IM..."/> <menu_item_call label="通話" name="Call"/> <menu_item_call label="邀請加入群組" name="Invite..."/> + <menu_item_call label="重設骨架" name="Reset Skeleton"/> <menu_item_call label="封鎖" name="Avatar Mute"/> <menu_item_call label="回報" name="abuse"/> <menu_item_call label="凍結" name="Freeze..."/> diff --git a/indra/newview/skins/default/xui/zh/menu_avatar_self.xml b/indra/newview/skins/default/xui/zh/menu_avatar_self.xml index a644a45df6..e2ddb57307 100644 --- a/indra/newview/skins/default/xui/zh/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/zh/menu_avatar_self.xml @@ -26,6 +26,7 @@ <menu_item_call label="編輯我的裝扮" name="Edit Outfit"/> <menu_item_call label="編輯我的體形" name="Edit My Shape"/> <menu_item_call label="懸浮高度" name="Hover Height"/> + <menu_item_call label="重設骨架" name="Reset Skeleton"/> <menu_item_call label="我的朋友" name="Friends..."/> <menu_item_call label="我的群組" name="Groups..."/> <menu_item_call label="我的個人檔案" name="Profile..."/> diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml index 41590d60c7..f2971491ac 100644 --- a/indra/newview/skins/default/xui/zh/menu_viewer.xml +++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml @@ -22,7 +22,6 @@ <menu_item_check label="請勿打擾" name="Do Not Disturb"/> </menu> <menu_item_call label="購買 L$…" name="Buy and Sell L$"/> - <menu_item_call label="商家發件匣…" name="MerchantOutbox"/> <menu_item_call label="Marketplace 刊登…" name="MarketplaceListings"/> <menu_item_call label="帳戶主控臺…" name="Manage My Account"/> <menu_item_call label="偏好設定…" name="Preferences"/> @@ -419,6 +418,7 @@ <menu_item_check label="停用細節層次" name="Disable LOD"/> <menu_item_check label="除錯字元可見性" name="Debug Character Vis"/> <menu_item_check label="顯示碰撞骨架" name="Show Collision Skeleton"/> + <menu_item_check label="顯示骨頭" name="Show Bones"/> <menu_item_check label="顯示用戶目標" name="Display Agent Target"/> <menu_item_call label="傾印附件" name="Dump Attachments"/> <menu_item_call label="除錯化身材質" name="Debug Avatar Textures"/> diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml index 3f08496a68..463afab1c0 100644 --- a/indra/newview/skins/default/xui/zh/notifications.xml +++ b/indra/newview/skins/default/xui/zh/notifications.xml @@ -480,6 +480,9 @@ <notification name="CannotWearInfoNotComplete"> 無法穿戴該物件,它尚未完成載入。 請稍候再試。 </notification> + <notification name="MustEnterPasswordToLogIn"> + 請輸入密碼以便登入。 + </notification> <notification name="MustHaveAccountToLogIn"> 糟糕! 發現有內容留白。 你必須為化身輸入一個使用者名稱。 @@ -548,6 +551,9 @@ <notification name="ChangeConnectionPort"> 重新啟動 [APP_NAME] 後將啟用新的埠設定。 </notification> + <notification name="ChangeDeferredDebugSetting"> + 這個除錯設定將在重新啟動 [APP_NAME] 後啟用。 + </notification> <notification name="ChangeSkin"> 重新啟動 [APP_NAME] 後將顯現新的皮膚。 </notification> @@ -1359,12 +1365,13 @@ <ignore name="ignore" text="服裝花太多時間下載"/> </form> </notification> - <notification name="RegionAndAgentComplexity"> - 你的[https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 視覺複雜度]是[AGENT_COMPLEXITY]。 + <notification name="AgentComplexityWithVisibility"> + 你的[https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 化身複雜度]是[AGENT_COMPLEXITY]。 [OVERLIMIT_MSG] + <usetemplate ignoretext="警告我化身的複雜度是否可能過高" name="notifyignore"/> </notification> <notification name="AgentComplexity"> - 你的[https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 視覺複雜度]是[AGENT_COMPLEXITY]。 + 你的[https://community.secondlife.com/t5/English-Knowledge-Base/Avatar-Rendering-Complexity/ta-p/2967838 化身複雜度]是[AGENT_COMPLEXITY]。 </notification> <notification name="FirstRun"> [APP_NAME] 安裝完成。 @@ -1479,6 +1486,10 @@ SHA1 指紋:[MD5_DIGEST] 你真的要確定產出目前地形,使其成為地形升/降極限的中間值,並設為「復原」工具的預設值? <usetemplate name="okcancelbuttons" notext="取消" yestext="確定"/> </notification> + <notification name="ConfirmTextureHeights"> + 你設的海拔範圍值,低值大於高值。 繼續? + <usetemplate canceltext="不要問" name="yesnocancelbuttons" notext="取消" yestext="確定"/> + </notification> <notification name="MaxAllowedAgentOnRegion"> 你最多只能有 [MAX_AGENTS] 位允許居民。 </notification> @@ -1713,14 +1724,6 @@ SHA1 指紋:[MD5_DIGEST] 無法離開群組。 你是此群組僅存的所有人,不得離開群組。 請先把所有人職銜指派給另一人。 <usetemplate name="okbutton" yestext="確定"/> </notification> - <notification name="GroupDepartError"> - 無法離開群組:[reason]。 - <usetemplate name="okbutton" yestext="確定"/> - </notification> - <notification name="GroupDepart"> - 你已經離開[group_name]群組。 - <usetemplate name="okbutton" yestext="確定"/> - </notification> <notification name="ConfirmKick"> 你確定要踢出這網格內的全部居民? <usetemplate name="okcancelbuttons" notext="取消" yestext="踢出全部居民"/> @@ -2390,6 +2393,10 @@ SHA1 指紋:[MD5_DIGEST] 你確定你要對你垃圾筒中的內容進行刪除? <usetemplate ignoretext="在我清空收納區垃圾筒資料夾前確認" name="okcancelignore" notext="取消" yestext="確定"/> </notification> + <notification name="TrashIsFull"> + 你的垃圾桶快滿了。 這可能會造成登入的問題。 + <usetemplate name="okcancelbuttons" notext="我稍後再清空垃圾桶" yestext="現在清空垃圾桶"/> + </notification> <notification name="ConfirmClearBrowserCache"> 你確定要刪除你的旅行、網頁及搜尋歷史紀錄嗎? <usetemplate name="okcancelbuttons" notext="取消" yestext="確定"/> @@ -2973,11 +2980,11 @@ SHA1 指紋:[MD5_DIGEST] 如果你繼續留在這地區,你將會被登出。 </notification> <notification name="LoadWebPage"> - 載入網頁 [URL]? + 載入網頁 [URL]? [MESSAGE] -來源物件:<nolink>[OBJECTNAME]</nolink>(所有人:[NAME_SLURL]) +來源物件:<nolink>[OBJECTNAME]</nolink>(所有人是[NAME_SLURL]) <form name="form"> <button name="Gotopage" text="前往頁面"/> <button name="Cancel" text="取消"/> @@ -3246,11 +3253,15 @@ SHA1 指紋:[MD5_DIGEST] <notification name="AttachmentSaved"> 附件已儲存。 </notification> - <notification name="PresetNotSaved"> - 儲存預設名稱[NAME]時出錯。 + <notification name="AppearanceToXMLSaved"> + 外觀已經存成位於[PATH]的XML </notification> - <notification name="PresetNotDeleted"> - 刪除預設名稱[NAME]時出錯。 + <notification name="AppearanceToXMLFailed"> + 將外觀存為XML失敗。 + icon="notifytip.tga" + name="PresetNotDeleted" + type="notifytip"> +刪除預設名稱[NAME]時出錯。 </notification> <notification name="UnableToFindHelpTopic"> 找不到這個元件的幫助主題。 @@ -4065,6 +4076,9 @@ SHA1 指紋:[MD5_DIGEST] <notification name="CantAttachNotEnoughScriptResources"> 腳本資源不足,無法附著物件! </notification> + <notification name="IllegalAttachment"> + 這個附件要求了化身上不存在的點。 因此已將該附件附著到胸部。 + </notification> <notification name="CantDropItemTrialUser"> 你無法在此卸除物件,請到「自由嘗試」區域再試。 </notification> diff --git a/indra/newview/skins/default/xui/zh/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/zh/panel_preferences_alerts.xml index 94eb3c1389..212880df55 100644 --- a/indra/newview/skins/default/xui/zh/panel_preferences_alerts.xml +++ b/indra/newview/skins/default/xui/zh/panel_preferences_alerts.xml @@ -3,8 +3,9 @@ <text name="tell_me_label"> 告訴我: </text> - <check_box label="當我花費或取得 L$" name="notify_money_change_checkbox"/> + <check_box label="當我花用 L$ 時" name="notify_money_spend_checkbox"/> <check_box label="當我的朋友上線或離線" name="friends_online_notify_checkbox"/> + <check_box label="當我得到 L$ 時" name="notify_money_received_checkbox"/> <text name="show_label"> 總是顯示: </text> diff --git a/indra/newview/skins/default/xui/zh/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/zh/panel_preferences_graphics1.xml index 8c4d2f9c18..b5c36668f6 100644 --- a/indra/newview/skins/default/xui/zh/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/zh/panel_preferences_graphics1.xml @@ -24,10 +24,15 @@ <text name="BetterText"> 最佳 </text> + <slider label="化身最大複雜度:" name="IndirectMaxComplexity" tool_tip="控制在何時機下讓複雜化身呈像為 JellyDoll"/> + <text name="IndirectMaxComplexityText"> + 0 + </text> <check_box initial_value="true" label="大氣著色" name="WindLightUseAtmosShaders"/> <check_box initial_value="true" label="進階照明模型" name="UseLightShaders"/> <button label="將設定存為預設值 …" name="PrefSaveButton"/> <button label="載入預設..." name="PrefLoadButton"/> + min_val="0.125" <button label="刪除自訂配置…" name="PrefDeleteButton"/> <button label="重設為我們建議的設定" name="Defaults"/> <button label="進階設定…" name="AdvancedSettings"/> diff --git a/indra/newview/skins/default/xui/zh/panel_sound_devices.xml b/indra/newview/skins/default/xui/zh/panel_sound_devices.xml index fa4e24a605..e29ffe31af 100644 --- a/indra/newview/skins/default/xui/zh/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/zh/panel_sound_devices.xml @@ -16,9 +16,9 @@ 輸出 </text> <text name="My volume label"> - 我的音量: + 麥克風音量: </text> - <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="用這控制條改變音量"/> + <slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="用這個控制條調整麥克風音量"/> <text name="wait_text"> 請稍候 </text> diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml index 2ce310b224..5ce5adf3f0 100644 --- a/indra/newview/skins/default/xui/zh/strings.xml +++ b/indra/newview/skins/default/xui/zh/strings.xml @@ -41,6 +41,9 @@ [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([CHANNEL]) [[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]] </string> + <string name="BuildConfig"> + 建製設置 [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]) 第二人生URL:<nolink>[SLURL]</nolink> @@ -72,6 +75,9 @@ LLCEFLib/CEF版本:[LLCEFLIB_VERSION] <string name="ErrorFetchingServerReleaseNotesURL"> 擷取伺服器版本說明 URL 時出錯。 </string> + <string name="BuildConfiguration"> + 建製設置 + </string> <string name="ProgressRestoring"> 回存中... </string> @@ -1382,6 +1388,9 @@ http://secondlife.com/viewer-access-faq <string name="BodyPartsRightLeg"> 右腿 </string> + <string name="BodyPartsEnhancedSkeleton"> + 增強版骨架 + </string> <string name="GraphicsQualityLow"> 低 </string> @@ -1830,6 +1839,51 @@ http://secondlife.com/viewer-access-faq <string name="Avatar Center"> 化身中心 </string> + <string name="Left Ring Finger"> + 左無名指 + </string> + <string name="Right Ring Finger"> + 右無名指 + </string> + <string name="Tail Base"> + 尾巴基部 + </string> + <string name="Tail Tip"> + 尾巴末梢 + </string> + <string name="Left Wing"> + 左翼 + </string> + <string name="Right Wing"> + 右翼 + </string> + <string name="Jaw"> + 顎 + </string> + <string name="Alt Left Ear"> + 替代左耳 + </string> + <string name="Alt Right Ear"> + 替代右耳 + </string> + <string name="Alt Left Eye"> + 替代左眼 + </string> + <string name="Alt Right Eye"> + 替代右眼 + </string> + <string name="Tongue"> + 舌頭 + </string> + <string name="Groin"> + 鼠蹊 + </string> + <string name="Left Hind Foot"> + 左後腳 + </string> + <string name="Right Hind Foot"> + 右後腳 + </string> <string name="Invalid Attachment"> 無效的附接點 </string> @@ -2219,12 +2273,12 @@ http://secondlife.com/viewer-access-faq <string name="ATTACH_BELLY"> 腹部 </string> - <string name="ATTACH_RPEC"> - 右胸肌 - </string> - <string name="ATTACH_LPEC"> + <string name="ATTACH_LEFT_PEC"> 左胸肌 </string> + <string name="ATTACH_RIGHT_PEC"> + 右胸肌 + </string> <string name="ATTACH_HUD_CENTER_2"> 擡頭顯示中央 2 </string> @@ -2255,6 +2309,51 @@ http://secondlife.com/viewer-access-faq <string name="ATTACH_AVATAR_CENTER"> 化身中心 </string> + <string name="ATTACH_LHAND_RING1"> + 左無名指 + </string> + <string name="ATTACH_RHAND_RING1"> + 右無名指 + </string> + <string name="ATTACH_TAIL_BASE"> + 尾巴基部 + </string> + <string name="ATTACH_TAIL_TIP"> + 尾巴末梢 + </string> + <string name="ATTACH_LWING"> + 左翼 + </string> + <string name="ATTACH_RWING"> + 右翼 + </string> + <string name="ATTACH_FACE_JAW"> + 顎 + </string> + <string name="ATTACH_FACE_LEAR"> + 替代左耳 + </string> + <string name="ATTACH_FACE_REAR"> + 替代右耳 + </string> + <string name="ATTACH_FACE_LEYE"> + 替代左眼 + </string> + <string name="ATTACH_FACE_REYE"> + 替代右眼 + </string> + <string name="ATTACH_FACE_TONGUE"> + 舌頭 + </string> + <string name="ATTACH_GROIN"> + 鼠蹊 + </string> + <string name="ATTACH_HIND_LFOOT"> + 左後腳 + </string> + <string name="ATTACH_HIND_RFOOT"> + 右後腳 + </string> <string name="CursorPos"> 橫行 [LINE],縱列 [COLUMN] </string> @@ -4244,6 +4343,12 @@ http://secondlife.com/viewer-access-faq <string name="OfflineStatus"> 離線 </string> + <string name="not_online_msg"> + 使用者不在線上 - 訊息將留存,稍後傳遞。 + </string> + <string name="not_online_inventory"> + 使用者不在線上 - 收納區已儲存。 + </string> <string name="answered_call"> 你的通話已經接通 </string> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 1b0334498e..b603157ca7 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -136,6 +136,7 @@ void LLGridManager::addSystemGrid(const std::string& label, const std::string& helper, const std::string& login_page, const std::string& update_url_base, + const std::string& web_profile_url, const std::string& login_id) { } diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index f3d89bb866..66d730d1ac 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -444,6 +444,11 @@ class Windows_i686_Manifest(ViewerManifest): self.path("media_plugin_cef.dll") self.end_prefix() + # Media plugins - LibVLC + if self.prefix(src='../media_plugins/libvlc/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_libvlc.dll") + self.end_prefix() + # winmm.dll shim if self.prefix(src='../media_plugins/winmmshim/%s' % self.args['configuration'], dst=""): self.path("winmm.dll") @@ -550,6 +555,12 @@ class Windows_i686_Manifest(ViewerManifest): self.path("zh-TW.pak") self.end_prefix() + if self.prefix(src=os.path.join(os.pardir, 'packages', 'bin', 'release'), dst="llplugin"): + self.path("libvlc.dll") + self.path("libvlccore.dll") + self.path("plugins/") + self.end_prefix() + # pull in the crash logger and updater from other projects # tag:"crash-logger" here as a cue to the exporter self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], @@ -1089,8 +1100,18 @@ class LinuxManifest(ViewerManifest): # plugins if self.prefix(src="", dst="bin/llplugin"): self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so") + self.path("../media_plugins/libvlc/libmedia_plugin_libvlc.so", "libmedia_plugin_libvlc.so") self.end_prefix("bin/llplugin") + if self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'vlc', 'plugins'), dst="bin/llplugin/vlc/plugins"): + self.path( "plugins.dat" ) + self.path( "*/*.so" ) + self.end_prefix() + + if self.prefix(src=os.path.join(os.pardir, 'packages', 'lib' ), dst="lib"): + self.path( "libvlc*.so*" ) + self.end_prefix() + # llcommon if not self.path("../llcommon/libllcommon.so", "lib/libllcommon.so"): print "Skipping llcommon.so (assuming llcommon was linked statically)" @@ -1144,7 +1165,7 @@ class LinuxManifest(ViewerManifest): def strip_binaries(self): if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer(): print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build" - self.run_command(r"find %(d)r/bin %(d)r/lib -type f \! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure + self.run_command(r"find %(d)r/bin %(d)r/lib -type f \! -name update_install \! -name *.dat | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure class Linux_i686_Manifest(LinuxManifest): def construct(self): diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index 53d4acc9e0..c767d52c7b 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -42,6 +42,8 @@ #include "llevents.h" #include "lleventfilter.h" #include "lleventcoro.h" +#include "llexception.h" +#include "stringize.h" //********************* // LLLogin @@ -128,30 +130,23 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params) void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) { - try - { - LLSD printable_params = login_params; - //if(printable_params.has("params") - // && printable_params["params"].has("passwd")) - //{ - // printable_params["params"]["passwd"] = "*******"; - //} - LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName() + LLSD printable_params = login_params; + if (printable_params.has("params") + && printable_params["params"].has("passwd")) + { + printable_params["params"]["passwd"] = "*******"; + } + try + { + LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName() << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL; - // Arriving in SRVRequest state - LLEventStream replyPump("SRVreply", true); - // Should be an array of one or more uri strings. - LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); // EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used // to share them -- but the EXT-3934 fix made it possible for an abandoned // SRV response to arrive just as we were expecting the XMLRPC response. LLEventStream loginReplyPump("loginreply", true); - // Loop through the rewrittenURIs, counting attempts along the way. - // Because of possible redirect responses, we may make more than one - // attempt per rewrittenURIs entry. LLSD::Integer attempts = 0; LLSD request(login_params); @@ -167,11 +162,11 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) LLSD progress_data; progress_data["attempt"] = attempts; progress_data["request"] = request; - if(progress_data["request"].has("params") - && progress_data["request"]["params"].has("passwd")) - { - progress_data["request"]["params"]["passwd"] = "*******"; - } + if (progress_data["request"].has("params") + && progress_data["request"]["params"].has("passwd")) + { + progress_data["request"]["params"]["passwd"] = "*******"; + } sendProgressEvent("offline", "authenticating", progress_data); // We expect zero or more "Downloading" status events, followed by @@ -189,8 +184,8 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) // Still Downloading -- send progress update. sendProgressEvent("offline", "downloading"); } - - LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL; + + LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL; status = mAuthResponse["status"].asString(); // Okay, we've received our final status event for this @@ -202,7 +197,7 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) break; } - sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]); + sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]); // Here the login service at the current URI is redirecting us // to some other URI ("indeterminate" -- why not "redirect"?). @@ -212,8 +207,7 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) request["method"] = mAuthResponse["responses"]["next_method"].asString(); } // loop back to try the redirected URI - // Here we're done with redirects for the current rewrittenURIs - // entry. + // Here we're done with redirects. if (status == "Complete") { // StatusComplete does not imply auth success. Check the @@ -230,14 +224,14 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) return; // Done! } -// /* Sometimes we end with "Started" here. Slightly slow server? -// * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below. -// */ -// if( status == "Started") -// { -// LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL; -// continue; -// } +// /* Sometimes we end with "Started" here. Slightly slow server? +// * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below. +// */ +// if( status == "Started") +// { +// LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL; +// continue; +// } // If we don't recognize status at all, trouble if (! (status == "CURLError" @@ -250,27 +244,25 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) } // Here status IS one of the errors tested above. - - // Here we got through all the rewrittenURIs without succeeding. Tell - // caller this didn't work out so well. Of course, the only failure data - // we can reasonably show are from the last of the rewrittenURIs. - - // *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an - // llsd with no "responses" node. To make the output from an incomplete login symmetrical - // to success, add a data/message and data/reason fields. - LLSD error_response; - error_response["reason"] = mAuthResponse["status"]; - error_response["errorcode"] = mAuthResponse["errorcode"]; - error_response["message"] = mAuthResponse["error"]; - if(mAuthResponse.has("certificate")) - { - error_response["certificate"] = mAuthResponse["certificate"]; - } - sendProgressEvent("offline", "fail.login", error_response); - } - catch (...) { - LL_ERRS() << "login exception caught" << LL_ENDL; - } + // Tell caller this didn't work out so well. + + // *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an + // llsd with no "responses" node. To make the output from an incomplete login symmetrical + // to success, add a data/message and data/reason fields. + LLSD error_response; + error_response["reason"] = mAuthResponse["status"]; + error_response["errorcode"] = mAuthResponse["errorcode"]; + error_response["message"] = mAuthResponse["error"]; + if(mAuthResponse.has("certificate")) + { + error_response["certificate"] = mAuthResponse["certificate"]; + } + sendProgressEvent("offline", "fail.login", error_response); + } + catch (...) { + CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName() + << "('" << uri << "', " << printable_params << ")")); + } } void LLLogin::Impl::disconnect() diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index cd4b108c1a..04e0395c50 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -30,7 +30,6 @@ #include "llexception.h" #include <boost/format.hpp> #include <boost/lexical_cast.hpp> -#include <boost/throw_exception.hpp> #include <curl/curl.h> #include "lldir.h" #include "llevents.h" @@ -468,7 +467,7 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u if(!mCurl) { - BOOST_THROW_EXCEPTION(DownloadError("failed to initialize curl")); + LLTHROW(DownloadError("failed to initialize curl")); } throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_NOSIGNAL, true)); throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_FOLLOWLOCATION, true)); @@ -509,7 +508,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte) mHeaderList = curl_slist_append(mHeaderList, rangeHeaderFormat.str().c_str()); if(mHeaderList == 0) { - BOOST_THROW_EXCEPTION(DownloadError("cannot add Range header")); + LLTHROW(DownloadError("cannot add Range header")); } throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HTTPHEADER, mHeaderList)); @@ -525,7 +524,7 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std mDownloadData["hash"] = hash; mDownloadData["current_version"] = ll_get_version(); LLSD path = uri.pathArray(); - if(path.size() == 0) BOOST_THROW_EXCEPTION(DownloadError("no file path")); + if(path.size() == 0) LLTHROW(DownloadError("no file path")); std::string fileName = path[path.size() - 1].asString(); std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName); mDownloadData["path"] = filePath; @@ -548,9 +547,9 @@ void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code) if(code != CURLE_OK) { const char * errorString = curl_easy_strerror(code); if(errorString != 0) { - BOOST_THROW_EXCEPTION(DownloadError(curl_easy_strerror(code))); + LLTHROW(DownloadError(curl_easy_strerror(code))); } else { - BOOST_THROW_EXCEPTION(DownloadError("unknown curl error")); + LLTHROW(DownloadError("unknown curl error")); } } else { ; // No op. diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp index 9f9a08f590..1c7629da23 100644 --- a/indra/viewer_components/updater/llupdateinstaller.cpp +++ b/indra/viewer_components/updater/llupdateinstaller.cpp @@ -36,7 +36,6 @@ #pragma warning(disable: 4702) // disable 'unreachable code' so we can use lexical_cast (really!). #endif #include <boost/lexical_cast.hpp> -#include <boost/throw_exception.hpp> namespace { struct RelocateError: public LLException @@ -49,7 +48,7 @@ namespace { std::string scriptFile = gDirUtilp->getBaseFileName(path); std::string newPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, scriptFile); apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, gAPRPoolp); - if(status != APR_SUCCESS) BOOST_THROW_EXCEPTION(RelocateError()); + if(status != APR_SUCCESS) LLTHROW(RelocateError()); return newPath; } diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index 0bdd1ede43..1665e41e70 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -32,10 +32,10 @@ #include "lltimer.h" #include "llupdatechecker.h" #include "llupdateinstaller.h" +#include "llexception.h" #include <boost/scoped_ptr.hpp> #include <boost/weak_ptr.hpp> -#include <boost/throw_exception.hpp> #include "lldir.h" #include "llsdserialize.h" #include "llfile.h" @@ -191,9 +191,8 @@ void LLUpdaterServiceImpl::initialize(const std::string& channel, { if(mIsChecking || mIsDownloading) { - BOOST_THROW_EXCEPTION( - LLUpdaterService::UsageError("LLUpdaterService::initialize call " - "while updater is running.")); + LLTHROW(LLUpdaterService::UsageError("LLUpdaterService::initialize call " + "while updater is running.")); } mChannel = channel; @@ -224,9 +223,8 @@ void LLUpdaterServiceImpl::startChecking(bool install_if_ready) { if(mChannel.empty() || mVersion.empty()) { - BOOST_THROW_EXCEPTION( - LLUpdaterService::UsageError("Set params before call to " - "LLUpdaterService::startCheck().")); + LLTHROW(LLUpdaterService::UsageError("Set params before call to " + "LLUpdaterService::startCheck().")); } mIsChecking = true; |