Apertura del repositorio

This commit is contained in:
2025-05-24 18:09:39 -03:00
parent 76e6359dad
commit d883ddd0d0
35253 changed files with 2891973 additions and 2 deletions
+27
View File
@@ -0,0 +1,27 @@
/**
* @file
* @brief
*
* $LicenseInfo:firstyear=2025&license=fsviewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2025, The Phoenix Firestorm Project, 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
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
Executable
+502
View File
@@ -0,0 +1,502 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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; either
version 2.1 of the License, or (at your option) any later version.
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
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
+27
View File
@@ -0,0 +1,27 @@
/**
* @file
* @brief
*
* $LicenseInfo:firstyear=2025&license=fsviewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2025, The Phoenix Firestorm Project, 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
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
+23 -2
View File
@@ -1,3 +1,24 @@
# Puma_Viewer
<img align="left" width="100" height="100" src="doc/puma_256.png" alt="Logo of Puma viewer"/>
**[Puma](https://avataresargentinos.com.ar) is a free client for 3D virtual worlds such as Second Life and various OpenSim worlds where users can create, connect and chat with others from around the world.**
This repository contains the official source code for the Firestorm viewer.
## Open Source
Puma is a third party viewer derived from the official [Second Life](https://github.com/secondlife/viewer) client. The client codebase has been open source since 2007 and is available under the LGPL license.
## Download
Pre-built versions of the viewer releases for Windows, Mac and Linux can be downloaded from the [official website](https://avataresargentinos.com.ar/descargas/).
## Build Instructions
Build instructions for each operating system can be found using the links below and in the official [wiki](https://wiki.avataresargentinos.com.ar).
- [Windows](doc/building_windows.md)
- [Mac](doc/building_macos.md)
- [Linux](doc/building_linux.md)
## Contribute
Visor Puma para Second Life y Opensim
+4210
View File
File diff suppressed because it is too large Load Diff
Executable
+556
View File
@@ -0,0 +1,556 @@
#!/usr/bin/env bash
# This is the custom build script for the viewer
#
# It must be run by the Linden Lab build farm shared buildscript because
# it relies on the environment that sets up, functions it provides, and
# the build result post-processing it does.
#
# PLEASE NOTE:
#
# * This script is interpreted on three platforms, including windows and cygwin
# Cygwin can be tricky....
# * The special style in which python is invoked is intentional to permit
# use of a native python install on windows - which requires paths in DOS form
cleanup="true"
retry_cmd()
{
max_attempts="$1"; shift
initial_wait="$1"; shift
attempt_num=1
echo "trying" "$@"
until "$@"
do
if ((attempt_num==max_attempts))
then
echo "Last attempt $attempt_num failed"
return 1
else
wait_time=$(($attempt_num*$initial_wait))
echo "Attempt $attempt_num failed. Trying again in $wait_time seconds..."
sleep $wait_time
attempt_num=$(($attempt_num+1))
fi
done
echo "succeeded"
return 0
}
build_dir_Darwin()
{
echo build-darwin-x86_64
}
build_dir_Linux()
{
echo build-linux-i686
}
build_dir_CYGWIN()
{
echo build-vc${AUTOBUILD_VSVER:-120}-${AUTOBUILD_ADDRSIZE}
}
viewer_channel_suffix()
{
local package_name="$1"
local suffix_var="${package_name}_viewer_channel_suffix"
local suffix=$(eval "echo \$${suffix_var}")
if [ "$suffix"x = ""x ]
then
echo ""
else
echo "_$suffix"
fi
}
installer_Darwin()
{
local package_name="$1"
local package_dir="$(build_dir_Darwin)/newview/"
local pattern=".*$(viewer_channel_suffix ${package_name})_[0-9]+_[0-9]+_[0-9]+_[0-9]+_x86_64\\.dmg\$"
# since the additional packages are built after the base package,
# sorting oldest first ensures that the unqualified package is returned
# even if someone makes a qualified name that duplicates the last word of the base name
local package=$(ls -1tr "$package_dir" 2>/dev/null | grep -E "$pattern" | head -n 1)
test "$package"x != ""x && echo "$package_dir/$package"
}
installer_Linux()
{
local package_name="$1"
local package_dir="$(build_dir_Linux)/newview/"
local pattern=".*$(viewer_channel_suffix ${package_name})_[0-9]+_[0-9]+_[0-9]+_[0-9]+_i686\\.tar\\.xz\$"
# since the additional packages are built after the base package,
# sorting oldest first ensures that the unqualified package is returned
# even if someone makes a qualified name that duplicates the last word of the base name
package=$(ls -1tr "$package_dir" 2>/dev/null | grep -E "$pattern" | head -n 1)
test "$package"x != ""x && echo "$package_dir/$package"
}
installer_CYGWIN()
{
local package_name="$1"
local variant=${last_built_variant:-Release}
local build_dir=$(build_dir_CYGWIN ${variant})
local package_dir
if [ "$package_name"x = ""x ]
then
package_dir="${build_dir}/newview/${variant}"
else
package_dir="${build_dir}/newview/${package_name}/${variant}"
fi
if [ -r "${package_dir}/touched.bat" ]
then
local package_file=$(sed 's:.*=::' "${package_dir}/touched.bat")
echo "${package_dir}/${package_file}"
fi
}
# if someone wants to run build.sh outside the GitHub environment
[[ -n "$GITHUB_OUTPUT" ]] || export GITHUB_OUTPUT='/dev/null'
# The following is based on the Warning for GitHub multiline output strings:
# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
# Build up these arrays as we go
metadata=()
symbolfile=()
physicstpv=()
# and dump them to GITHUB_OUTPUT when done
cleanup="$cleanup ; \
arrayoutput metadata ; \
arrayoutput symbolfile ; \
arrayoutput physicstpv"
trap "$cleanup" EXIT
arrayoutput()
{
local outputname="$1"
# append "[*]" to the array name so array indirection works
local array="$1[*]"
local IFS='
'
echo "$outputname<<$EOF
${!array}
$EOF" >> "$GITHUB_OUTPUT"
}
pre_build()
{
local variant="$1"
begin_section "Configure $variant"
[ -n "$master_message_template_checkout" ] \
&& [ -r "$master_message_template_checkout/message_template.msg" ] \
&& template_verifier_master_url="-DTEMPLATE_VERIFIER_MASTER_URL=file://$master_message_template_checkout/message_template.msg"
RELEASE_CRASH_REPORTING=OFF
HAVOK=OFF
SIGNING=()
if [[ "$variant" != *OS ]]
then
# Proprietary builds
RELEASE_CRASH_REPORTING=ON
HAVOK=ON
if [[ "$arch" == "Darwin" ]]
then
SIGNING=("-DENABLE_SIGNING:BOOL=YES" \
"-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.")
fi
fi
if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ]
then
case "$arch" in
CYGWIN)
symplat="windows"
;;
Darwin)
symplat="darwin"
;;
Linux)
symplat="linux"
;;
esac
# This name is consumed by indra/newview/CMakeLists.txt. Make it
# absolute because we've had troubles with relative pathnames.
abs_build_dir="$(cd "$build_dir"; pwd)"
VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/symbols/$variant/${viewer_channel}.sym.tar.xz")"
fi
# honor autobuild_configure_parameters same as sling-buildscripts
eval_autobuild_configure_parameters=$(eval $(echo echo $autobuild_configure_parameters))
"$autobuild" configure --quiet -c $variant \
${eval_autobuild_configure_parameters:---} \
-DLL_TESTS:BOOL=ON \
-DPACKAGE:BOOL=ON \
-DHAVOK:BOOL="$HAVOK" \
-DRELEASE_CRASH_REPORTING:BOOL="$RELEASE_CRASH_REPORTING" \
-DVIEWER_SYMBOL_FILE:STRING="${VIEWER_SYMBOL_FILE:-}" \
-DBUGSPLAT_DB:STRING="${BUGSPLAT_DB:-}" \
-DVIEWER_CHANNEL:STRING="${viewer_channel}" \
-DGRID:STRING="\"$viewer_grid\"" \
-DTEMPLATE_VERIFIER_OPTIONS:STRING="$template_verifier_options" $template_verifier_master_url \
"${SIGNING[@]}" \
|| fatal "$variant configuration failed"
end_section "Configure $variant"
}
package_llphysicsextensions_tpv()
{
begin_section "PhysicsExtensions_TPV"
tpv_status=0
# nat 2016-12-21: without HAVOK, can't build PhysicsExtensions_TPV.
if [ "$variant" = "Release" -a "${HAVOK:-}" != "OFF" ]
then
tpvconfig="$build_dir/packages/llphysicsextensions/autobuild-tpv.xml"
test -r "$tpvconfig" || fatal "No llphysicsextensions_tpv autobuild configuration found"
# SL-19942: autobuild ignores -c switch if AUTOBUILD_CONFIGURATION set
unset AUTOBUILD_CONFIGURATION
"$autobuild" build --quiet --config-file "$(native_path "$tpvconfig")" -c Tpv \
|| fatal "failed to build llphysicsextensions_tpv"
# capture the package file name for use in upload later...
PKGTMP=`mktemp -t pgktpv.XXXXXX`
cleanup="$cleanup ; rm $PKGTMP* 2>/dev/null"
trap "$cleanup" EXIT
"$autobuild" package --quiet --config-file "$tpvconfig" --results-file "$(native_path $PKGTMP)" || fatal "failed to package llphysicsextensions_tpv"
tpv_status=$?
if [ -r "${PKGTMP}" ]
then
. "${PKGTMP}" # sets autobuild_package_{name,filename,md5}
echo "${autobuild_package_filename}" > $build_dir/llphysicsextensions_package
fi
else
record_event "Do not provide llphysicsextensions_tpv for $variant"
llphysicsextensions_package=""
fi
end_section "PhysicsExtensions_TPV"
return $tpv_status
}
build()
{
local variant="$1"
if $build_viewer
then
begin_section "autobuild $variant"
# honor autobuild_build_parameters same as sling-buildscripts
eval_autobuild_build_parameters=$(eval $(echo echo $autobuild_build_parameters))
"$autobuild" build --no-configure -c $variant \
$eval_autobuild_build_parameters \
|| fatal "failed building $variant"
echo true >"$build_dir"/build_ok
end_section "autobuild $variant"
begin_section "extensions $variant"
# Run build extensions
if [ -d ${build_dir}/packages/build-extensions ]
then
for extension in ${build_dir}/packages/build-extensions/*.sh
do
begin_section "Extension $extension"
. $extension
end_section "Extension $extension"
done
fi
# *TODO: Make this a build extension.
package_llphysicsextensions_tpv || fatal "failed building llphysicsextensions packages"
end_section "extensions $variant"
else
record_event "Skipping build due to configuration build_viewer=${build_viewer}"
echo true >"$build_dir"/build_ok
fi
}
################################################################
# Start of the actual script
################################################################
# Check to see if we were invoked from the master buildscripts wrapper, if not, fail
if [ "x${BUILDSCRIPTS_SUPPORT_FUNCTIONS}" = x ]
then
echo "This script relies on being run by the master Linden Lab buildscripts" 1>&2
exit 1
fi
shopt -s nullglob # if nothing matches a glob, expand to nothing
initialize_build # provided by master buildscripts build.sh
begin_section "autobuild initialize"
# ensure AUTOBUILD is in native path form for child processes
AUTOBUILD="$(native_path "$AUTOBUILD")"
# set "$autobuild" to cygwin path form for use locally in this script
autobuild="$(shell_path "$AUTOBUILD")"
if [ ! -x "$autobuild" ]
then
record_failure "AUTOBUILD not executable: '$autobuild'"
exit 1
fi
# load autobuild provided shell functions and variables
"$autobuild" --quiet source_environment > "$build_log_dir/source_environment"
PYTHONPATH="$BUILDSCRIPTS_SHARED/packages/lib/python:$PYTHONPATH"
begin_section "dump source environment commands"
cat "$build_log_dir/source_environment"
end_section "dump source environment commands"
begin_section "execute source environment commands"
. "$build_log_dir/source_environment"
end_section "execute source environment commands"
end_section "autobuild initialize"
# something about the additional_packages mechanism messes up buildscripts results.py on Linux
# since we don't care about those packages on Linux, just zero it out, yes - a HACK
if [ "$arch" = "Linux" ]
then
export additional_packages=
fi
begin_section "select viewer channel"
# Look for a branch-specific viewer_channel setting
# changeset_branch is set in the sling-buildscripts
viewer_build_branch=$(echo -n "${changeset_branch:-$(repo_branch ${BUILDSCRIPTS_SRC:-$(pwd)})}" | tr -Cs 'A-Za-z0-9_' '_' | sed -E 's/^_+//; s/_+$//')
if [ -n "$viewer_build_branch" ]
then
branch_viewer_channel_var="${viewer_build_branch}_viewer_channel"
if [ -n "${!branch_viewer_channel_var}" ]
then
viewer_channel="${!branch_viewer_channel_var}"
record_event "Overriding viewer_channel for branch '$changeset_branch' to '$viewer_channel'"
else
record_event "No branch-specific viewer_channel for branch '$viewer_build_branch'; to set a branch build channel set '$branch_viewer_channel_var'"
fi
fi
end_section "select viewer channel"
python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel}"
initialize_version # provided by buildscripts build.sh; sets version id
begin_section "coding policy check"
# On our TC Windows build hosts, the GitPython library underlying our
# coding_policy_git.py script fails to run git for reasons we have not tried
# to diagnose. Clearly git works fine on those hosts, or we would never get
# this far. Running coding policy checks on one platform *should* suffice...
if [[ "$arch" == "Darwin" ]]
then
git_hooks_reqs="$git_hooks_checkout/requirements.txt"
if [[ -r "$(shell_path "$git_hooks_reqs")" ]]
then
# install the git-hooks dependencies
pip install -r "$(native_path "$git_hooks_reqs")" || \
fatal "pip install git-hooks failed"
fi
git_hooks_script="$git_hooks_checkout/coding_policy_git.py"
if [[ -r "$(shell_path "$git_hooks_script")" ]]
then
# validate the branch we're about to build
python_cmd "$(native_path "$git_hooks_script")" --all_files || \
fatal "coding policy check failed"
fi
fi
end_section "coding policy check"
# Now run the build
succeeded=true
last_built_variant=
for variant in $variants
do
# Only the last built arch is available for upload
last_built_variant="$variant"
build_dir=`build_dir_$arch $variant`
begin_section "Initialize $variant Build Directory"
rm -rf "$build_dir"
mkdir -p "$build_dir/tmp"
end_section "Initialize $variant Build Directory"
if pre_build "$variant" "$build_dir"
then
begin_section "Build $variant"
build "$variant" "$build_dir"
end_section "Build $variant"
begin_section "post-build $variant"
if `cat "$build_dir/build_ok"`
then
case "$variant" in
Release)
if [ -r "$build_dir/autobuild-package.xml" ]
then
begin_section "Autobuild metadata"
python_cmd "$helpers/codeticket.py" addoutput "Autobuild Metadata" "$build_dir/autobuild-package.xml" --mimetype text/xml \
|| fatal "Upload of autobuild metadata failed"
metadata+=("$build_dir/autobuild-package.xml")
if [ "$arch" != "Linux" ]
then
record_dependencies_graph "$build_dir/autobuild-package.xml" # defined in buildscripts/hg/bin/build.sh
else
record_event "TBD - no dependency graph for linux (probable python version dependency)"
fi
end_section "Autobuild metadata"
else
record_event "no autobuild metadata at '$build_dir/autobuild-package.xml'"
fi
if [ -r "$build_dir/newview/viewer_version.txt" ]
then
begin_section "Viewer Version"
viewer_version="$(<"$build_dir/newview/viewer_version.txt")"
python_cmd "$helpers/codeticket.py" addoutput "Viewer Version" "$viewer_version" --mimetype inline-text \
|| fatal "Upload of viewer version failed"
metadata+=("$build_dir/newview/viewer_version.txt")
echo "viewer_version=$viewer_version" >> "$GITHUB_OUTPUT"
end_section "Viewer Version"
fi
;;
Doxygen)
if [ -r "$build_dir/doxygen_warnings.log" ]
then
record_event "Doxygen warnings generated; see doxygen_warnings.log"
python_cmd "$helpers/codeticket.py" addoutput "Doxygen Log" "$build_dir/doxygen_warnings.log" --mimetype text/plain ## TBD
metadata+=("$build_dir/doxygen_warnings.log")
fi
if [ -d "$build_dir/doxygen/html" ]
then
tar -cJf "$build_dir/viewer-doxygen.tar.xz" --strip-components 3 "$build_dir/doxygen/html"
python_cmd "$helpers/codeticket.py" addoutput "Doxygen Tarball" "$build_dir/viewer-doxygen.tar.xz" \
|| fatal "Upload of doxygen tarball failed"
metadata+=("$build_dir/viewer-doxygen.tar.xz")
fi
;;
*)
;;
esac
else
record_failure "Build of \"$variant\" failed."
fi
end_section "post-build $variant"
else
record_event "configure for $variant failed: build skipped"
fi
if ! $succeeded
then
record_event "remaining variants skipped due to $variant failure"
break
fi
done
# build debian package
if [ "$arch" == "Linux" ]
then
if $succeeded
then
if $build_viewer_deb && [ "$last_built_variant" == "Release" ]
then
begin_section "Build Viewer Debian Package"
# mangle the changelog
dch --force-bad-version \
--distribution unstable \
--newversion "${VIEWER_VERSION}" \
"Automated build #$build_id, repository $branch revision $revision."
# build the debian package
$pkg_default_debuild_command || record_failure "\"$pkg_default_debuild_command\" failed."
# Unmangle the changelog file
hg revert debian/changelog
end_section "Build Viewer Debian Package"
# Run debian extensions
if [ -d ${build_dir}/packages/debian-extensions ]; then
for extension in ${build_dir}/packages/debian-extensions/*.sh; do
. $extension
done
fi
# Move any .deb results.
mv ${build_dir}/packages/*.deb ../ 2>/dev/null || true
# upload debian package and create repository
begin_section "Upload Debian Repository"
for deb_file in `/bin/ls ../packages_public/*.deb ../*.deb 2>/dev/null`; do
deb_pkg=$(basename "$deb_file" | sed 's,_.*,,')
python_cmd "$helpers/codeticket.py" addoutput "Debian $deb_pkg" $deb_file \
|| fatal "Upload of debian $deb_pkg failed"
done
for deb_file in `/bin/ls ../packages_private/*.deb 2>/dev/null`; do
deb_pkg=$(basename "$deb_file" | sed 's,_.*,,')
python_cmd "$helpers/codeticket.py" addoutput "Debian $deb_pkg" "$deb_file" --private \
|| fatal "Upload of debian $deb_pkg failed"
done
create_deb_repo
# Rename the local debian_repo* directories so that the master buildscript
# doesn't make a remote repo again.
for debian_repo_type in debian_repo debian_repo_private; do
if [ -d "$build_log_dir/$debian_repo_type" ]; then
mv $build_log_dir/$debian_repo_type $build_log_dir/${debian_repo_type}_pushed
fi
done
end_section "Upload Debian Repository"
else
record_event "debian build not enabled"
fi
else
record_event "skipping debian build due to failed build"
fi
fi
# check status and upload results to S3
if $succeeded
then
if $build_viewer
then
begin_section "Uploads"
# nat 2016-12-22: without RELEASE_CRASH_REPORTING, we have no symbol file.
if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ]
then
# e.g. build-darwin-x86_64/symbols/Release/Second Life Test.xarchive.zip
symbol_file="${build_dir}/symbols/${variant}/${viewer_channel}.xcarchive.zip"
if [[ ! -f "$symbol_file" ]]
then
# symbol tarball we prep for (e.g.) Breakpad
symbol_file="$VIEWER_SYMBOL_FILE"
fi
# Upload crash reporter file
symbolfile+=("$symbol_file")
fi
# Upload the llphysicsextensions_tpv package, if one was produced
# Only upload this package when building the private repo so the
# artifact is private.
if [[ "x$GITHUB_REPOSITORY" == "xsecondlife/viewer-private" && \
-r "$build_dir/llphysicsextensions_package" ]]
then
llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package)
physicstpv+=("$llphysicsextensions_package")
fi
end_section "Uploads"
else
record_event "skipping upload of installer"
fi
else
record_event "skipping upload of installer due to failed build"
fi
# The branch independent build.sh script invoking this script will finish processing
$succeeded || exit 1
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/env bash
if [ $# -eq 0 ]
then
echo "USAGE: $0 <OS|SL>"
exit 1
fi
if [ $1 == "SL" ] || [ $1 == "OS" ]
then
[ $1 == "SL" ] && l="OS" || l="SL"
else
if [ $1 == "test" ] || [ $1 == "?" ]
then
if [ -d "./build-vc150-64" ]
then
c="Unknown"
if [ ! -d "./build-vc150-64-SL" ] && [ -d "./build-vc150-64-OS" ]
then
c="SL"
fi
if [ -d "./build-vc150-64-SL" ] && [ ! -d "./build-vc150-64-OS" ]
then
c="OS"
fi
echo "Current build is for $c"
else
echo "No build configured"
fi
exit 0
else
echo "Invalid target $1"
echo "USAGE: $0 <OS|SL>"
exit 2
fi
fi
t=$1
if [ -d "./build-vc150-64" ]
then
if [ ! -d "./build-vc150-64-$t" ]
then
# live folder exists
# target does not so we are probably good to go
echo "$t already setup"
exit 0
else
# target folder exists so probably means that the setup is for the alternate
if [ ! -d "./build-vc150-64-$l" ]
then
# alternate folder not found so we rename the live target back to this
echo "Currently setup for $l. Renaming default back to $l"
`mv ./build-vc150-64 ./build-vc150-64-$l`
else
# no LAST and no TARGET exists so this is not in the right state
echo "Not setup for multi-target"
exit 3
fi
fi
fi
if [ -d "./build-vc150-64-$t" ]
then
# live folder exists
# target does not so we are probably good to go
echo "renaming $t to default"
`mv ./build-vc150-64-$t ./build-vc150-64`
else
echo "Not setup for target $t"
exit 4
fi
+60
View File
@@ -0,0 +1,60 @@
# standalone functions from sling-buildscripts
set_build_number_to_revision()
{
record_event "buildNumber $revision"
}
record_event()
{
echo "=== $@"
}
begin_section()
{
record_event "START $*"
sections+=("$*")
}
end_section()
{
# accommodate dumb Mac bash 3, which doesn't understand array[-1]
local last=$(( ${#sections[@]} - 1 ))
record_event "END ${*:-${sections[$last]}}"
unset "sections[$last]"
}
record_success()
{
record_event "SUCCESS $*"
}
record_failure()
{
record_event "FAILURE $*" >&2
}
fatal()
{
record_failure "$@"
finalize false
exit 1
}
# redefined fail for backward compatibility
alias fail=fatal
pass()
{
exit 0
}
export -f set_build_number_to_revision
export -f record_event
export -f begin_section
export -f end_section
export -f record_success
export -f record_failure
export -f fatal
export -f pass
export sections
+63
View File
@@ -0,0 +1,63 @@
# Firestorm Pull Request Guidelines
Thank you for submitting code to Firestorm; we will review it and merge or provide feedback in due course.
We have written this guide to help you contribute code that meets our needs. It will hopefully reduce the number of iterations required before we can merge the code.
1. **Descriptive Title**:
   - Use a clear and descriptive title for the PR.
1. **Related Issues**:
   - Reference any related issues or pull requests by including the JIRA number and description in the commit message header (e.g., `[FIRE-12345] When I click, my head falls off` or `[FIRE-12345] prevent click detaching head`).
1. **Description**:
   - Provide a detailed description of the changes. Explain why the changes are necessary and what problem they solve. If a JIRA is associated with the change, there is no need to duplicate that, but we would appreciate a summary and explanation of the fix.
1. **Comment tags (important)**:
   - We use comments to preserve the original upstream (LL) code when making modifications; this allows the person merging future code updates to see both the original code from LL and any new updates and then use those to determine whether the FS-specific changes need to be updated and reviewed.
If you are modifying LL code, we need the LL code preserved in a comment.
For example:
```c++
    int buggy_code = TRUE;
    LL_WARN() << "This code is buggy" << LL_ENDL;
```
Would become:
```c++
    // <FS> [FIRE-999] Fix the buggy code
    // int buggy_code = TRUE;
    // LL_WARN() << "This code is buggy" << LL_ENDL;
    bool fixed_code = true;
    LL_DEBUG() << "I fixed this" << LL_ENDL;
    // </FS>
```
Note: You can tag them with your initials, e.g. `<FS:YI>` or a short unique tag (shorter is better)
If you add new code, the same rules apply, but there is nothing to comment out.
This is done so that when LL updates the original code, we can see what the original code was doing, what their changes do, and how that relates to the changes that we applied on top.
A single line change can use the shorthand `<FS:YI/>`:
```c++
    bool break_stuff=true;
```
Could be fixed as follows:
```c++
    bool break_stuff=false; // <FS:Beq/> [FIRE-23456] don't break stuff.
```
The Comment tags are only required when changing code maintained upstream. If the code you are changing is in an FS-created file, RLV code, OpenSim-only code, etc., then we do not need the comments.
If the code you are changing is already inside an `//<FS>` comment block, then there is no need to add a new block, but do try to make sure that any comments align with the updates you make.
5. **Testing**:
   - Include details on how the changes should be tested. Describe the testing environment and any steps needed to verify the changes.
1. **Documentation**:
   - If the change includes a new feature, it would be beneficial to suggest how we should update the FS Wiki pages to help users understand the feature
Thank you for your contribution!
+502
View File
@@ -0,0 +1,502 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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; either
version 2.1 of the License, or (at your option) any later version.
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
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
+23
View File
@@ -0,0 +1,23 @@
COPYRIGHT AND PERMISSION NOTICE
Second Life(TM) Viewer Artwork. Copyright (C) 2008 Linden Research, Inc.
Linden Research, Inc. ("Linden Lab") licenses the Second Life viewer
artwork and other works in the files distributed with this Notice under
the Creative Commons Attribution-Share Alike 3.0 License, available at
http://creativecommons.org/licenses/by-sa/3.0/legalcode. For the license
summary, see http://creativecommons.org/licenses/by-sa/3.0/.
Notwithstanding the foregoing, all of Linden Lab's trademarks, including
but not limited to the Second Life brand name and Second Life Eye-in-Hand
logo, are subject to our trademark policy at
http://secondlife.com/corporate/brand/trademark/.
If you distribute any copies or adaptations of the Second Life viewer
artwork or any other works in these files, you must include this Notice
and clearly identify any changes made to the original works. Include
this Notice and information where copyright notices are usually included,
for example, after your own copyright notice acknowledging your use of
the Second Life viewer artwork, in a text file distributed with your
program, in your application's About window, or on a credits page for
your work.
+33
View File
@@ -0,0 +1,33 @@
Source code
========
The license for the source code in this distribution should be clearly
marked on each source file. Unless otherwise specified, the source
code in this distribution ("Source Code") is provided by Linden Lab to
you under the terms of the GNU Lesser General Public License, version 2.1
("LGPL"), unless you have obtained a separate licensing agreement
("Other License"), formally executed by you and Linden Lab. Terms of
the GPL can be found in doc/LGPL-license.txt in this distribution, or
online at
https://wiki.secondlife.com/wiki/Linden_Lab_Official:GNU_Lesser_General_Public_License,_version_2.1
By copying, modifying or distributing this software, you acknowledge
that you have read and understood your obligations described above,
and agree to abide by those obligations.
ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
COMPLETENESS OR PERFORMANCE.
Logos and trademarks
==============
"Second Life" and "Linden Lab" are registered trademarks of Linden
Research, Inc. Other trademarks include (but are not limited to): the
names Linden and Linden Research, as well as the Linden Lab Hexagon
Design and the Second Life Hand Design logos.
Use of logos and trademarks are subject to the Linden Lab trademark
policy, available at:
http://secondlife.com/corporate/trademark/
+277
View File
@@ -0,0 +1,277 @@
# Build instructions for Linux
> [!WARNING]
> Please note that we do not give support for compiling the viewer on your own. However, there is a self-compilers group in Second Life that can be joined to ask questions related to compiling the viewer: [Firestorm Self Compilers](https://tinyurl.com/firestorm-self-compilers)
This procedure is based on discussions with the Firestorm Linux development team and is the only one recommended for Firestorm for Linux. System requirements are:
- Ubuntu 22.04 LTS (x86_64) - fully upgraded (this is also now the minimum requirement for running the viewer).
- 16GB or more RAM ([Low Memory Caution](#common-issuesbugsglitches-and-solutions))
- 64GB hard drive space
- 4 or more core CPU (you could get by with 2 cores, but the process will take much longer)
- GCC 11 compiler (which is the default version on Ubuntu 22.04 LTS)
It is recommended that you use a virtual machine for compiling, ensuring the guest can meet the hardware requirements.
This procedure may or may not work on other Linux distributions (or you might need to adjust some of the package names to suit the distribution you are using).
> [!WARNING]
> A system with a glibc version of at least 2.34 is required (Ubuntu 22.04 LTS meets this requirement)
> Building on a system with a glibc version older than 2.34 will likely result in linker errors.
> [!IMPORTANT]
> Only 64 bit builds are possible - 32 bit support was dropped quite some time ago.
## Establish your programming environment
This only needs to be done once.
### Create your source tree
Typically, Linux source code is stored in a src directory in your home directory. So: `mkdir ~/src`
### Install required packages
A few packages must be installed on the build system. Some may already be installed:
| | | | | | |
| --------------- | ---------------- | ------------- | ------------------ | ---------------- | ------ |
| libgl1-mesa-dev | libglu1-mesa-dev | libpulse-dev | build-essential | python3-pip | git |
| libssl-dev | libxinerama-dev | libxrandr-dev | libfontconfig-dev | libfreetype6-dev | gcc-11 |
| cmake | | | | | |
```
sudo apt install libgl1-mesa-dev libglu1-mesa-dev libpulse-dev build-essential python3-pip git libssl-dev libxinerama-dev libxrandr-dev libfontconfig-dev libfreetype6-dev gcc-11 cmake
```
### Install Autobuild
Autobuild is a Linden Lab resource that does all the hard work.
You can install it using the same versions as our automated builds as follows:
```
sudo pip3 install --upgrade pip
pip install -r requirements.txt
```
Check Autobuild version to be "autobuild 3.9.3" or higher: `autobuild --version`
## Download the source code
There are two required repositories, the viewer itself and the build variables. An optional third repository is used to configure and package FMOD Studio.
### Clone the viewer
```
cd ~/src
git clone https://github.com/FirestormViewer/phoenix-firestorm.git
```
This will create a folder called phoenix-firestorm and add all the source files. If you desire, you can choose a different folder name by adding the name to the end of the command:
```
git clone https://github.com/FirestormViewer/phoenix-firestorm.git NewDestinationDirectory
```
The rest of this document will assume the default directory, `phoenix-firestorm`
### Clone the Autobuild build variables
Autobuild uses a separate file to control compiler options, switches, and the like for different configurations.
```
cd ~/src
git clone https://github.com/FirestormViewer/fs-build-variables.git
```
### Create FMOD Studio package (optional)
Although not required, including FMOD Studio in your build will improve your audio-based experience.
```
cd ~/src
git clone https://github.com/FirestormViewer/3p-fmodstudio.git
cd ~/src/3p-fmodstudio
```
Open the file called `build-cmd.sh` and look at the fifth line down, it begins with `FMOD_VERSION`. This is the version of the API you need to download.
The FMOD Studio API can be downloaded [here](https://www.fmod.com) (requires creating a free account to access the download section).
Click the button representing the version you're after, then click the Download link for the Linux file.
> [!IMPORTANT]
> Make sure to download the FMOD Studio API and not the FMOD Studio Tool!
Copy that file to the `~/src/3p-fmodstudio` directory.
```
export AUTOBUILD_VARIABLES_FILE=$HOME/src/fs-build-variables/variables
autobuild build -A 64 --all
autobuild package -A 64 --results-file result.txt
```
Near the end of the output you will see the package name written, similar to:
```
wrote !/home/username/src/3p-fmodstudio/fmodstudio-2.01.02-linux64-202161533.tar.bz2
```
Additionally, a file `result.txt` has been created containing the md5 hash value of the package file, which you will need in the next steps.
```
cd ~/src/phoenix-firestorm
```
Copy the FMOD Studio path and md5 value from the package process into this command:
```
autobuild installables edit fmodstudio platform=linux64 hash=<md5 value> url=file:///<fmodstudio path>
```
For example:
```
autobuild installables edit fmodstudio platform=linux64 hash=c3f696412ef74f1559c6d023efe3a087 url=file:///!/src/3p-fmodstudio/fmodstudio-2.00.07-linux64-200912220.tar.bz2
```
> [!NOTE]
> Having modified autobuild.xml would require it be restored before trying to fetch any new commits or more especially if you push a commit. This can be done with `git reset --hard && git remote update`
## Configure and build
### Configuring the viewer
Start by initializing the variables
```
export AUTOBUILD_VARIABLES_FILE=$HOME/src/fs-build-variables/variables
```
You can add that to `~/.bashrc` or `~/.profile` so they execute automatically, or execute them before you run autobuild.
```
cd ~/src/phoenix-firestorm
autobuild configure -A 64 -c ReleaseFS_open
```
This will set up to compile with all defaults and without non-default libraries. It will fetch any additional necessary libraries.
Available premade firestorm-specific build targets:
```
ReleaseFS (includes KDU, FMOD)
ReleaseFS_open (no KDU, no FMOD)
RelWithDebInfoFS_open (no KDU, no FMOD)
```
### Configuration Switches
There are a number of switches you can use to modify the configuration process. The name of each switch is followed by its type and then by the value you want to set.
- **LL_TESTS** (bool) controls if the tests are compiled and run. There are quite a lot of them so excluding them is recommended unless you have some reason to need one or more of them.
- **clean** will cause autobuild to remove any previously compiled objects and fetched packages. It can be useful if you need to force a reload of all packages
- **package** will result in a bzip2 archive of the completed viewer. Enabled by default, you would have to use **-DPACKAGE:BOOL=Off** to disable it
- **chan** will set a unique channel (and the name) for the viewer, appending whatever is defined to "Firestorm-". By default, the channel is "private" followed by your computer's name.
- **fmodstudio** will tell autobuiild to use the FmodStudio package when compiling.
Most switches start with a double-dash (\--). And if you use any switches you must enclose them with a double-dash at the start and an optional double-dash at the end.
> [!TIP]
> **OFF** and **NO** are the same as **FALSE**; anything else is considered to be **TRUE**
Examples:
```
autobuild configure -A 64 -c ReleaseFS_open -- -DLL_TESTS:BOOL=FALSE
autobuild configure -A 64 -c ReleaseFS_open -- --clean
autobuild configure -A 64 -c ReleaseFS_open -- --fmodstudio
autobuild configure -A 64 -c ReleaseFS_open -- --chan="MyBuild"
```
In the last example, the channel and resulting viewer name would be "Firestorm-MyBuild".
The first time you configure, several additional files will be downloaded from Firestorm and Second Life sources. These are mostly binary packages maintained outside the viewer development itself. And if you use the `--clean` switch, you will re-download them all.
## Compiling the viewer
```
autobuild build -A 64 -c ReleaseFS_open
```
Be sure to use the fmodstudio and chan switches again.
Compiling can take quite a bit of time depending on your computer's processing power.
> [!NOTE]
> It is possible to use autobuild to do both the configure step (only needed once) and the build step with one command (`autobuild build -A 64 -c ReleaseFS_open -- --clean [more switches]`). For clarity, they are mentioned separately.
> [!TIP]
> When using the --package switch you can set the XZ_DEFAULTS variable to -T0 to use all available CPU cores to create the .tar.xz file. This can significantly reduce the time needed to create the archive, but it will use a lot more memory. For example:
> ```
> export XZ_DEFAULTS="-T0"
> autobuild build -A64 -c ReleaseFS_open -- --package
> ```
### Copy out of the guest
If you build the viewer using a virtual machine (guest), you will need to copy the viewer files over to your host or to a different machine in order to use the viewer. Your guest may not have sufficient resources to run the viewer. The rsync program can make copying easy and accurate. And if you build the viewer again, the options included in the command example will cause rsync to only copy the new files, cutting down on the time needed to copy.
The build process created a ready-to-use viewer as well as a compressed archive. The archive can be copied or moved to any shared filesystem, such as a flash or cloud drive, and it could be installed or extracted in the same manner as is the official release.
```
cp ~/src/phoenix-firestorm/build-linux-x86_64/newview/Phoenix*.tar.* /path/to/shared/drive
```
or
```
mv ~/src/phoenix-firestorm/build-linux-x86_64/newview/Phoenix*.tar.* /path/to/shared/drive
```
When copying the ready-to-run folders and files, use
```
rsync -rptgoDLK --update --progress ~/src/phoenix-firestorm/build-linux-x86_64/newview/packaged/* /path/to/destination
```
Using rsync has the advantage of updating the destination, replacing only those files that changed or are missing, which takes much less time than copying and replacing every file.
## Running your newly built viewer
### Running from a menu item
Create the desktop launcher after copying to the destination machine
```
cd /path/to/firestorm
etc/refresh_desktop_app_entry.sh
```
Then open your applications menu and look in the Internet or Network branch for the Firestorm launcher.
### Running from command line or file browser
```
cd /path/to/firestorm
./firestorm
```
## Troubleshooting
### Handling problems
If you encounter errors or run into problems, please first double check that you followed the steps correctly. One typo can break it. Then, check whether someone else already had the same issue. A solution might be known already.
- **Firestorm Self-Compilers group:** [Firestorm Self Compilers](https://tinyurl.com/firestorm-self-compilers) is free to join, fellow self-compilers may be able to offer assistance.
- **Jira:** [JIRA](https://jira.firestormviewer.org) may contain resolved issues related to the error you're seeing. Search using the error you encountered. Or create a new issue to report an error in this document, or if a code change causes a build process to fail.
### Common issues/bugs/glitches and solutions
- **Virtual memory exhausted, c++ fatal error, or similar out-of-memory issues** may occur if you are building the viewer for the first time, or re-building after a very large set of changes were added. Sometimes restarting the build command will let you recover, sometimes you have to restart the build system. To avoid that from happening, add ram to your virtual environment, or add swap space, something on the order of 10GB or more. As well, reducing the number of CPU cores assigned, down to 4 or less, will lower ram usage.
- **Missing libraries/applications/packages:** This may occur if you did not or could not install the packages shown above, or are attempting to use this procedure with a different Linux OS, or are attempting to build a 32-bit viewer. Start over, making sure you are using the right OS, reinstall all packages as listed, and do not attempt to make a 32-bit viewer.
- **SDL2:** Currently the SDL2 install/update process has a problem if the SDL2 files already exist. The workaround is to delete those files:
```
rm -rf ../build-linux-x86_64/packages/include/SDL2/
rm -rf ../build-linux-x86_64/packages/docs/SDL/
rm ../build-linux-x86_64/packages/LICENSES/SDL.txt
rm ../build-linux-x86_64/packages/lib/release/*SDL*
```
- **Delayed sounds:** Some users have noted that OpenAL plays sounds from the viewer up to 20 seconds after they are triggered. There is no solution to this via the viewer, but there may be some solutions on the Internet. Compiling with FModStudio may resolve this issue.
- **No sounds:** The viewer will try to use whatever sound service you have running, but might need a little coaxing. Read through the firestorm script inside the program directlry, you will find various commented options. Uncommenting one or more may help restore sound, as can compiling with FModStudio. Refer also to the README.Linux.txt and README-linux-voice.txt files in the program directory.
- **Voice won't connect:** Refer to **[this link](https://wiki.firestormviewer.org/fs_voice#linux)** or the relevant link on **[this page](https://wiki.firestormviewer.org/linux)** to make needed adjustments to your computer and/or the SLVoice files.
+249
View File
@@ -0,0 +1,249 @@
# Build instructions for macOS
The viewer and its libraries are built with the current version of Xcode and Cmake, as well as the standard version of Autobuild from Linden Lab.
> [!WARNING]
> Please note that we do not give support for compiling the viewer on your own. However, there is a self-compilers group in Second Life that can be joined to ask questions related to compiling the viewer: [Firestorm Self Compilers](https://tinyurl.com/firestorm-self-compilers)
## Obtaining a shell to work with
The steps listed below are expected to be run from a shell prompt. Simply copy and paste the commands, or type them out if you wish, into a shell prompt when told to. If you do not know how to acquire a shell prompt, open up the Applications folder, go to Utilities, then open Terminal. This will open a shell prompt. If you are a power user and know what a shell prompt is, open one now using your preferred method and program, then continue on to the next section. Leave this window open throughout the guide. You don't need to close it and re-open it after every command.
## Getting development tools
You will need to install the following tools:
### Xcode
- Xcode, It's a free download from Apple, but the latest version (12.x) is too new, so you will need to get an older version.
- To download a version that will work (11.7 in this case), go [here](https://developer.apple.com/download) and log in with an apple ID.
- Either find the 11.7 download in the list or use this [direct link](https://download.developer.apple.com/Developer_Tools/Xcode_11.7/Xcode_11.7.xip) (will prompt you to log in if you skipped the above step.)
- Open the downloaded file and copy the Xcode application to the Applications folder.
- Open Xcode at least once to set up everything to compile the viewer later on.
- Test by running `clang --version` from the terminal window.
- It should report version 11 something (Apple clang version 11.0.3 (clang-1103.0.32.62) for example.)
- If it reports version 12, something is messed up and you installed Xcode 12.
### CMake
- Download [CMake](http://www.cmake.org/download) version 3.16.0 or higher
- Open the downloaded file and copy CMake to the Applications folder.
- You will need to install the command line links manually. To do this, run from the terminal: `sudo /Applications/CMake.app/Contents/MacOS/CMake --install`
- Again, test by running: `cmake --version` from the terminal window.
### Pip
The pip Python package installation tool is required for the next step. To install it, run from terminal:
```
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
sudo python3 get-pip.py
```
### Autobuild
The Linden Lab [Autobuild](https://github.com/secondlife/autobuild) tool.
- Use the following command to install it on your machine:
```
pip3 install --user -r requirements.txt
```
- Add it to your PATH environment variable so it can be found by the shell. The macOS-approved way to do this is to issue the following command (This change will not take effect until the next time you open a Terminal window.):
```
echo '~/Library/Python/3.7/bin/' | sudo tee /etc/paths.d/99-autobuild
```
- If you do not want to close and re-open your terminal, type the following to add it your PATH (otherwise if you did close it down, re-open it as shown above [here](#obtaining-a-shell-to-work-with)):
```
export PATH=$PATH:~/Library/Python/3.7/bin/
```
- Check Autobuild version to be "autobuild 3.9.3" or higher: `autobuild --version`
### Additional third party libraries
If you want to use licensed FMOD Studio API or KDU build libraries (they are optional) you have to provide these yourself. If you're building Firestorm as part of the project team, ask for the libraries for fmodstudio and kdu. Put them into `/opt/firestorm`.
If you're a community builder, you'll need to build these libraries yourself, then change your autobuild.xml file to point to your own versions, or create a different autobuild.xml with your customizations, and use this with autobuild instead of our default autobuild.xml. There are some examples of how to build FMOD Studio on the LL Wiki and opensource-dev mailing list.
We've created a non-KDU build target to make this easier. Everywhere you see "ReleaseFS" below, use "ReleaseFS_open" instead. This will perform the same build, using openjpeg instead of KDU and omitting FMOD Studio.
Available premade firestorm-specific build targets:
```
ReleaseFS (includes KDU, FMOD)
ReleaseFS_open (no KDU, no FMOD)
RelWithDebInfo_open (no KDU, no FMOD)
```
To build firestorm:
```
autobuild build -c ReleaseFS
```
Other examples:
```
autobuild configure -c ReleaseFS # basic configuration step, don't build, just configure
autobuild configure -c ReleaseFS -- --clean # clean the output area first, then configure
autobuild configure -c ReleaseFS -- --chan Private-Yourname # configure with a custom channel
autobuild build -c ReleaseFS --no-configure # default quick rebuild
autobuild build -c ReleaseFS --no-configure -- --clean # Clean rebuild
autobuild configure -c ReleaseFS_open -- # configure with no third-party libraries
autobuild configure -c ReleaseFS_open -- --fmodstudio # configure with FMOD Studio but no KDU
```
Any of the configure options can also be used (and do the same thing) with the build options. Typical LL autobuild configure options should also work, as long as they don't duplicate configuration we are already doing.
Logs: Look for logs in `build-darwin-x86_64/logs`.
Output: Look for output in `build-darwin-x86_64/newview/Release`.
## Set up your source code tree
Plan your directory structure ahead of time. If you are going to be producing changes or patches you will be cloning a copy of an unaltered source code tree for every change or patch you make, so you might want to have all this work stored in its own directory. If you are a casual compiler and won't be producing any changes, you can use one directory. For this document, we will assume $HOME/firestorm.
```
mkdir ~/firestorm
cd ~/firestorm
git clone https://github.com/FirestormViewer/phoenix-firestorm.git
```
This can take a while. It's a rather large download.
You will also need to download the build variables used for building the viewer. Like the viewer source, these are downloaded from the Firestorm git repository. Assuming you are still in your ~/firestorm directory (or wherever else you chose), issue the following commands:
```
git clone https://github.com/FirestormViewer/fs-build-variables.git
```
You will then need to add this line to your ~/.zshrc file (assuming you are on Catalina or later):
```
echo 'AUTOBUILD_VARIABLES_FILE=~/firestorm/fs-build-variables/variables' | sudo tee ~/.zshrc
```
Again, if you do not wish to restart your terminal:
```
export AUTOBUILD_VARIABLES_FILE=~/firestorm/fs-build-variables/variables
```
## Prepare third party libraries
Most third party libraries needed to build the viewer will be automatically downloaded for you and installed into the build directory within your source tree during compilation. Some need to be manually prepared and are not normally required when using an open source configuration (ReleaseFS_open).
### FMOD Studio using autobuild
- Get the FMOD Studio API disk image installer for the Mac from the [FMOD site](https://www.fmod.com) (requires creating an account to access the download section).
> [!IMPORTANT]
> Make sure to download the FMOD Studio API and not the FMOD Studio Tool!
- Enter these commands into the terminal window:
```
git clone https://github.com/FirestormViewer/3p-fmodstudio.git
cd 3p-fmodstudio
```
- Place the installer disk image (.dmg) file you downloaded into the current directory.
- Issue the following commands:
```
autobuild build
autobuild package --results-file result.txt
```
Near the top of the output you will see the package name written:
```
wrote /Users/yourname/3p-fmodstudio/fmodstudio-2.01.05-darwin-202981448.tar.bz2
```
Additionally, a file `result.txt` has been created containing the md5 hash value of the package file, which you will need in the next step.
- Next, update Firestorms autobuild.xml file to use your FMOD Studio.
```
cd ~/firestorm/phoenix-firestorm
cp autobuild.xml my_autobuild.xml
export AUTOBUILD_CONFIG_FILE=my_autobuild.xml
```
- Copy the fmodstudio path and md5 value from the package process into this command:
```
autobuild installables edit fmodstudio platform=darwin64 hash=<md5 value> url=file:///<fmod path>
```
For example:
```
autobuild installables edit fmodstudio platform=darwin64 hash=3b0d38f2a17ff1b73c8ab6dffbd661eb url=file:///Users/yourname/3p-fmodstudio/https://fmodstudio-2.01.05-darwin-202981448.tar.bz2
```
> [!NOTE]
> Having to copy autobuild.xml and modify the copy from within a cloned repository is a lot of work for every repository you make, but this is the only way to guarantee you pick up upstream changes to autobuild.xml and do not send up a modified autobuild.xml when you do a git push.
## Configuring the Viewer
The following is all still done from within the terminal window:
```
cd ~/firestorm/phoenix-firestorm
autobuild configure -A 64 -c ReleaseFS_open
```
This will configure the viewer for compiling with all defaults and without third party libraries.
### Configuration Switches
There are a number of switches you can use to modify the configuration process. The name of each switch is followed by its type and then by the value you want to set.
- FMODSTUDIO (bool) controls if the FMOD Studio package is incorporated into the viewer. You must have performed the FMOD Studio installation steps in [FMOD Studio using autobuild](#fmod-studio-using-autobuild) for this to work. This is the switch the --fmodstudio build argument sets.
- LL_TESTS (bool) controls if the tests are compiled and run. There are quite a lot of them so excluding them is recommended unless you have some reason to need one or more of them.
> [!TIP]
> OFF and NO are the same as FALSE; anything else is considered to be TRUE
Example:
```
autobuild configure -A 64 -c ReleaseFS_open -- -DLL_TESTS:BOOL=FALSE -DFMODSTUDIO:BOOL=TRUE
```
```
autobuild configure -A 64 -c ReleaseFS_open
```
> [!IMPORTANT]
> You must specify the -A 64 switch to autobuild whenever you configure or build. This tells autobuild to build a 64-bit viewer; this is the only architecture supported on macOS.
## Compiling the Viewer
To compile the code into an app that can be used on your computer, run the following in the terminal window:
```
cd ~/firestorm/phoenix-firestorm
autobuild build -A 64 -c ReleaseFS_open --no-configure
```
Compiling may take quite a bit of time, depending on how fast your machine is and how much else you're doing.
> [!NOTE]
> It is possible to use autobuild to do both the configure step (only needed once) and the build step with one command (`autobuild build -A 64 -c ReleaseFS[_open] [-- config options]`). Some find it is clearer if these steps are done separately, but can save a bit of time if done together.
## Launching the viewer
Now that the viewer has been compiled, it can be found in `build-darwin-x86_64/newview/Release`. Enter the following into the terminal to open Finder:
```
open build-darwin-x86_64/newview/Release
```
From here you can run it directly or copy it to the Applications folder for ease of finding and running later.
## Updating the viewer
If you want to update your self-compiled viewer, you don't have to go through this entire page again. Follow these steps to pull down any new code and re-compile.
- First you need to change to the directory where you built the viewer before. Assuming you followed the steps above and used the same names, run the following in the terminal window: `cd ~/firestorm/phoenix-firestorm`
- Next, decide if you are going to remove the already compiled files and perform a "Clean build", or if you want to keep the existing build files, "Dirty build". Clean builds are generally recommended by developers but have the downside of building everything again, which comes at a cost of time; dirty builds on the other hand, keep all the previously compiled files and only compile the parts that have changed. The downside to dirty builds comes when a change to a core file is pulled down, which will then cause everything to be rebuilt, negating any speed benefit or possibly taking longer than a clean build.
- If you have picked to do a clean build, run the following in the terminal window, otherwise skip to the next step: `rm -r build-darwin-x86_64`
- If you are using a custom autobuild.xml file, then run the following in the terminal window, otherwise skip this step: `export AUTOBUILD_CONFIG_FILE=my_autobuild.xml`
- Now, to pull down any new code, run the following in the terminal window: `git pull`
- After any new code is downloaded, it needs to be reconfigured. Run the following in the terminal window: `autobuild configure -A 64 -c ReleaseFS_open`
- Finally, re-compile the viewer with the new changes. Again, in the terminal window, run: `autobuild build -A 64 -c ReleaseFS_open --no-configure`
Finally, follow the instructions in [Launching the viewer](#launching-the-viewer) to run your freshly updated viewer.
+292
View File
@@ -0,0 +1,292 @@
# Build instructions for Windows
This page describes all necessary steps to build the Firestorm viewer for Windows. For building instructions up to (and including) release 6.5.3, see the archived version for [building with Python 2.7](https://wiki.firestormviewer.org/archive:fs_compiling_firestorm_windows_py_27).
> [!WARNING]
> Please note that we do not give support for compiling the viewer on your own. However, there is a self-compilers group in Second Life that can be joined to ask questions related to compiling the viewer: [Firestorm Self Compilers](https://tinyurl.com/firestorm-self-compilers)
> [!IMPORTANT]
> With the [merge of Linden Lab release 6.6.16](https://github.com/FirestormViewer/phoenix-firestorm/commit/b64793e2b0d14e44274335c874660af9f679f7f8) it is **NOT** possible to create 32bit builds anymore! Only 64bit builds are possible going forward!
## Install required development tools
This is needed for compiling any viewer based on the Linden Lab open source code and only needs to be done once.
All installations are done with default settings (unless told explicitly) - if you change that, you're on your own!
### Windows
- Install Windows 10/11 64bit using your own product key
### Microsoft Visual Studio 2022
- Install Visual Studio 2022
- Run the installer as Administrator (right click, "Run as administrator")
- Check "Desktop development with C++" on the "Workloads" tab.
- All other workload options can be unchecked
> [!TIP]
> If you don't own a copy of a commercial edition of Visual Studio 2022 (e.g. Professional), you might consider installing the [Community version](https://visualstudio.microsoft.com/free-developer-offers)
### Tortoise Git
- Download and install [TortoiseGit 2.9.0 or newer](https://tortoisegit.org) (64bit)
- Note: No option available to install as Administrator
- Use default options (path, components etc.) for Tortoise Git itself
- At some point, it will ask you to download and install Git for Windows
- You can install with default options **EXCEPT** when it asks for "Configuring the line endings conversion": You **MUST** select "Checkout as-is, commit as-is" here!
### CMake
- Download and install at least [CMake 3.16.0](http://www.cmake.org/download)
- Note: No option available to install as Administrator
- At the "Install options" screen, select "Add CMake to the system PATH for all users"
- For everything else, use the default options (path, etc.)
- Make sure that the following directory was added to your path:
For the 32bit version:
`C:\Program Files (x86)\CMake\bin`
For the 64bit version:
`C:\Program Files\CMake\bin`
### Cygwin
- Download and install [Cygwin 64](http://cygwin.com/install.html) (64bit)
- Run the installer as Administrator (right click, "Run as administrator")
- Use default options (path, components etc.) *until* you get to the "Select Packages" screen
- Add additional packages:
- Devel/patch
- Use default options for everything else
- Make sure that the following directory was added to your path and that it is placed before "%SystemRoot%\system32":
`C:\Cygwin64\bin`
### Python
- Download and install the most recent version of [Python 3](https://www.python.org/downloads/windows)
- Run the installer as Administrator (right click, “Run as administrator”)
- Tick "Add Python 3.10 to PATH"
- Choose the "Customize Installation" option.
- Make sure that "pip" is ticked.
- "Documentation", "tcl/tk and IDLE", "Python test suite" and "py launcher" are not needed to compile the viewer but can be selected if you wish.
- On the next screen, the correct options should already be ticked.
- Set custom install location to: `C:\Python3`
- Make sure that the following directory was added to your path: `C:\Python3`
> [!TIP]
> On Windows 10/11, you also might want to disable the app alias for Python. Open the Windows settings app, search for "Manage app execution aliases" and disable the alias for "python3.exe"
### Intermediate check
Confirm things are installed properly so far by opening a Cygwin terminal and enter:
```
cmake --version
git --version
python --version
pip --version
```
If they all report sensible values and not "Command not found" errors, then you are in good shape.
> [!NOTE]
> The Cygwin terminal is only needed for testing. All commands for actually building the viewer will be run from the Windows command shell.
### Set up Autobuild
- Install Autobuild
You can install autobuild and its dependencies using the `requirements.txt` file that is part of the repo, this will build using the same versions that our official builds use.
- Open Windows Command Prompt and enter: <code>pip install -r requirements.txt</code>
- Autobuild will be installed. **Earlier versions of Autobuild could be made to work by just putting the source files into your path correctly; this is no longer true - Autobuild _must_ be installed as described here.**
- Open Windows Command Prompt and enter:
`pip install git+https://github.com/secondlife/autobuild.git#egg=autobuild`
- Set environment variable AUTOBUILD_VSVER to 170 (170 = Visual Studio 2022).
- Check Autobuild version to be "autobuild 3.8" or higher:
`autobuild --version`
### NSIS
- If you plan to package the viewer and create an installer file, you must install the NSIS from the [official website](https://nsis.sourceforge.io).
- Not required unless you need to build an actual viewer installer for distribution, or change the NSIS installer package logic itself
> [!IMPORTANT]
> If you want to package the viewer built on a revision prior to the [Bugsplat merge](https://github.com/FirestormViewer/phoenix-firestorm/commit/a399c6778579ac7c8965737088c275dde1371c9e), you must install the Unicode version of NSIS [from here](http://www.scratchpaper.com) - the installer from the NSIS website **WILL NOT** work!
## Setup viewer build variables
In order to make it easier to build collections of related packages (such as the viewer and all the library packages that it imports) with the same compilation options, Autobuild expects a file of variable definitions. This can be set using the environmenat variable AUTOBUILD_VARIABLES_FILE.
- Clone the build variables repository:
`git clone https://github.com/FirestormViewer/fs-build-variables.git <path-to-your-variables-file>`
- Set the environment variable AUTOBUILD_VARIABLES_FILE to
`<path-to-your-variables-file>\variables`
## Configure Visual Studio 2022 (optional)
- Start the IDE
- Navigate to **Tools** > **Options** > **Projects and Solutions** > **Build and Run** and set **maximum number of parallel projects builds** to **1**.
## Set up your source code tree
Plan your directory structure ahead of time. If you are going to be producing changes or patches you will be cloning a copy of an unaltered source code tree for every change or patch you make, so you might want to have all this work stored in its own directory. If you are a casual compiler and won't be producing any changes, you can use one directory. For this document, it is assumed that you created a folder c:\firestorm.
```
c:
cd \firestorm
git clone https://github.com/FirestormViewer/phoenix-firestorm.git
```
## Prepare third party libraries
Most third party libraries needed to build the viewer will be automatically downloaded for you and installed into the build directory within your source tree during compilation. Some need to be manually prepared and are not normally required when using an open source configuration (ReleaseFS_open).
> [!IMPORTANT]
> If you are manually building the third party libraries, you will have to build the correct version (32bit libraries for a 32bit viewer, 64bit versions for a 64bit viewer)!
## FMOD Studio using Autobuild
If you want to use FMOD Studio to play sounds within the viewer, you will have to download your own copy. FMOD Studio can be downloaded [here](https://www.fmod.com) (requires creating an account to access the download section).
> [!IMPORTANT]
> Make sure to download the FMOD Studio API and not the FMOD Studio Tool!
```
c:
cd \firestorm
git clone https://github.com/FirestormViewer/3p-fmodstudio.git
```
- After you have cloned the repository, copy the downloaded FMOD Studio installer file into the root of the repository
- Make sure to modify the file build-cmd.sh in the root of the repository and set the correct version number based on the version you downloaded. Right at the top, you find the version number of FMOD Studio you want to package (one short version without separator and one long version):
```
FMOD_VERSION="20102"
FMOD_VERSION_PRETTY="2.01.02"
```
Continue on the Windows command line:
```
c:
cd \firestorm\3p-fmodstudio
autobuild build -A 64 --all
autobuild package -A 64 --results-file result.txt
```
While running the Autobuild build command, Windows might ask if you want to allow making changes to the computer. This is because of the FMOD Studio installer being executed. Allow these changes to be made.
Near the end of the output you will see the package name written:
```
wrote C:\firestorm\3p-fmodstudio\fmodstudio-{version#}-windows64-{build_id}.tar.bz2''
```
where {version#} is the version of FMOD Studio (like 2.01.02) and {build_id} is an internal build id of the package. Additionally, a file `result.txt` has been created containing the md5 hash value of the package file, which you will need in the next step.
```
cd \firestorm\phoenix-firestorm
cp autobuild.xml my_autobuild.xml
set AUTOBUILD_CONFIG_FILE=my_autobuild.xml
```
Copy the FMOD Studio path and md5 value from the package process into this command:
`autobuild installables edit fmodstudio platform=windows64 hash=<md5 value> url=file:///<fmodstudio path>`
For example:
`autobuild installables edit fmodstudio platform=windows64 hash=a0d1821154e7ce5c418e3cdc2f26f3fc url=file:///C:/firestorm/3p-fmodstudio/fmodstudio-2.01.02-windows-192171947.tar.bz2`
> [!NOTE]
> Having to copy autobuild.xml and modify the copy from within a cloned repository is a lot of work for every repository you make, but this is the only way to guarantee you pick up upstream changes to autobuild.xml and do not send up a modified autobuild.xml when you do a git push.
## Configuring the viewer
Open the Windows command prompt.
If you are building with FMOD Studio and have followed the previous FMOD Studio setup instructions AND you are now using a new terminal you will need to reset the environment variable first by entering
`set AUTOBUILD_CONFIG_FILE=my_autobuild.xml`
Then enter:
```
c:
cd \firestorm\phoenix-firestorm
autobuild configure -A 64 -c ReleaseFS_open
```
This will configure Firestorm to be built with all defaults and without third party libraries.
Available premade firestorm-specific build targets:
```
ReleaseFS (includes KDU, FMOD)
ReleaseFS_open (no KDU, no FMOD)
RelWithDebInfoFS_open (no KDU, no FMOD)
```
> [!TIP]
> Configuring the viewer for the first time will take some time to download all the required third-party libraries. The download progress is hidden by default. If you want to watch the download progress, you can use the verbose option to display a more detailed output:
> `autobuild configure -A 64 -v -c ReleaseFS_open`
### Configuration switches
There are a number of switches you can use to modify the configuration process. The name of each switch is followed by its type and then by the value you want to set.
- -A \<architecture\> sets the target architecture, that is if you want to build a 32bit or 64bit viewer (32bit is default if omitted).
- --fmodstudio controls if the FMOD Studio package is incorporated into the viewer. You must have performed the FMOD Studio installation steps in [FMOD Studio using Autobuild](#fmod-studio-using-autobuild) for this to work.
- --package makes sure all files are copied into viewers output directory. You won't be able to start your compiled viewer if you don't enable package or do 'compile' it in VS.
- --chan \<channel name\> lets you define a custom channel name for the viewer
- -LL_TESTS:BOOL=\<bool\> controls if the tests are compiled and run. There are quite a lot of them so excluding them is recommended unless you have some reason to need one or more of them.
> [!TIP]
> **OFF** and **NO** are the same as **FALSE**; anything else is considered to be **TRUE**
Examples:
- To build a 64bit viewer with FMOD Studio and to create an installer package, run this command in the Windows command window:
`autobuild configure -A 64 -c ReleaseFS_open -- --fmodstudio --package --chan MyViewer -DLL_TESTS:BOOL=FALSE`
- To build a 64bit viewer without FMOD Studio and without installer package, run this command:
`autobuild configure -A 64 -c ReleaseFS_open -- --chan MyViewer -DLL_TESTS:BOOL=FALSE`
## Building the viewer
There are two ways to build the viewer: Via Windows command line or from within Visual Studio.
### Building from the Windows command line
If you are building with FMOD Studio and have followed the previous FMOD Studio setup instructions AND you are now using a new terminal you will need to reset the environment variable with
`set AUTOBUILD_CONFIG_FILE=my_autobuild.xml`
Then run the Autobuild build command. Make sure you include the same architecture parameter you used while [configuring the viewer](#configuring-the-viewer):
`autobuild build -A 64 -c ReleaseFS_open --no-configure`
Compiling will take quite a bit of time.
### Building from within Visual Studio
Inside the Firestorm source folder, you will find a folder named build-vc170-\<architecture\>, with \<architecture\> either being 32 or 64, depending on what you chose during the configuration step. Inside the folder is the Visual Studio solution file for Firestorm, called Firestorm.sln.
- Double-click Firestorm.sln to open the Firestorm solution in Visual Studio.
- From the menu, choose Build -> Build Solution
- Wait until the build is finished
## Troubleshooting
### SystemRootsystem32: unbound variable
When trying to execute the Autobuild build command, you might encounter an error similar to
`../build.cmd.sh line 200: SystemRootsystem32: unbound variable`
This error is caused by the order of the items in the Windows "path" environment variable. Autobuild exports all paths set in the "path" environment variable into Cygpath names and variables. Since these Windows "paths" can also contain variables like %SystemRoot% and they can also depend on each other, it is important to keep the dependency order intact. Example:
```
%SystemRoot%
%SystemRoot%\system32
%SystemRoot%\System32\Wbem
```
Make sure the ones mentioned are the first items set in the "path" environment variable.
+1738
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

@@ -0,0 +1,16 @@
The Setting RenderMaxTextureResolution controls the maximum resolution of non-boosted textures as displayed by the viewer.
Valid values are 512-2048 (clamped in C++).
![image](https://github.com/secondlife/viewer/assets/23218274/d0f889fc-8135-41d2-9d83-871ad4eebed5)
![image](https://github.com/secondlife/viewer/assets/23218274/19950828-7eb1-4bb2-85d7-f35c63b34294)
![image](https://github.com/secondlife/viewer/assets/23218274/249afc83-4de6-488d-a05e-4877d08573b1)
Test Asset available on beta grid:
Object: 'Damaged Helmet', AssetID 0623e759-11b5-746c-a75e-7ba1caa6eb0e
+21
View File
@@ -0,0 +1,21 @@
A resident may swap out their sky for an EXR format HDRI for the purposes of previewing how their object would render in Second Life in an environment that matches the supplied HDRI. This should aid in matching inworld lighting with external tools so artists can know if their content has imported properly.
To load an HDRI, click Develop->Render Tests->HDRI Preview:
![image](https://github.com/secondlife/viewer/assets/23218274/fbdeab5f-dc1f-4406-be19-0c9ee7437b3f)
Choose an EXR image. A library of publicly available HDRIs can be found here: https://polyhaven.com/hdris
The Personal Lighting floater will open, and the sky will be replaced with the HDRI you chose. Reflection Probes will reset, and the scene will be illuminated by the HDRI.
Three debug settings affect how the HDRI is displayed:
RenderHDRIExposure - Exposure adjustment of HDRI when previewing an HDRI. Units are EV. Sane values would be -10 to 10.
RenderHDRIRotation - Rotation (in degrees) of environment when previewing an HDRI.
RenderHDRISplitScreen - What percentage of screen to render using HDRI vs EEP sky.
Exposure and Rotation should behave similarly to the rotation and exposure controls in Substance Painter.
Split Screen can be used to display an EEP sky side-by-side with an HDRI sky to aid in authoring an EEP sky that matches an HDRI sky. It is currently expected that EEP sun disc, moon, clouds, and stars do not render when previewing an HDRI, but that may change in the future.
+83
View File
@@ -0,0 +1,83 @@
# Material Preview
## Overview
Material preview is a UI feature which displays a lit spherical preview of a PBR material. It can be found in the following UIs:
- The material picker swatch
- In the build floater, in the Texture tab, when applying a PBR material
- (If the feature is enabled) In the Region/Estate floater, in the Terrain tab, when applying PBR materials to terrain
- In the floater to select a material from inventory, which can be opened by clicking the material picker swatch
## Known Issues
These are known issues that the current implementation of this feature does not address:
- The material preview in the build floater is a preview of the base material ID only, and ignores other properties on the prim face like material overrides (https://github.com/secondlife/viewer/issues/865)
- Alpha mask previews as alpha blend (https://github.com/secondlife/viewer/issues/866)
- Double-sided previews as single-sided (https://github.com/secondlife/viewer/issues/867)
- Material preview inherits some of its lighting from the current environment, and reflections from the default reflection probe (https://github.com/secondlife/viewer/issues/868)
## General Regression Testing
- Check that the material preview swatch looks OK with different materials selected
- Check that the material preview swatch runs reasonably well on different systems, especially when the select material from inventory floater is also open
- In particular: AMD, MacOS, minimum spec machines
- Watch out for regressions in rendering caused by opening a floater with a material preview swatch
## Bug Fixes
### Disappearing Objects Fix Test
This test is recommended for verifying that https://github.com/secondlife/viewer-issues/issues/72 is fixed.
#### Symptoms
When the bug occurs, one or more of following types of objects could randomly disappear in the world, permanently until relog:
- Objects
- Water level in current region
- Adjacent region/void water
Note: Disappearing objects in reflections have a different root cause and are not covered by the fix.
#### Bug Reproduction Steps
Verify the disappearing objects bug does not reproduce, given the following steps:
- Runtime prerequisites: Material preview swatch may not be available in your viewer or region if this feature is still behind a feature flag. It is safe to enable this feature manually by setting, "UIPreviewMaterial" to True in the advanced settings. The setting will persist for the current session.
- Region prerequisites: Unknown, but a region with lots of objects in it seems to increase repro rate. The following locations have been known to easily reproduce the bug, as of 2024-02-16:
- http://maps.secondlife.com/secondlife/LindenWorld%20B/161/75/47
- [secondlife://Aditi/secondlife/Rumpus%20Room%202048/128/128/24](secondlife://Aditi/secondlife/Rumpus%20Room%202048/128/128/24)
- Right click an object and select, "Edit item"
- Go to texture tab, select PBR Metallic Roughness from dropdown, and click the button to select material from inventory
- Ensure "Apply now" is checked in the inventory selection floater
- Alternate between different materials from the inventory selection floater
- Look around the world and check for permanently disappeared objects.
### Dynamic Exposure Influence Fix Test
This test is recommended for verifying that https://github.com/secondlife/viewer-issues/issues/72 is fixed.
#### Symptoms
Dynamic exposure in the world could be influenced by the material preview being displayed. If a material preview was being generated in a given frame, then, depending on the current environment, the user would observe an unpleasant flashing effect in the environment:
- The world view could suddenly get darker and then fade back to normal exposure levels
- The world view could suddenly get brighter and then fade back to normal exposure levels
#### Bug Reproduction Steps
Verify the dynamic exposure influence bug does not reproduce. Test using a few environment presets such as Default Midday, Sunset, and Midnight.
- Right click an object and select, "Edit item"
- Go to texture tab, select PBR Metallic Roughness from dropdown, and click the button to select material from inventory
- Alternate between different materials from the inventory selection floater
#### Regression Testing
Dynamic exposure in the world should continue to work correctly. In particular:
- Exposure should fade gradually from high exposure to low exposure and back as needed
- Exposure should decrease in brighter environments
- Exposure should increase in darker environments
+5
View File
@@ -0,0 +1,5 @@
Textures imported via Build->Upload->Material that have an all opaque (255) alpha channel should have their alpha channel removed before upload.
1. Make 4 images that have different colors but all 255 alpha channels
2. Upload them all using Build->Upload->Material, with one in each of the material texture slots
3. Verify that using the textures as a blinn-phong diffuse map does not make the corresponding face render in the alpha pass (face should stay visible after disabling alpha pass by unchecking Advanced->Render Types->Alpha).
+12
View File
@@ -0,0 +1,12 @@
# PBR Materials
## KHR Texture Transforms
Texture repeats for PBR materials on prims are based on the [KHR\_texture\_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) spec, and thus should be expected to behave according to the spec. We currently suport offset, rotation, and scale from the spec. texCoord is not currently supported.
PBR materials should have approximately correct lighting based on the normal texture:
- With default texture transforms, assuming the prim or model has correct normals and tangents
- With a texture transform applied, especially rotation or negative scale
- With a texture animation applied via `llSetTextureAnim`, especially a rotation animation
- Note: Texture animations are not guaranteed to loop when a PBR texture transform is applied
+63
View File
@@ -0,0 +1,63 @@
# PBR Terrain Appearance
## Tiling Without Texture Transforms
This section assumes the PBR terrain of the current region and adjacent regions have the default texture transforms.
The southwest corner of a region with PBR materials should exactly match up with the bottom left corner of the material texture(s).
If two adjacent regions have the same PBR terrain settings, then there should not be seams between the two regions at their shared border.
The ground should not suddenly slide beneath the avatar when moving between two PBR terrain regions (except due to movement of the avatar, which is not covered by this test plan)
## Feature Gating
PBR terrain should have lower detail on lower graphics settings. PBR terrain will also not show emissive textures on some machines (like Macs) which do not support more than 16 textures.
### Triplanar Mapping
Triplanar mapping improves the texture repeats on the sides of terrain slopes.
Availability of Triplanar mapping:
- Medium-High and below: No triplanar mapping
- High and above: Triplanar mapping
### PBR Textures
At the highest graphics support level, PBR terrain supports all PBR textures.
Availability of PBR textures varies by machine and graphics setting:
- Low: Base color only (looks similar to texture terrain)
- Medium-Low, and machines that do not support greater than 16 textures such as Macs: All PBR textures enabled except emissive textures.
- Medium: All PBR textures enabled
### PBR Alpha
PBR terrain does not support materials with alpha blend or double-sided. In addition, the viewer does not make any guarantees about what will render behind the terrain if alpha is used.
## PBR Terrain Texture Transforms
Like PBR materials on prims, PBR terrain repeats are based on the [KHR\_texture\_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) spec, and thus should be expected to behave the same way. We currently suport offset, rotation, and scale from the spec. texCoord is not currently supported.
The southwest corner of a region, at z=0, is the UV origin for all texture coordinates of the whole region. Unless an offset is also applied, scale and rotation of the terrain texture transforms are relative to that point.
When an avatar faces north and looks down at flat ground, the textures of the materials should appear to face upright, unless a rotation is applied.
If triplanar mapping is enabled, and an avatar faces an axially-aligned wall, the textures of the materials should appear to face upright, unless a rotation is applied.
Textures of materials should not appear mirrored.
When triplanar mapping is enabled, rotations on the axially aligned walls should apply in the same direction as they would on flat ground.
## PBR Terrain Normal Textures
This section assumes terrain normal maps are enabled at the current graphics setting.
PBR terrain should have approximately correct lighting based on the normal texture:
- When on flat ground
- On cliffs, when triplanar mapping is enabled. Lighting will be somewhat less accurate when the cliff face is not axially aligned.
- If no Terrain Texture Transform is applied.
- If a Terrain Texture Transform is applied, especially for rotation or negative scale.
+106
View File
@@ -0,0 +1,106 @@
# PBR Terrain Composition
## Feature Availability
PBR Terrain is visible for all viewers with the PBR Terrain feature, regardless of if the feature flag is enabled.
There is only one set of four asset IDs applied to the terrain. In other words, unlike PBR materials on prims, there is no fallback texture set for viewers that do not support PBR terrain. Viewers without support will view terrain as blank (solid grey or white).
## Editing Terrain Composition
All tests in this section assume the PBR terrain feature flag is enabled, and that the user has appropriate permissions to modify the terrain textures.
### Feature Availability
These features are related to UI, where the Region/Estate floater is opened to the terrain Tab.
#### Feature: PBR Terrain
On the client, the advanced setting `RenderTerrainPBREnabled` is the PBR terrain feature flag.
The PBR terrain feature flag should be set automatically when logging in/teleporting to a new region.
- The flag should be enabled on regions where the PBR terrain feature is enabled
- Otherwise the flag should be disabled
When the PBR terrain feature flag is disabled:
- The "PBR Metallic Roughness" checkbox should not be visible
- The user should not be able to apply PBR terrain to the region, only textures.
When the PBR terrain feature flag is enabled:
- The "PBR Metallic Roughness" checkbox should be visible
- The user should be able to apply PBR terrain or textures to the region, depending on if the "PBR Metallic Roughness" checkbox is checked.
#### Feature: PBR Terrain Texture Transforms
On the client, the advanced setting, `RenderTerrainPBRTransformsEnabled` is the PBR terrain texture transform flag. Generally, this feature should not be expected to work correctly unless the PBR terrain feature is also enabled.
The PBR terrain texture transform flag should be set automatically when logging in/teleporting to a new region.
- The flag should be enabled on regions where the PBR terrain texture transform feature is enabled
- Otherwise the flag should be disabled
When the PBR terrain texture transform feature is enabled, the UI of the Terrain tab should be overhauled. Availability of features depends on the type of terrain.
**Known issue:** The Region/Estate floater may have to be closed/reopened a second time in order for the UI overhaul to take effect, after teleporting between regions that do and do not have the feature flag set.
When "PBR Metallic Roughness" is checked:
- There should be a way for the user to change the texture transforms for the terrain in the current region
- For each of the four swatches, the user can change the scale, offset, and rotation of that swatch. Nonuniform scale is allowed
When "PBR Metallic Roughness" is unchecked, the controls for texture transforms should be hidden.
### Current Composition Type
When the Region/Estate floater is opened to the terrain Tab, the current terrain should be shown in the four swatches, and the "PBR Metallic Roughness" checkbox should be checked or unchecked accordingly.
- If it is texture terrain, the "PBR Metallic Roughness" checkbox should be unchecked, and the floater should display the four textures applied to the terrain.
- If it is material terrain, the "PBR Metallic Roughness" checkbox should be checked, and the floater should display the four materials applied to the terrain.
In addition, where possible, textual labels and descriptions in the tab should make sense given the current value of the "PBR Metallic Roughness" checkbox. If the checkbox is unchecked, the labels should refer to textures. If the checkbox is checked, the labels should refer to materials.
### Toggling Composition Type
When toggling the "PBR Metallic Roughness" checkbox to the opposite value, which does not correspond to the current terrain type, one of the following sets of four terrain swatches will be displayed:
- The default textures/materials
- For textures, this is the default terrain texture set
- For materials, this is all blank materials, but this is subject to change
- The previously applied texture/material set
- History is available on a best-effort basis only. In particular, the history does not persist on viewer restart.
When toggling back the "PBR Metallic Roughness" checkbox to the original value, assuming nothing else has changed, then the current terrain should be shown in the four swatches again.
### Saving Composition
A user with appropriate permissions can change and save the textures or materials to the terrain. If the "PBR Metallic Roughness" checkbox is checked, the user applies materials, otherwise the user applies textures.
The user should not be allowed to set the texture or material swatches to null.
Saving may fail for the following reasons:
- A terrain or material texture is invalid
- A terrain texture is greater than the max texture upload resolution
If saving the terrain fails for any reason, the terrain should not be updated.
Unlike a viewer without PBR terrain support, the new viewer will no longer treat textures with alpha channels as invalid.
### Saving PBR Terrain Texture Transforms
If "PBR Metallic Roughness" checkbox is checked, a user with saving composition permissions should also be allowed to edit and save PBR texture transforms.
One texture transform may be set for each material swatch. Setting texture transforms for each individual texture on the material is not currently supported.
## Graphics Features
Texture terrain with transparency is not permitted to be applied in the viewer.
See [PBR Terrain Appearance](./pbr_terrain_appearance.md) for supported PBR terrain features.
## Minimap
The minimap should display the terrain with appropriate textures and colors.
+48
View File
@@ -0,0 +1,48 @@
# PBR Terrain Paintmap
## Introduction/Disclaimer
As of 2024-08-06, PBR terrain painting is **WIP**. Currently, there is only a client-side terrain paintmap, with no way to directly edit it. This document will explain how to informally explore this feature and compare it to the existing heightmap with noise. In the future, a testing document will be added for PBR terrain painting.
## Background
Historically, PBR terrain in a region has several parameters for controlling its composition. These are:
- The four materials
- The elevation of the terrain, which roughly controls the material, with some noise added on top ("heightmap with noise")
- Material Elevation Ranges, which control where the materials start and end
This allows for some coarse control over terrain composition. For example, you can have one corner of the terrain be a sandy beach and the rest of the coastline be rocky. Or you can have the peaks of your mountains be covered with snow. However, artistic control is limited due to the gradient imposed by the material elevation ranges, and the unpredictability of the noise.
A terrain painting option would allow for more control over the terrain composition. The first step to getting that working is the paintmap.
## How to activate the local paintmap
The local paintmap is a good way to assess the quality of the PBR terrain paintmap. By default, the newly created local paintmap inherits its composition (i.e. where the grass and dirt goes) from the existing terrain. This allows for a direct comparison with the terrain heightmap-with-noise shader.
Activating the local paintmap is similar to [applying local PBR terrain via the debug settings](https://wiki.secondlife.com/wiki/PBR_Terrain#How_to_apply_PBR_Terrain), but with a couple extra steps.
You will need:
- Four fullperm PBR material items to copy UUIDs from
- A region with a good variation of elevations which showcase the four composition layers (no special permissions needed)
Open the Debug Settings menu (Advanced > Show Debug Settings) and search for "terrain". The following relevant options are available:
- LocalTerrainAsset1
- LocalTerrainAsset1
- LocalTerrainAsset3
- LocalTerrainAsset4
- LocalTerrainPaintEnabled
- TerrainPaintBitDepth
- TerrainPaintResolution
By setting LocalTerrainAsset1, etc to valid material IDs, you will override the terrain to use those materials.
The next step is to "bake" the terrain into a paintmap (Develop > Terrain > Create Local Paintmap). This will *automatically* set LocalTerrainPaintEnabled to true. **WARNING:** LocalTerrainPaintEnabled will *not* do anything until one of LocalTerrainAsset1, etc is set.
You are now looking at the same terrain, but rendered as a paintmap.
To compare the quality of the paintmap version and the heightmap-with-noise version, toggle LocalTerrainPaintEnabled in Debug Settings.
To change the bit depth and/or resolution of the paintmap, change TerrainPaintBitDepth and TerrainPaintResolution as desired, then "re-bake" the paintmap (Develop > Terrain > Create Local Paintmap).
+29
View File
@@ -0,0 +1,29 @@
# Terrain Loading
## Behavior overview
- Texture terrain should load if textures are applied to the region, and no PBR Metallic Roughness materials are applied.
- PBR terrain should load if PBR materials are applied to the region, even if the RenderTerrainPBREnabled feature flag is disabled in debug settings. This setting only disables the display of PBR materials in the Region / Estate > Terrain UI.
- Related subsystem: A change to the PBR terrain loading system may affect the texture terrain loading system and vice-versa
- Related subsystem: Minimap should load if terrain loads
- They may not finish loading at the same time
## Implementation details
This section is provided mainly for clarification of how the terrain loading system works.
The simulator sends 4 terrain composition UUIDs to the viewer for the region. The viewer does not know ahead-of-time if the terrain composition uses textures or materials. Therefore, to expedite terrain loading, the viewer makes up to 8 "top-level" asset requests simultaneously:
- Up to 4 texture asset requests, one for each UUID
- Up to 4 material asset requests, one for each UUID
It is therefore expected that half of these asset lookups will fail.
The viewer inspects the load success of these top-level assets to make the binary decision of whether to render all 4 texture assets or all 4 material assets. This determines the choice of composition for terrain both in-world and on the minimap.
The minimap also attempts to wait for textures to partially load before it can render a tile for a given region:
- When rendering texture terrain, the minimap attempts to wait for top-level texture assets to partially load
- When rendering PBR material terrain, the minimap attempts to wait for any base color/emissive textures in the materials to partially load, if they are present
We don't make guarantees that the minimap tile will render for the region if any aforementioned required textures/materials fail to sufficiently load. However, the minimap may make a best-effort attempt to render the region by ignoring or replacing data.
+29
View File
@@ -0,0 +1,29 @@
#List of translators who contribute to SL Viewer 2.0+ by language
Danish
Flemming Congrejo
German
Torben Trautman
French
Valerie Linden
Polish
Identity Euler
Portuguese
Zaza Linden
Spanish
Aralara Rajal
Aura Dirval
Cayu Cluny
Eva Rau
FreeSL Aeon
Frontera Thor
Inma Rau
Irene Muni
Lunita Savira
Minerva Memel
Polo Gufler
Xiki Luik
Shinya Tandino
Catwise Yoshikawa
Traditional Chinese
gefeit Dufaux
+768
View File
@@ -0,0 +1,768 @@
<?xml version="1.0"?>
<llsd>
<map>
<key>serverDefaults</key>
<!--
a map of server names to default message transport
-->
<map>
<key>simulator</key>
<string>template</string>
<key>spaceserver</key>
<string>template</string>
<key>dataserver</key>
<string>template</string>
<key>logDataserver</key>
<string>template</string>
<key>inventoryDataserver</key>
<string>template</string>
<key>rpcserver</key>
<string>template</string>
<key>mapserver</key>
<string>template</string>
<key>viewer</key>
<string>template</string>
</map>
<key>messages</key>
<!--
a map of individual message names that override defaults
-->
<map>
<!--
Circuit related messages
-->
<key>PacketAck</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>OpenCircuit</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>CloseCircuit</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>StartPingCheck</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>CompletePingCheck</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>AddCircuitCode</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>UseCircuitCode</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>CreateTrustedCircuit</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>RequestTrustedCircuit</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<!--
Simulator to Launcher
until we get a HTTP server in the launcher
-->
<key>ReportAutosaveCrash</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>SetCPURatio</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<!--
Viewer to simulator messages sent before UntrustedSimulatorMessage cap received.
-->
<key>CompleteAgentMovement</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>EconomyDataRequest</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>ViewerEffect</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>RegionHandshakeReply</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<!--
Viewer to simulator messages sent unreliably.
-->
<key>AgentUpdate</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<!--
Messages created by LLThrottleGroup clients
-->
<key>ImagePacket</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>LayerData</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>ObjectUpdateCached</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>ObjectUpdateCompressed</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>ObjectUpdate</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>ImprovedTerseObjectUpdate</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>AvatarAnimation</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>ObjectAnimation</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>AvatarAppearance</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<!-- Simulator to simulator reliable messages -->
<key>GodKickUser</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>RoutedMoneyBalanceReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<!-- Simulator to simulator unreliable messages -->
<key>EdgeDataPacket</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>CoarseLocationUpdate</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>true</boolean>
<key>only-send-latest</key>
<boolean>true</boolean>
</map>
<key>SimulatorLoad</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>EstablishAgentCommunication</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>AgentGroupDataUpdate</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>AgentDropGroup</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ChatterBoxSessionStartReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ChatterBoxSessionEventReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ForceCloseChatterBoxSession</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ChatterBoxSessionAgentListUpdates</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ChatterBoxSessionUpdate</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ChatterBoxInvitation</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<!-- Client to server -->
<key>ParcelVoiceInfoRequest</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<!-- Server to client -->
<key>DisplayNameUpdate</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<!-- Server to client -->
<key>OpenRegionInfo</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>WindLightRefresh</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ParcelVoiceInfo</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ParcelNavigateMedia</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>ParcelObjectOwnersReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ParcelProperties</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>LandStatReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>PlacesReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>SetDisplayNameReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>SimConsoleResponse</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>DirLandReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>avatarnotesrequest</key>
<map>
<key>service_name</key>
<string>avatar-notes</string>
<key>builder</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>avatarclassifiedsrequest</key>
<map>
<key>service_name</key>
<string>avatar-classifieds</string>
<key>builder</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>avatarpicksrequest</key>
<map>
<key>service_name</key>
<string>avatar-pick</string>
<key>builder</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>pickinforequest</key>
<map>
<key>service_name</key>
<string>pick-info</string>
<key>builder</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>ProvisionVoiceAccountRequest</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>VoiceSignalingRequest</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<!-- Server to client -->
<key>RequiredVoiceVersion</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>EnableSimulator</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>TeleportFinish</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>TeleportFailed</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>CrossedRegion</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>NavMeshStatusUpdate</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>AgentStateUpdate</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<!-- UDPDeprecated Messages -->
<key>ScriptRunningReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>LandStatReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>StartGroupProposal</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>FetchInventoryDescendents</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>GroupProposalBallot</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>RpcScriptRequestInboundForward</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>ObjectPhysicsProperties</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
</map>
<key>capBans</key>
<map>
<key>MapLayer</key>
<boolean>false</boolean>
<key>MapLayerGod</key>
<boolean>false</boolean>
<key>NewFileAgentInventory</key>
<boolean>false</boolean>
<key>UpdateGestureAgentInventory</key>
<boolean>false</boolean>
<key>UpdateNotecardAgentInventory</key>
<boolean>false</boolean>
<key>UpdateScriptAgentInventory</key>
<boolean>false</boolean>
<key>UpdateGestureTaskInventory</key>
<boolean>false</boolean>
<key>UpdateNotecardTaskInventory</key>
<boolean>false</boolean>
<key>UpdateScriptTaskInventory</key>
<boolean>false</boolean>
<key>ViewerStartAuction</key>
<boolean>true</boolean>
<key>ParcelGodReserveForNewbie</key>
<boolean>true</boolean>
<key>SendUserReport</key>
<boolean>false</boolean>
<key>SendUserReportWithScreenshot</key>
<boolean>false</boolean>
<key>RequestTextureDownload</key>
<boolean>true</boolean>
<key>EventQueueGet</key>
<boolean>false</boolean>
<key>UntrustedSimulatorMessage</key>
<boolean>false</boolean>
<key>SendPostcard</key>
<boolean>false</boolean>
<key>SendPostcard2</key>
<boolean>true</boolean>
<key>SendPostcard3</key>
<boolean>true</boolean>
<key>ParcelVoiceInfoRequest</key>
<boolean>false</boolean>
<key>ChatSessionRequest</key>
<boolean>false</boolean>
<key>ProvisionVoiceAccountRequest</key>
<boolean>false</boolean>
<key>VoiceSignalingRequest</key>
<boolean>false</boolean>
<key>RemoteParcelRequest</key>
<boolean>false</boolean>
<key>SearchStatTracking</key>
<boolean>false</boolean>
<key>ParcelPropertiesUpdate</key>
<boolean>false</boolean>
<key>EstateChangeInfo</key>
<boolean>true</boolean>
<key>FetchInventoryDescendents2</key>
<boolean>false</boolean>
<key>FetchInventory2</key>
<boolean>false</boolean>
<key>FetchLibDescendents2</key>
<boolean>false</boolean>
<key>FetchLib2</key>
<boolean>false</boolean>
<key>UploadBakedTexture</key>
<boolean>true</boolean>
<key>ObjectMedia</key>
<boolean>false</boolean>
<key>ObjectMediaNavigate</key>
<boolean>false</boolean>
</map>
<key>messageBans</key>
<map>
<key>trusted</key>
<map>
</map>
<key>untrusted</key>
<map>
</map>
</map>
<key>maxQueuedEvents</key>
<integer>100</integer>
</map>
</llsd>
+200
View File
@@ -0,0 +1,200 @@
# -*- cmake -*-
# cmake_minimum_required should appear before any
# other commands to guarantee full compatibility
# with the version specified
## 3.8 added VS_DEBUGGER_WORKING_DIRECTORY support
## 3.13/12 is needed for add_link_options/add_compile_definitions
## 3.14 added FILE CREATE_LINK
## 3.16 is needed for target_precompile_headers
## Nicky: Ideally we want at least 3.21 for good preset support
## We're not there yet, but once done, there is a kludge in Linking.cmake
# "if(${CMAKE_VERSION} VERSION_LESS "3.20.0")" that can also be removed
cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR)
set(ROOT_PROJECT_NAME "Puma" CACHE STRING
"The root project/makefile/solution name. Defaults to Puma.")
project(${ROOT_PROJECT_NAME})
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_CURRENT_BINARY_DIR}")
include(conanbuildinfo OPTIONAL RESULT_VARIABLE USE_CONAN )
if( USE_CONAN )
set( USE_CONAN ON )
set( USE_AUTOBUILD_3P OFF )
conan_basic_setup(TARGETS NO_OUTPUT_DIRS)
add_compile_definitions(LL_USESYSTEMLIBS USE_CONAN NO_AUTOBUILD_3P)
else()
set( USE_CONAN OFF )
set( USE_AUTOBUILD_3P ON )
endif()
if (NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 20)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(Variables)
include(BuildVersion)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING
"Build type. One of: Release RelWithDebInfo" FORCE)
endif (NOT CMAKE_BUILD_TYPE)
#<FS:AW optional opensim support>
option(OPENSIM "OpenSim support" OFF)
if (OPENSIM)
add_compile_definitions(OPENSIM)
if (SINGLEGRID)
add_compile_definitions(SINGLEGRID SINGLEGRID_URI=\"${SINGLEGRID_URI}\")
message(STATUS "Compiling with OpenSim support - Single Grid version (${SINGLEGRID_URI})")
else (SINGLEGRID)
message(STATUS "Compiling with OpenSim support")
endif (SINGLEGRID)
else (OPENSIM)
if (SINGLEGRID)
message(WARNING "Value for SINGLEGRID is unused during Havok/SecondLife builds" )
endif()
message(STATUS "Compiling without OpenSim support")
endif (OPENSIM)
if (HAVOK_TPV)
add_compile_definitions(HAVOK_TPV)
message(STATUS "Compiling with Havok libraries")
endif (HAVOK_TPV)
#</FS:AW optional opensim support>
#<FS:Ansariel> Support for test builds
option(TESTBUILD "Generating test build" OFF)
if(TESTBUILD AND TESTBUILDPERIOD)
add_compile_definitions(TESTBUILD TESTBUILDPERIOD=${TESTBUILDPERIOD})
message(STATUS "Creating test build version; test period: ${TESTBUILDPERIOD} days")
endif(TESTBUILD AND TESTBUILDPERIOD)
#</FS:Ansariel>
# <FS:Ansariel> [AVX Optimization]
option(USE_AVX_OPTIMIZATION "AVX optimization support" OFF)
option(USE_AVX2_OPTIMIZATION "AVX2 optimization support" OFF)
if (USE_AVX_OPTIMIZATION)
if (USE_AVX2_OPTIMIZATION)
message(FATAL_ERROR "You cannot use AVX and AVX2 at the same time!")
else (USE_AVX2_OPTIMIZATION)
add_compile_definitions(USE_AVX_OPTIMIZATION)
message(STATUS "Compiling with AVX optimizations")
endif (USE_AVX2_OPTIMIZATION)
elseif (USE_AVX2_OPTIMIZATION)
add_compile_definitions(USE_AVX2_OPTIMIZATION)
message(STATUS "Compiling with AVX2 optimizations")
else (USE_AVX_OPTIMIZATION)
message(STATUS "Compiling without AVX optimizations")
endif (USE_AVX_OPTIMIZATION)
# </FS:Ansariel> [AVX Optimization]
add_subdirectory(cmake)
# <FS:Beq> Tracy Profiler support
if (USE_TRACY)
message(STATUS "Compiling with Tracy profiler")
else (USE_TRACY)
message(STATUS "Compiling without Tracy profiler")
endif (USE_TRACY)
# </FS:Beq> Tracy Profiler support
add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
add_subdirectory(${LIBS_OPEN_PREFIX}llappearance)
add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
add_subdirectory(${LIBS_OPEN_PREFIX}llcommon)
add_subdirectory(${LIBS_OPEN_PREFIX}llcorehttp)
add_subdirectory(${LIBS_OPEN_PREFIX}llimage)
add_subdirectory(${LIBS_OPEN_PREFIX}llkdu)
add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)
add_subdirectory(${LIBS_OPEN_PREFIX}llinventory)
add_subdirectory(${LIBS_OPEN_PREFIX}llmath)
add_subdirectory(${LIBS_OPEN_PREFIX}llmeshoptimizer)
add_subdirectory(${LIBS_OPEN_PREFIX}llmessage)
add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive)
add_subdirectory(${LIBS_OPEN_PREFIX}llrender)
add_subdirectory(${LIBS_OPEN_PREFIX}llfilesystem)
add_subdirectory(${LIBS_OPEN_PREFIX}llwebrtc)
add_subdirectory(${LIBS_OPEN_PREFIX}llwindow)
add_subdirectory(${LIBS_OPEN_PREFIX}llxml)
if (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts)
add_subdirectory(${LIBS_CLOSED_PREFIX}copy_win_scripts)
endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts)
add_custom_target(viewer)
if (NOT USE_BUGSPLAT)
add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger)
endif (NOT USE_BUGSPLAT)
if( LINUX )
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
endif()
add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
add_subdirectory(${LIBS_OPEN_PREFIX}llui)
add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components)
if( LL_TESTS )
# Legacy C++ tests. Build always, run if LL_TESTS is true.
add_subdirectory(${VIEWER_PREFIX}test)
endif()
if (ENABLE_MEDIA_PLUGINS)
# viewer media plugins
add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
endif (ENABLE_MEDIA_PLUGINS)
if (LINUX)
if (INSTALL_PROPRIETARY)
include(LLAppearanceUtility)
add_subdirectory(${LLAPPEARANCEUTILITY_SRC_DIR} ${LLAPPEARANCEUTILITY_BIN_DIR})
endif (INSTALL_PROPRIETARY)
elseif (WINDOWS)
# cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake
if (EXISTS ${VIEWER_DIR}win_setup)
add_subdirectory(${VIEWER_DIR}win_setup)
endif (EXISTS ${VIEWER_DIR}win_setup)
endif (LINUX)
if (WINDOWS)
# cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake
if (EXISTS ${VIEWER_DIR}win_setup)
add_subdirectory(${VIEWER_DIR}win_setup)
endif (EXISTS ${VIEWER_DIR}win_setup)
endif (WINDOWS)
if (USE_BUGSPLAT)
if (BUGSPLAT_DB)
message(STATUS "Building with BugSplat; database '${BUGSPLAT_DB}'")
else (BUGSPLAT_DB)
message(WARNING "Building with BugSplat, but no database name set (BUGSPLAT_DB)")
endif (BUGSPLAT_DB)
else (USE_BUGSPLAT)
message(STATUS "Not building with BugSplat")
endif (USE_BUGSPLAT)
add_subdirectory(${VIEWER_PREFIX}newview)
add_dependencies(viewer puma-bin)
set_target_properties(
puma-bin PROPERTIES
VS_DEBUGGER_WORKING_DIRECTORY "..\\..\\indra\\newview")
add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL)
# sets the 'startup project' for debugging from visual studio.
set_property(
DIRECTORY ${VIEWER_PREFIX}
PROPERTY VS_STARTUP_PROJECT ${VIEWER_BINARY_NAME}
)
if (LL_TESTS)
# Define after the custom targets are created so
# individual apps can add themselves as dependencies
add_subdirectory(${INTEGRATION_TESTS_PREFIX}integration_tests)
endif (LL_TESTS)
+1
View File
@@ -0,0 +1 @@
VERSION_VIEWER=4.7.6
+35
View File
@@ -0,0 +1,35 @@
# -*- cmake -*-
# The copy_win_scripts folder contains scripts handy for launching the
# from the windows command line on windows.
# The cmake target created copies the scripts to the
# build directory being used, which where the scripts
# need to be executed from.
include(CMakeCopyIfDifferent)
set(win_scripts-src ${CMAKE_SOURCE_DIR}/copy_win_scripts)
set(win_scripts-dst ${CMAKE_BINARY_DIR}/batch)
set(file-list
llstart.py
start-client.py
start-servers.py
stop-servers.py
user_config.py
)
foreach(file ${file-list})
if(EXISTS ${win_scripts-src}/${file})
set(win_scripts-files ${win_scripts-files} ${file})
endif(EXISTS ${win_scripts-src}/${file})
endforeach(file ${file-list})
copy_if_different(
${win_scripts-src}
${win_scripts-dst}
win_scripts-targets
${win_scripts-files}
)
add_custom_target(copy_win_scripts ALL DEPENDS ${win_scripts-targets})
+92
View File
@@ -0,0 +1,92 @@
#!/usr/bin/env python3
"""\
@file start-client.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$
"""
import sys, getopt
import os
import llstart
def usage():
print("""start-client.py
--grid <grid>
--farm <grid>
--region <starting region name>
""")
def start_client(grid, slurl, build_config, my_args):
login_url = "https://login.%s.lindenlab.com/cgi-bin/login.cgi" % (grid)
viewer_args = { "--grid" : grid,
"--loginuri" : login_url }
viewer_args.update(my_args)
# *sigh* We must put --url at the end of the argument list.
if "--url" in viewer_args:
slurl = viewer_args["--url"]
del(viewer_args["--url"])
viewer_args = llstart.get_args_from_dict(viewer_args)
if slurl is not None:
viewer_args += " --url %s" % slurl
# Figure out path stuff.
# The client should run from indra/newview
# but the exe is at indra/build-<xxx>/newview/<target>
build_path = os.path.dirname(os.getcwd());
f = open("start-client.log", "w")
print("Viewer startup arguments:", file=f)
llstart.start("viewer", "../../newview",
"%s/newview/%s/firestorm-bin.exe" % (build_path, build_config),
viewer_args, f)
f.close()
if __name__ == "__main__":
grid = llstart.get_config("grid")
if grid == None:
grid = "aditi"
build_config = llstart.get_config("build_config")
my_args = llstart.get_config("viewer_args", force_dict = True)
opts, args = getopt.getopt(sys.argv[1:], "u:r:f:g:i:h",
["region=", "username=", "farm=", "grid=", "ip=", "help"])
region = None
for o, a in opts:
if o in ("-r", "--region", "-u", "--username"):
region = a
if o in ("-f", "--farm", "-g", "--grid"):
grid = a
if o in ("-h", "--help"):
usage()
sys.exit(0)
slurl = llstart.get_config("slurl")
if slurl == None:
if region is None:
region = llstart.get_user_name()
slurl = "//%s/128/128/" % (region)
# Ensure the slurl has quotes around it.
if slurl is not None:
slurl = '"%s"' % (slurl.strip('"\''))
start_client(grid, slurl, build_config, my_args)
+28
View File
@@ -0,0 +1,28 @@
# -*- cmake -*-
# cmake_minimum_required should appear before any
# other commands to guarantee full compatibility
# with the version specified
## prior to 2.8, the add_custom_target commands used in setting the version did not work correctly
#cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR)
set(ROOT_PROJECT_NAME "SecondLife" CACHE STRING
"The root project/makefile/solution name. Defaults to SecondLife.")
project(${ROOT_PROJECT_NAME})
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(Variables)
# add a target to generate API documentation with Doxygen
find_package(Doxygen)
if(DOXYGEN_FOUND)
GET_FILENAME_COMPONENT(DOXYGEN_TOP_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.. PATH)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
add_custom_target(doc
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
COMMENT "Generating API documentation with Doxygen" VERBATIM
)
endif(DOXYGEN_FOUND)
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
+8
View File
@@ -0,0 +1,8 @@
# -*- cmake -*-
add_subdirectory(llui_libtest)
IF (LLIMAGE_LIBTEST)
MESSAGE(STATUS "Build llimage_libtest")
add_subdirectory(llimage_libtest)
ELSE (LLIMAGE_LIBTEST)
MESSAGE(STATUS "Skip llimage_libtest")
ENDIF (LLIMAGE_LIBTEST)
@@ -0,0 +1,105 @@
# -*- cmake -*-
# Integration tests of the llimage library (JPEG2000, PNG, jpeg, etc... images reading and writing)
project (llimage_libtest)
include(00-Common)
include(LLCommon)
include(LLImage)
include(LLMath)
include(LLImageJ2COJ)
include(LLKDU)
include(LLFileSystem)
set(llimage_libtest_SOURCE_FILES
llimage_libtest.cpp
)
set(llimage_libtest_HEADER_FILES
CMakeLists.txt
llimage_libtest.h
)
list(APPEND llimage_libtest_SOURCE_FILES ${llimage_libtest_HEADER_FILES})
add_executable(llimage_libtest
WIN32
MACOSX_BUNDLE
${llimage_libtest_SOURCE_FILES}
)
set_target_properties(llimage_libtest
PROPERTIES
WIN32_EXECUTABLE
FALSE
)
# Libraries on which this application depends on
# Sort by high-level to low-level
target_link_libraries(llimage_libtest
llcommon
llfilesystem
llmath
llimage
llkdu
llimagej2coj
)
if (DARWIN)
# Path inside the app bundle where we'll need to copy libraries
set(LLIMAGE_LIBTEST_DESTINATION_DIR
${CMAKE_CURRENT_BINARY_DIR}/$<IF:$<BOOL:${LL_GENERATOR_IS_MULTI_CONFIG}>,$<CONFIG>,>/llimage_libtest.app/Contents/Resources
)
# Create the Contents/Resources directory
add_custom_command(
TARGET llimage_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS
-E
make_directory
${LLIMAGE_LIBTEST_DESTINATION_DIR}
COMMENT "Creating Resources directory in app bundle."
)
else (DARWIN)
set(LLIMAGE_LIBTEST_DESTINATION_DIR
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
)
endif (DARWIN)
get_target_property(BUILT_LLCOMMON llcommon LOCATION)
add_custom_command(TARGET llimage_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_LLCOMMON} ${LLIMAGE_LIBTEST_DESTINATION_DIR}
DEPENDS ${BUILT_LLCOMMON}
)
if (DARWIN)
# Copy the required libraries to the package app
add_custom_command(TARGET llimage_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${AUTOBUILD_INSTALL_DIR}/lib/release/libapr-1.0.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
DEPENDS ${AUTOBUILD_INSTALL_DIR}/lib/release/libapr-1.0.dylib
)
add_custom_command(TARGET llimage_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${AUTOBUILD_INSTALL_DIR}/lib/release/libaprutil-1.0.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
DEPENDS ${AUTOBUILD_INSTALL_DIR}/lib/release/libaprutil-1.0.dylib
)
add_custom_command(TARGET llimage_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${AUTOBUILD_INSTALL_DIR}/lib/release/libexception_handler.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
DEPENDS ${AUTOBUILD_INSTALL_DIR}/lib/release/libexception_handler.dylib
)
foreach(expat ${EXPAT_COPY})
add_custom_command(TARGET llimage_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${AUTOBUILD_INSTALL_DIR}/lib/release/${expat} ${LLIMAGE_LIBTEST_DESTINATION_DIR}
DEPENDS ${AUTOBUILD_INSTALL_DIR}/lib/release/${expat}
)
endforeach(expat)
endif (DARWIN)
if (WINDOWS)
# Check indra/test_apps/llplugintest/CMakeLists.txt for an example of what to copy over for Windows and how
endif (WINDOWS)
# Ensure people working on the viewer don't break this library
# *NOTE: This could be removed, or only built by TeamCity, if the build
# and link times become too long.
add_dependencies(viewer llimage_libtest)
@@ -0,0 +1,41 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>contrast</string>
<real>0.8</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.5</real>
<real>0.0</real>
<real>0.0</real>
</array>
<array>
<string>blend</string>
<real>10.0</real>
<real>0.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.1</real>
<real>0.1</real>
<real>0.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,11 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.01</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,36 @@
<llsd>
<array>
<array>
<string>grayscale</string>
</array>
<array>
<string>linearize</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>posterize</string>
<real>10.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>gradient</string>
</array>
<array>
<string>colorize</string>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.15</real>
</array>
<array>
<string>blur</string>
</array>
</array>
</llsd>
@@ -0,0 +1,25 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>stencil</string>
<string>uniform</string>
<string>add</string>
<real>0.0</real>
<real>1.0</real>
</array>
<array>
<string>gamma</string>
<real>0.25</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,7 @@
<llsd>
<array>
<array>
<string>blur</string>
</array>
</array>
</llsd>
@@ -0,0 +1,11 @@
<llsd>
<array>
<array>
<string>brighten</string>
<real>0.5</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,24 @@
<llsd>
<array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>blend</string>
<real>0.0</real>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>10.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.5</real>
<real>0.5</real>
<real>0.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,16 @@
<llsd>
<array>
<array>
<string>colortransform</string>
<real>0.2125</real>
<real>0.7154</real>
<real>0.0721</real>
<real>0.2125</real>
<real>0.7154</real>
<real>0.0721</real>
<real>0.2125</real>
<real>0.7154</real>
<real>0.0721</real>
</array>
</array>
</llsd>
@@ -0,0 +1,11 @@
<llsd>
<array>
<array>
<string>contrast</string>
<real>1.5</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,18 @@
<llsd>
<array>
<array>
<string>convolve</string>
<real>1.0</real>
<real>0.0</real>
<real>4.0</real>
<real>1.0</real>
<real>4.0</real>
<real>1.0</real>
<real>0.0</real>
<real>1.0</real>
<real>4.0</real>
<real>1.0</real>
<real>4.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,11 @@
<llsd>
<array>
<array>
<string>darken</string>
<real>0.5</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,47 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>add</string>
<real>0.0</real>
<real>0.4</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>2.0</real>
</array>
<array>
<string>contrast</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>add</string>
<real>-0.8</real>
<real>0.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>2.0</real>
</array>
<array>
<string>contrast</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,24 @@
<llsd>
<array>
<array>
<string>gradient</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>contrast</string>
<real>2.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,39 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>blend</string>
<real>0.0</real>
<real>0.4</real>
<real>0.0</real>
<real>0.0</real>
<real>0.5</real>
<real>2.0</real>
</array>
<array>
<string>sharpen</string>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>blend</string>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.5</real>
<real>2.0</real>
</array>
<array>
<string>blur</string>
</array>
</array>
</llsd>
@@ -0,0 +1,11 @@
<llsd>
<array>
<array>
<string>gamma</string>
<real>1.7</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,14 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>grayscale</string>
</array>
</array>
</llsd>
@@ -0,0 +1,38 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>contrast</string>
<real>0.8</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>fade</string>
<real>0.5</real>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>4.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>0.0</real>
<real>1.0</real>
<real>0.4</real>
<real>0.0</real>
<real>0.2</real>
</array>
</array>
</llsd>
@@ -0,0 +1,20 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>grayscale</string>
</array>
<array>
<string>screen</string>
<string>line</string>
<real>0.015</real>
<real>0.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,20 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>grayscale</string>
</array>
<array>
<string>screen</string>
<string>line</string>
<real>0.02</real>
<real>0.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,131 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.01</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>stencil</string>
<string>gradient</string>
<string>add</string>
<real>1.0</real>
<real>0.0</real>
<real>-1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>-1.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.1</real>
<real>0.1</real>
<real>0.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>add</string>
<real>0.0</real>
<real>1.0</real>
<real>-1.0</real>
<real>1.0</real>
<real>1.5</real>
<real>5.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.6</real>
<real>0.0</real>
<real>0.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>add</string>
<real>0.0</real>
<real>1.0</real>
<real>-1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>5.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.6</real>
<real>0.6</real>
<real>0.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>add</string>
<real>0.0</real>
<real>0.5</real>
<real>0.5</real>
<real>-0.5</real>
<real>0.10</real>
<real>20.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.7</real>
<real>0.0</real>
<real>0.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>add</string>
<real>0.0</real>
<real>0.5</real>
<real>0.6</real>
<real>-0.6</real>
<real>0.05</real>
<real>20.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.7</real>
<real>0.0</real>
<real>0.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>add</string>
<real>0.0</real>
<real>0.5</real>
<real>0.4</real>
<real>-0.4</real>
<real>0.025</real>
<real>20.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.7</real>
<real>0.0</real>
<real>0.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,78 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.01</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>brighten</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>stencil</string>
<string>gradient</string>
<string>add</string>
<real>1.0</real>
<real>0.0</real>
<real>-1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>-1.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.1</real>
<real>0.1</real>
<real>0.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>add</string>
<real>0.0</real>
<real>1.0</real>
<real>-1.0</real>
<real>1.0</real>
<real>1.5</real>
<real>5.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.8</real>
<real>0.0</real>
<real>0.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>add</string>
<real>0.0</real>
<real>1.0</real>
<real>-1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>5.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.8</real>
<real>0.8</real>
<real>0.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,11 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,118 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.02</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>contrast</string>
<real>1.02</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>saturate</string>
<real>1.2</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>blend</string>
<real>0.0</real>
<real>0.25</real>
<real>0.0</real>
<real>0.0</real>
<real>0.25</real>
<real>2.0</real>
</array>
<array>
<string>sharpen</string>
</array>
<array>
<string>stencil</string>
<string>gradient</string>
<string>blend</string>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>-1.0</real>
<real>0.0</real>
<real>-0.25</real>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>stencil</string>
<string>gradient</string>
<string>blend</string>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>0.0</real>
<real>0.25</real>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
</array>
</llsd>
@@ -0,0 +1,20 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>grayscale</string>
</array>
<array>
<string>screen</string>
<string>2Dsine</string>
<real>0.015</real>
<real>0.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,24 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
<real>0.0</real>
<real>0.3</real>
<real>0.0</real>
</array>
<array>
<string>saturate</string>
<real>0.35</real>
</array>
</array>
</llsd>
@@ -0,0 +1,35 @@
<llsd>
<array>
<array>
<string>blur</string>
</array>
<array>
<string>darken</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>contrast</string>
<real>0.9</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>linearize</string>
<real>0.01</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>posterize</string>
<real>4.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,11 @@
<llsd>
<array>
<array>
<string>posterize</string>
<real>10.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,8 @@
<llsd>
<array>
<array>
<string>rotate</string>
<real>180.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,8 @@
<llsd>
<array>
<array>
<string>saturate</string>
<real>3.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,14 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>sepia</string>
</array>
</array>
</llsd>
@@ -0,0 +1,7 @@
<llsd>
<array>
<array>
<string>sharpen</string>
</array>
</array>
</llsd>
@@ -0,0 +1,20 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>grayscale</string>
</array>
<array>
<string>screen</string>
<string>line</string>
<real>0.015</real>
<real>45.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,45 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>contrast</string>
<real>0.8</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>saturate</string>
<real>1.5</real>
</array>
<array>
<string>fade</string>
<real>1.0</real>
<real>0.25</real>
</array>
<array>
<string>saturate</string>
<real>0.8</real>
</array>
<array>
<string>contrast</string>
<real>1.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>brighten</string>
<real>30</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,24 @@
<llsd>
<array>
<array>
<string>stencil</string>
<string>gradient</string>
<string>blend</string>
<real>0.0</real>
<real>1.0</real>
<real>0.0</real>
<real>-1.0</real>
<real>0.0</real>
<real>1.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,22 @@
<llsd>
<array>
<array>
<string>stencil</string>
<string>scanlines</string>
<string>blend</string>
<real>0.0</real>
<real>0.5</real>
<real>0.1</real>
<real>45.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,20 @@
<llsd>
<array>
<array>
<string>stencil</string>
<string>uniform</string>
<string>blend</string>
<real>0.0</real>
<real>0.5</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,24 @@
<llsd>
<array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>blend</string>
<real>0.0</real>
<real>0.5</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>10.0</real>
</array>
<array>
<string>colorize</string>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,42 @@
<llsd>
<array>
<array>
<string>grayscale</string>
</array>
<array>
<string>linearize</string>
<real>0.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>posterize</string>
<real>50.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>gradient</string>
</array>
<array>
<string>screen</string>
<string>line</string>
<real>0.025</real>
<real>90.0</real>
</array>
<array>
<string>colorize</string>
<real>0.0</real>
<real>1.0</real>
<real>0.0</real>
<real>0.1</real>
<real>0.2</real>
<real>0.2</real>
</array>
<array>
<string>blur</string>
</array>
</array>
</llsd>
@@ -0,0 +1,46 @@
<llsd>
<array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>fade</string>
<real>0.0</real>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.2</real>
<real>3.0</real>
</array>
<array>
<string>linearize</string>
<real>0.05</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>grayscale</string>
</array>
<array>
<string>contrast</string>
<real>1.1</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>stencil</string>
<string>vignette</string>
<string>blend</string>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.5</real>
<real>2.0</real>
</array>
<array>
<string>blur</string>
</array>
</array>
</llsd>
@@ -0,0 +1,20 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>grayscale</string>
</array>
<array>
<string>screen</string>
<string>line</string>
<real>0.015</real>
<real>90.0</real>
</array>
</array>
</llsd>
@@ -0,0 +1,44 @@
<llsd>
<array>
<array>
<string>linearize</string>
<real>0.0</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>darken</string>
<real>0.15</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>stencil</string>
<string>uniform</string>
<string>add</string>
<real>0.0</real>
<real>0.5</real>
</array>
<array>
<string>screen</string>
<string>line</string>
<real>0.02</real>
<real>0.0</real>
</array>
<array>
<string>gamma</string>
<real>0.25</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
<array>
<string>blur</string>
</array>
<array>
<string>blur</string>
</array>
</array>
</llsd>
@@ -0,0 +1,645 @@
/**
* @file llimage_libtest.cpp
* @author Merov Linden
* @brief Integration test for the llimage library
*
* $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$
*/
#include "linden_common.h"
#include "llpointer.h"
#include "lltimer.h"
#include "llimage_libtest.h"
// Linden library includes
#include "llimage.h"
#include "llimagefilter.h"
#include "llimagejpeg.h"
#include "llimagepng.h"
#include "llimagebmp.h"
#include "llimagetga.h"
#include "llimagej2c.h"
#include "lldir.h"
#include "lldiriterator.h"
#include "v4coloru.h"
#include "llsdserialize.h"
#include "llcleanup.h"
// system libraries
#include <iostream>
// doc string provided when invoking the program with --help
static const char USAGE[] = "\n"
"usage:\tllimage_libtest [options]\n"
"\n"
" -h, --help\n"
" Print this help\n"
" -i, --input <file1 .. file2>\n"
" List of image files to load and convert. Patterns with wild cards can be used.\n"
" -o, --output <file1 .. file2> OR <type>\n"
" List of image files to create (assumes same order as for input files)\n"
" OR 3 letters file type extension to convert each input file into.\n"
" -load, --load_size <n>\n"
" Portion of the input file to load, in bytes."
" If (load == 0), it will load the whole file."
" If (load == -1), it will load the size relevant to reach the requested discard level (see -d)."
" Only valid for j2c images. Default is 0 (load whole file).\n"
" -r, --region <x0, y0, x1, y1>\n"
" Crop region applied to the input files in pixels.\n"
" Only used for j2c images. Default is no region cropping.\n"
" -d, --discard_level <n>\n"
" Discard level max used on input. 0 is highest resolution. Max discard level is 5.\n"
" This allows the input image to be clamped in resolution when loading.\n"
" Only valid for j2c images. Default is no discard.\n"
" -p, --precincts <n>\n"
" Dimension of precincts in pixels. Precincts are assumed square and identical for\n"
" all levels. Note that this option also add PLT and tile markers to the codestream, \n"
" and uses RPCL order. Power of 2 must be used.\n"
" Only valid for output j2c images. Default is no precincts used.\n"
" -b, --blocks <n>\n"
" Dimension of coding blocks in pixels. Blocks are assumed square. Power of 2 must\n"
" be used. Blocks must be smaller than precincts. Like precincts, this option adds\n"
" PLT, tile markers and uses RPCL.\n"
" Only valid for output j2c images. Default is 64.\n"
" -l, --levels <n>\n"
" Number of decomposition levels (aka discard levels) in the output image.\n"
" The maximum number of levels authorized is 32.\n"
" Only valid for output j2c images. Default is 5.\n"
" -rev, --reversible\n"
" Set the compression to be lossless (reversible in j2c parlance).\n"
" Only valid for output j2c images.\n"
" -f, --filter <file>\n"
" Apply the filter <file> to the input images.\n"
" -log, --logmetrics <metric>\n"
" Log performance data for <metric>. Results in <metric>.slp\n"
" Note: so far, only ImageCompressionTester has been tested.\n"
" -a, --analyzeperformance\n"
" Create a report comparing <metric>_baseline.slp with current <metric>.slp\n"
" Results in <metric>_report.csv\n"
" -s, --image-stats\n"
" Output stats for each input and output image.\n"
"\n";
// true when all image loading is done. Used by metric logging thread to know when to stop the thread.
static bool sAllDone = false;
// Create an empty formatted image instance of the correct type from the filename
LLPointer<LLImageFormatted> create_image(const std::string &filename)
{
std::string exten = gDirUtilp->getExtension(filename);
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromExtension(exten);
return image;
}
void output_image_stats(LLPointer<LLImageFormatted> image, const std::string &filename)
{
// Print out some statistical data on the image
std::cout << "Image stats for : " << filename << ", extension : " << image->getExtension() << std::endl;
std::cout << " with : " << (int)(image->getWidth()) << ", height : " << (int)(image->getHeight()) << std::endl;
std::cout << " comp : " << (int)(image->getComponents()) << ", levels : " << (int)(image->getLevels()) << std::endl;
std::cout << " head : " << (int)(image->calcHeaderSize()) << ", data : " << (int)(image->getDataSize()) << std::endl;
return;
}
// Load an image from file and return a raw (decompressed) instance of its data
LLPointer<LLImageRaw> load_image(const std::string &src_filename, int discard_level, int* region, int load_size, bool output_stats)
{
LLPointer<LLImageFormatted> image = create_image(src_filename);
// We support partial loading only for j2c images
if (image->getCodec() == IMG_CODEC_J2C)
{
// Load the header
if (!image->load(src_filename, 600))
{
return NULL;
}
S32 h = ((LLImageJ2C*)(image.get()))->calcHeaderSize();
S32 d = (load_size > 0 ? ((LLImageJ2C*)(image.get()))->calcDiscardLevelBytes(load_size) : 0);
S8 r = ((LLImageJ2C*)(image.get()))->getRawDiscardLevel();
std::cout << "Merov debug : header = " << h << ", load_size = " << load_size << ", discard level = " << d << ", raw discard level = " << r << std::endl;
for (d = 0; d < MAX_DISCARD_LEVEL; d++)
{
S32 data_size = ((LLImageJ2C*)(image.get()))->calcDataSize(d);
std::cout << "Merov debug : discard_level = " << d << ", data_size = " << data_size << std::endl;
}
if (load_size < 0)
{
load_size = (discard_level != -1 ? ((LLImageJ2C*)(image.get()))->calcDataSize(discard_level) : 0);
}
// Load the requested byte range
if (!image->load(src_filename, load_size))
{
return NULL;
}
}
else
{
// This just loads the image file stream into a buffer. No decoding done.
if (!image->load(src_filename))
{
return NULL;
}
}
if( (image->getComponents() != 3) && (image->getComponents() != 4) )
{
std::cout << "Image files with less than 3 or more than 4 components are not supported\n";
return NULL;
}
if (output_stats)
{
output_image_stats(image, src_filename);
}
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
// Set the image restriction on load in the case of a j2c image
if ((image->getCodec() == IMG_CODEC_J2C) && ((discard_level != -1) || (region != NULL)))
{
// That method doesn't exist (and likely, doesn't make sense) for any other image file format
// hence the required cryptic cast.
((LLImageJ2C*)(image.get()))->initDecode(*raw_image, discard_level, region);
}
if (!image->decode(raw_image, 0.0f))
{
return NULL;
}
return raw_image;
}
// Save a raw image instance into a file
bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, int blocks_size, int precincts_size, int levels, bool reversible, bool output_stats)
{
LLPointer<LLImageFormatted> image = create_image(dest_filename);
// Set the image codestream parameters on output in the case of a j2c image
if (image->getCodec() == IMG_CODEC_J2C)
{
// That method doesn't exist (and likely, doesn't make sense) for any other image file format
// hence the required cryptic cast.
if ((blocks_size != -1) || (precincts_size != -1) || (levels != 0))
{
((LLImageJ2C*)(image.get()))->initEncode(*raw_image, blocks_size, precincts_size, levels);
}
((LLImageJ2C*)(image.get()))->setReversible(reversible);
}
if (!image->encode(raw_image, 0.0f))
{
return false;
}
if (output_stats)
{
output_image_stats(image, dest_filename);
}
return image->save(dest_filename);
}
void store_input_file(std::list<std::string> &input_filenames, const std::string &path)
{
// Break the incoming path in its components
std::string dir = gDirUtilp->getDirName(path);
std::string name = gDirUtilp->getBaseFileName(path);
std::string exten = gDirUtilp->getExtension(path);
// std::cout << "store_input_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl;
// If extension is not an image type or "*", exit
// Note: we don't support complex patterns for the extension like "j??"
// Note: on most shells, the pattern expansion is done by the shell so that pattern matching limitation is actually not a problem
if ((exten.compare("*") != 0) && (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID))
{
return;
}
if ((name.find('*') != -1) || ((name.find('?') != -1)))
{
// If file name is a pattern, iterate to get each file name and store
std::string next_name;
LLDirIterator iter(dir, name);
while (iter.next(next_name))
{
std::string file_name = gDirUtilp->add(dir, next_name);
input_filenames.push_back(file_name);
}
}
else
{
// Verify that the file does exist before storing
if (gDirUtilp->fileExists(path))
{
input_filenames.push_back(path);
}
else
{
std::cout << "store_input_file : the file " << path << " could not be found" << std::endl;
}
}
}
void store_output_file(std::list<std::string> &output_filenames, std::list<std::string> &input_filenames, const std::string &path)
{
// Break the incoming path in its components
std::string dir = gDirUtilp->getDirName(path);
std::string name = gDirUtilp->getBaseFileName(path);
std::string exten = gDirUtilp->getExtension(path);
// std::cout << "store_output_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl;
if (dir.empty() && exten.empty())
{
// If dir and exten are empty, we interpret the name as a file extension type name and will iterate through input list to populate the output list
exten = name;
// Make sure the extension is an image type
if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID)
{
return;
}
std::string delim = gDirUtilp->getDirDelimiter();
std::list<std::string>::iterator in_file = input_filenames.begin();
std::list<std::string>::iterator end = input_filenames.end();
for (; in_file != end; ++in_file)
{
dir = gDirUtilp->getDirName(*in_file);
name = gDirUtilp->getBaseFileName(*in_file,true);
std::string file_name;
if (!dir.empty())
{
file_name = dir + delim + name + "." + exten;
}
else
{
file_name = name + "." + exten;
}
output_filenames.push_back(file_name);
}
}
else
{
// Make sure the extension is an image type
if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID)
{
return;
}
// Store the path
output_filenames.push_back(path);
}
}
// Holds the metric gathering output in a thread safe way
class LogThread : public LLThread
{
public:
std::string mFile;
LogThread(std::string& test_name) : LLThread("llimage_libtest log")
{
std::string file_name = test_name + std::string(".slp");
mFile = file_name;
}
void run()
{
std::ofstream os(mFile.c_str());
while (!sAllDone)
{
LLFastTimer::writeLog(os);
os.flush();
ms_sleep(32);
}
LLFastTimer::writeLog(os);
os.flush();
os.close();
}
};
int main(int argc, char** argv)
{
// List of input and output files
std::list<std::string> input_filenames;
std::list<std::string> output_filenames;
// Other optional parsed arguments
bool analyze_performance = false;
bool image_stats = false;
int* region = NULL;
int discard_level = -1;
int load_size = 0;
int precincts_size = -1;
int blocks_size = -1;
int levels = 0;
bool reversible = false;
std::string filter_name = "";
// Init whatever is necessary
ll_init_apr();
LLImage::initClass();
LogThread* fast_timer_log_thread = NULL; // For performance and metric gathering
// Analyze command line arguments
for (int arg = 1; arg < argc; ++arg)
{
if (!strcmp(argv[arg], "--help") || !strcmp(argv[arg], "-h"))
{
// Send the usage to standard out
std::cout << USAGE << std::endl;
return 0;
}
else if ((!strcmp(argv[arg], "--input") || !strcmp(argv[arg], "-i")) && arg < argc-1)
{
std::string file_name = argv[arg+1];
while (file_name[0] != '-') // if arg starts with '-', we consider it's not a file name but some other argument
{
// std::cout << "input file name : " << file_name << std::endl;
store_input_file(input_filenames, file_name);
arg += 1; // Skip that arg now we know it's a file name
if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
break;
file_name = argv[arg+1]; // Next argument and loop over
}
}
else if ((!strcmp(argv[arg], "--output") || !strcmp(argv[arg], "-o")) && arg < argc-1)
{
std::string file_name = argv[arg+1];
while (file_name[0] != '-') // if arg starts with '-', we consider it's not a file name but some other argument
{
// std::cout << "output file name : " << file_name << std::endl;
store_output_file(output_filenames, input_filenames, file_name);
arg += 1; // Skip that arg now we know it's a file name
if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
break;
file_name = argv[arg+1]; // Next argument and loop over
}
}
else if ((!strcmp(argv[arg], "--region") || !strcmp(argv[arg], "-r")) && arg < argc-1)
{
std::string value_str = argv[arg+1];
int index = 0;
region = new int[4];
while (value_str[0] != '-') // if arg starts with '-', it's the next option
{
int value = atoi(value_str.c_str());
region[index++] = value;
arg += 1; // Definitely skip that arg now we know it's a number
if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
break;
if (index == 4) // Break out of the loop if we captured 4 values already
break;
value_str = argv[arg+1]; // Next argument and loop over
}
if (index != 4)
{
std::cout << "--region arguments invalid" << std::endl;
delete [] region;
region = NULL;
}
}
else if (!strcmp(argv[arg], "--discard_level") || !strcmp(argv[arg], "-d"))
{
std::string value_str;
if ((arg + 1) < argc)
{
value_str = argv[arg+1];
}
if (((arg + 1) >= argc) || (value_str[0] == '-'))
{
std::cout << "No valid --discard_level argument given, discard_level ignored" << std::endl;
}
else
{
discard_level = atoi(value_str.c_str());
// Clamp to the values accepted by the viewer
discard_level = llclamp(discard_level,0,5);
}
}
else if (!strcmp(argv[arg], "--load_size") || !strcmp(argv[arg], "-load"))
{
std::string value_str;
if ((arg + 1) < argc)
{
value_str = argv[arg+1];
}
if (((arg + 1) >= argc) || (value_str[0] == '-'))
{
std::cout << "No valid --load_size argument given, load_size ignored" << std::endl;
}
else
{
load_size = atoi(value_str.c_str());
}
}
else if (!strcmp(argv[arg], "--precincts") || !strcmp(argv[arg], "-p"))
{
std::string value_str;
if ((arg + 1) < argc)
{
value_str = argv[arg+1];
}
if (((arg + 1) >= argc) || (value_str[0] == '-'))
{
std::cout << "No valid --precincts argument given, precincts ignored" << std::endl;
}
else
{
precincts_size = atoi(value_str.c_str());
}
}
else if (!strcmp(argv[arg], "--blocks") || !strcmp(argv[arg], "-b"))
{
std::string value_str;
if ((arg + 1) < argc)
{
value_str = argv[arg+1];
}
if (((arg + 1) >= argc) || (value_str[0] == '-'))
{
std::cout << "No valid --blocks argument given, blocks ignored" << std::endl;
}
else
{
blocks_size = atoi(value_str.c_str());
}
}
else if (!strcmp(argv[arg], "--levels") || !strcmp(argv[arg], "-l"))
{
std::string value_str;
if ((arg + 1) < argc)
{
value_str = argv[arg+1];
}
if (((arg + 1) >= argc) || (value_str[0] == '-'))
{
std::cout << "No valid --levels argument given, default (5) will be used" << std::endl;
}
else
{
levels = atoi(value_str.c_str());
}
}
else if (!strcmp(argv[arg], "--reversible") || !strcmp(argv[arg], "-rev"))
{
reversible = true;
}
else if (!strcmp(argv[arg], "--logmetrics") || !strcmp(argv[arg], "-log"))
{
// '--logmetrics' needs to be specified with a named test metric argument
// Note: for the moment, only ImageCompressionTester has been tested
std::string test_name;
if ((arg + 1) < argc)
{
test_name = argv[arg+1];
}
if (((arg + 1) >= argc) || (test_name[0] == '-'))
{
// We don't have an argument left in the arg list or the next argument is another option
std::cout << "No --logmetrics argument given, no perf data will be gathered" << std::endl;
}
else
{
LLFastTimer::sMetricLog = TRUE;
LLFastTimer::sLogName = test_name;
arg += 1; // Skip that arg now we know it's a valid test name
if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
break;
}
}
else if (!strcmp(argv[arg], "--filter") || !strcmp(argv[arg], "-f"))
{
// '--filter' needs to be specified with a named filter argument
if ((arg + 1) < argc)
{
filter_name = argv[arg+1];
}
if (((arg + 1) >= argc) || (filter_name[0] == '-'))
{
// We don't have an argument left in the arg list or the next argument is another option
std::cout << "No --filter argument given, no filter will be applied" << std::endl;
}
else
{
arg += 1; // Skip that arg now we know it's a valid test name
if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
break;
}
}
else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
{
analyze_performance = true;
}
else if (!strcmp(argv[arg], "--image-stats") || !strcmp(argv[arg], "-s"))
{
image_stats = true;
}
}
// Check arguments consistency. Exit with proper message if inconsistent.
if (input_filenames.size() == 0)
{
std::cout << "No input file, nothing to do -> exit" << std::endl;
return 0;
}
if (analyze_performance && !LLFastTimer::sMetricLog)
{
std::cout << "Cannot create perf report if no perf gathered (i.e. use argument -log <perf> with -a) -> exit" << std::endl;
return 0;
}
// Create the logging thread if required
if (LLFastTimer::sMetricLog)
{
LLFastTimer::sLogLock = new LLMutex(NULL);
fast_timer_log_thread = new LogThread(LLFastTimer::sLogName);
fast_timer_log_thread->start();
}
// Load the filter once and for all
LLImageFilter filter(filter_name);
// Perform action on each input file
std::list<std::string>::iterator in_file = input_filenames.begin();
std::list<std::string>::iterator out_file = output_filenames.begin();
std::list<std::string>::iterator in_end = input_filenames.end();
std::list<std::string>::iterator out_end = output_filenames.end();
for (; in_file != in_end; ++in_file, ++out_file)
{
// Load file
LLPointer<LLImageRaw> raw_image = load_image(*in_file, discard_level, region, load_size, image_stats);
if (!raw_image)
{
std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl;
continue;
}
// Apply the filter
filter.executeFilter(raw_image);
// Save file
if (out_file != out_end)
{
if (!save_image(*out_file, raw_image, blocks_size, precincts_size, levels, reversible, image_stats))
{
std::cout << "Error: Image " << *out_file << " could not be saved" << std::endl;
}
else
{
std::cout << *in_file << " -> " << *out_file << std::endl;
}
}
}
// Output perf data if requested by user
if (analyze_performance)
{
std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
std::string current_name = LLFastTimer::sLogName + ".slp";
std::string report_name = LLFastTimer::sLogName + "_report.csv";
std::cout << "Analyzing performance, check report in : " << report_name << std::endl;
LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline_name, current_name, report_name);
}
// Stop the perf gathering system if needed
if (LLFastTimer::sMetricLog)
{
LLMetricPerformanceTesterBasic::deleteTester(LLFastTimer::sLogName);
sAllDone = true;
}
// Cleanup and exit
SUBSYSTEM_CLEANUP(LLImage);
if (fast_timer_log_thread)
{
fast_timer_log_thread->shutdown();
}
return 0;
}
@@ -0,0 +1,29 @@
/**
* @file llimage_libtest.h
*
* $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$
*/
#ifndef LLIMAGE_LIBTEST_H
#define LLIMAGE_LIBTEST_H
#endif
@@ -0,0 +1,81 @@
# -*- cmake -*-
# Only set this up for viewer builds, because the llui library is most closely
# related to the viewer
if (VIEWER)
project (llui_libtest)
include(00-Common)
include(LLCommon)
include(LLImage)
include(LLImageJ2COJ) # ugh, needed for images
include(LLKDU)
include(LLMath)
include(LLMessage)
include(LLRender)
include(LLWindow)
include(LLUI)
include(LLFileSystem)
include(LLXML)
include(Hunspell)
include(Linking)
# include(Tut)
set(llui_libtest_SOURCE_FILES
llui_libtest.cpp
llwidgetreg.cpp
)
set(llui_libtest_HEADER_FILES
CMakeLists.txt
llui_libtest.h
llwidgetreg.h
)
list(APPEND llui_libtest_SOURCE_FILES ${llui_libtest_HEADER_FILES})
add_executable(llui_libtest ${llui_libtest_SOURCE_FILES})
# Libraries on which this library depends, needed for Linux builds
# Sort by high-level to low-level
target_link_libraries(llui_libtest
llui
llinventory
llmessage
llrender
llimage
llkdu
llimagej2coj
)
if (WINDOWS)
set_target_properties(llui_libtest
PROPERTIES
LINK_FLAGS "/NODEFAULTLIB:LIBCMT"
)
# Copy over OpenJPEG.dll
# *NOTE: On Windows with VS2005, only the first comment prints
set(OPENJPEG_RELEASE
"${ARCH_PREBUILT_DIRS_RELEASE}/openjp2.dll")
add_custom_command( TARGET llui_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${OPENJPEG_RELEASE} ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Copying OpenJPEG DLLs to binary directory"
)
set(OPENJPEG_DEBUG
"${ARCH_PREBUILT_DIRS_DEBUG}/openjp2.dll")
add_custom_command( TARGET llui_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${OPENJPEG_DEBUG} ${CMAKE_CURRENT_BINARY_DIR}
)
endif (WINDOWS)
# Ensure people working on the viewer don't break this library
# *NOTE: This could be removed, or only built by Parabuild, if the build
# and link times become too long. JC
add_dependencies(viewer llui_libtest)
endif (VIEWER)
@@ -0,0 +1,229 @@
/**
* @file llui_libtest.cpp
* @brief Integration test for the LLUI library
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llui_libtest.h"
// project includes
#include "llwidgetreg.h"
// linden library includes
#include "llcontrol.h" // LLControlGroup
#include "lldir.h"
#include "lldiriterator.h"
#include "llerrorcontrol.h"
#include "llfloater.h"
#include "llfontfreetype.h"
#include "llfontgl.h"
#include "lltransutil.h"
#include "llui.h"
#include "lluictrlfactory.h"
#include <iostream>
// *TODO: switch to using TUT
// *TODO: teach Parabuild about this program, run automatically after full builds
// I believe these must be globals, not stack variables. JC
LLControlGroup gSavedSettings("Global"); // saved at end of session
LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session
LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warnings
// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
#include "llavatarname.h"
// Stub for rlvGetAnonym
std::string rlvGetAnonym(const LLAvatarName& avName)
{
static std::string strAnonym = "A resident";
return strAnonym;
}
// [/RLVa:KB]
// We can't create LLImageGL objects because we have no window or rendering
// context. Provide enough of an LLUIImage to test the LLUI library without
// an underlying image.
class TestUIImage : public LLUIImage
{
public:
TestUIImage()
: LLUIImage( std::string(), NULL ) // NULL ImageGL, don't deref!
{ }
/*virtual*/ S32 getWidth() const
{
return 16;
}
/*virtual*/ S32 getHeight() const
{
return 16;
}
};
class LLTexture ;
// We need to supply dummy images
class TestImageProvider : public LLImageProviderInterface
{
public:
/*virtual*/ LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority)
{
return makeImage();
}
/*virtual*/ LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority)
{
return makeImage();
}
/*virtual*/ void cleanUp()
{
}
LLPointer<LLUIImage> makeImage()
{
LLPointer<LLTexture> image_gl;
LLPointer<LLUIImage> image = new TestUIImage(); //LLUIImage( std::string(), image_gl);
mImageList.push_back(image);
return image;
}
public:
// Unclear if we need this, hold on to one copy of each image we make
std::vector<LLPointer<LLUIImage> > mImageList;
};
TestImageProvider gTestImageProvider;
void init_llui()
{
// Font lookup needs directory support
#if LL_DARWIN
const char* newview_path = "../../../../newview";
#else
const char* newview_path = "../../../newview";
#endif
gDirUtilp->initAppDirs("SecondLife", newview_path);
gDirUtilp->setSkinFolder("default", "en");
// colors are no longer stored in a LLControlGroup file
LLUIColorTable::instance().loadFromSettings();
std::string config_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings.xml");
gSavedSettings.loadFromFile(config_filename);
// See LLAppViewer::init()
LLUI::settings_map_t settings;
settings["config"] = &gSavedSettings;
settings["ignores"] = &gWarningSettings;
settings["floater"] = &gSavedSettings;
settings["account"] = &gSavedPerAccountSettings;
// Don't use real images as we don't have a GL context
LLUI::initClass(settings, &gTestImageProvider);
const bool no_register_widgets = false;
LLWidgetReg::initClass( no_register_widgets );
// Otherwise we get translation warnings when setting up floaters
// (tooltips for buttons)
std::set<std::string> default_args;
LLTransUtil::parseStrings("strings.xml", default_args);
LLTransUtil::parseLanguageStrings("language_settings.xml");
LLFontManager::initClass();
// Creating widgets apparently requires fonts to be initialized,
// otherwise it crashes.
LLFontGL::initClass(96.f, 1.f, 1.f,
gDirUtilp->getAppRODataDir(),
"fonts.xml",
f.0,
false ); // don't create gl textures
LLFloaterView::Params fvparams;
fvparams.name("Floater View");
fvparams.rect( LLRect(0,480,640,0) );
fvparams.mouse_opaque(false);
fvparams.follows.flags(FOLLOWS_ALL);
fvparams.tab_stop(false);
gFloaterView = LLUICtrlFactory::create<LLFloaterView> (fvparams);
}
/*==========================================================================*|
static std::string get_xui_dir()
{
std::string delim = gDirUtilp->getDirDelimiter();
return gDirUtilp->getSkinBaseDir() + delim + "default" + delim + "xui" + delim;
}
// buildFromFile() no longer supports generate-output-LLXMLNode
void export_test_floaters()
{
// Convert all test floaters to new XML format
std::string delim = gDirUtilp->getDirDelimiter();
std::string xui_dir = get_xui_dir() + "en" + delim;
std::string filename;
LLDirIterator iter(xui_dir, "floater_test_*.xml");
while (iter.next(filename))
{
if (filename.find("_new.xml") != std::string::npos)
{
// don't re-export other test floaters
continue;
}
LL_INFOS() << "Converting " << filename << LL_ENDL;
// Build a floater and output new attributes
LLXMLNodePtr output_node = new LLXMLNode();
LLFloater* floater = new LLFloater(LLSD());
floater->buildFromFile( filename,
// FALSE, // don't open floater
output_node);
std::string out_filename = gDirUtilp->add(xui_dir, filename);
std::string::size_type extension_pos = out_filename.rfind(".xml");
out_filename.resize(extension_pos);
out_filename += "_new.xml";
LL_INFOS() << "Output: " << out_filename << LL_ENDL;
LLFILE* floater_file = LLFile::fopen(out_filename.c_str(), "w");
LLXMLNode::writeHeaderToFile(floater_file);
output_node->writeToFile(floater_file);
fclose(floater_file);
}
}
|*==========================================================================*/
int main(int argc, char** argv)
{
// Must init LLError for llerrs to actually cause errors.
LLError::initForApplication(".");
init_llui();
// export_test_floaters();
return 0;
}
@@ -0,0 +1,30 @@
/**
* @file llui_libtest.h
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LLUI_LIBTEST_H
#define LLUI_LIBTEST_H
// TODO
#endif
@@ -0,0 +1,107 @@
/**
* @file llwidgetreg.cpp
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llwidgetreg.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "llcontainerview.h"
#include "lliconctrl.h"
#include "llloadingindicator.h"
#include "llmenubutton.h"
#include "llmenugl.h"
#include "llmultislider.h"
#include "llmultisliderctrl.h"
#include "llprogressbar.h"
#include "llradiogroup.h"
#include "llsearcheditor.h"
#include "llscrollcontainer.h"
#include "llscrollingpanellist.h"
#include "llscrolllistctrl.h"
#include "llslider.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
#include "llstatview.h"
#include "lltabcontainer.h"
#include "lltextbox.h"
#include "lltexteditor.h"
#include "lltimectrl.h"
#include "llflyoutbutton.h"
#include "llfiltereditor.h"
#include "lllayoutstack.h"
void LLWidgetReg::initClass(bool register_widgets)
{
// Only need to register if the Windows linker has optimized away the
// references to the object files.
if (register_widgets)
{
LLDefaultChildRegistry::Register<LLButton> button("button");
LLDefaultChildRegistry::Register<LLMenuButton> menu_button("menu_button");
LLDefaultChildRegistry::Register<LLCheckBoxCtrl> check_box("check_box");
LLDefaultChildRegistry::Register<LLComboBox> combo_box("combo_box");
LLDefaultChildRegistry::Register<LLFilterEditor> filter_editor("filter_editor");
LLDefaultChildRegistry::Register<LLFlyoutButton> flyout_button("flyout_button");
LLDefaultChildRegistry::Register<LLContainerView> container_view("container_view");
LLDefaultChildRegistry::Register<LLIconCtrl> icon("icon");
LLDefaultChildRegistry::Register<LLLoadingIndicator> loading_indicator("loading_indicator");
LLDefaultChildRegistry::Register<LLLineEditor> line_editor("line_editor");
LLDefaultChildRegistry::Register<LLMenuItemSeparatorGL> menu_item_separator("menu_item_separator");
LLDefaultChildRegistry::Register<LLMenuItemCallGL> menu_item_call_gl("menu_item_call");
LLDefaultChildRegistry::Register<LLMenuItemCheckGL> menu_item_check_gl("menu_item_check");
LLDefaultChildRegistry::Register<LLMenuGL> menu("menu");
LLDefaultChildRegistry::Register<LLMenuBarGL> menu_bar("menu_bar");
LLDefaultChildRegistry::Register<LLContextMenu> context_menu("context_menu");
LLDefaultChildRegistry::Register<LLMultiSlider> multi_slider_bar("multi_slider_bar");
LLDefaultChildRegistry::Register<LLMultiSliderCtrl> multi_slider("multi_slider");
LLDefaultChildRegistry::Register<LLPanel> panel("panel", &LLPanel::fromXML);
LLDefaultChildRegistry::Register<LLLayoutStack> layout_stack("layout_stack");
LLDefaultChildRegistry::Register<LLProgressBar> progress_bar("progress_bar");
LLDefaultChildRegistry::Register<LLRadioGroup> radio_group("radio_group");
LLDefaultChildRegistry::Register<LLSearchEditor> search_editor("search_editor");
LLDefaultChildRegistry::Register<LLScrollContainer> scroll_container("scroll_container");
LLDefaultChildRegistry::Register<LLScrollingPanelList> scrolling_panel_list("scrolling_panel_list");
LLDefaultChildRegistry::Register<LLScrollListCtrl> scroll_list("scroll_list");
LLDefaultChildRegistry::Register<LLSlider> slider_bar("slider_bar");
LLDefaultChildRegistry::Register<LLSliderCtrl> slider("slider");
LLDefaultChildRegistry::Register<LLSpinCtrl> spinner("spinner");
LLDefaultChildRegistry::Register<LLStatBar> stat_bar("stat_bar");
//LLDefaultChildRegistry::Register<LLPlaceHolderPanel> placeholder("placeholder");
LLDefaultChildRegistry::Register<LLTabContainer> tab_container("tab_container");
LLDefaultChildRegistry::Register<LLTextBox> text("text");
LLDefaultChildRegistry::Register<LLTimeCtrl> time("time");
LLDefaultChildRegistry::Register<LLTextEditor> simple_text_editor("simple_text_editor");
LLDefaultChildRegistry::Register<LLUICtrl> ui_ctrl("ui_ctrl");
LLDefaultChildRegistry::Register<LLStatView> stat_view("stat_view");
//LLDefaultChildRegistry::Register<LLUICtrlLocate> locate("locate");
//LLDefaultChildRegistry::Register<LLUICtrlLocate> pad("pad");
LLDefaultChildRegistry::Register<LLViewBorder> view_border("view_border");
}
// *HACK: Usually this is registered as a viewer text editor
LLDefaultChildRegistry::Register<LLTextEditor> text_editor("text_editor");
}
@@ -0,0 +1,37 @@
/**
* @file llwidgetreg.h
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LLWIDGETREG_H
#define LLWIDGETREG_H
// Register all widgets with the builder registry.
// Useful on Windows where linker discards all references to the
// static LLDefaultChildRegistry::Register<> calls.
class LLWidgetReg
{
public:
static void initClass(bool register_widgets);
};
#endif
+25
View File
@@ -0,0 +1,25 @@
"""\
@file __init__.py
@brief Initialization file for the indra module.
$LicenseInfo:firstyear=2006&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2006-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$
"""
+27
View File
@@ -0,0 +1,27 @@
"""\
@file __init__.py
@brief Initialization file for the indra ipc module.
$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$
"""
+123
View File
@@ -0,0 +1,123 @@
"""\
@file compatibility.py
@brief Classes that manage compatibility states.
$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$
"""
"""Compatibility combination table:
I M O N S
-- -- -- -- --
I: I I I I I
M: I M M M M
O: I M O M O
N: I M M N N
S: I M O N S
"""
class _Compatibility(object):
def __init__(self, reason):
self.reasons = [ ]
if reason:
self.reasons.append(reason)
def combine(self, other):
if self._level() <= other._level():
return self._buildclone(other)
else:
return other._buildclone(self)
def prefix(self, leadin):
self.reasons = [ leadin + r for r in self.reasons ]
def same(self): return self._level() >= 1
def deployable(self): return self._level() > 0
def resolved(self): return self._level() > -1
def compatible(self): return self._level() > -2
def explain(self):
return self.__class__.__name__ + "\n" + "\n".join(self.reasons) + "\n"
def _buildclone(self, other=None):
c = self._buildinstance()
c.reasons = self.reasons
if other:
c.reasons = c.reasons + other.reasons
return c
def _buildinstance(self):
return self.__class__(None)
# def _level(self):
# raise RuntimeError('implement in subclass')
class Incompatible(_Compatibility):
def _level(self):
return -2
class Mixed(_Compatibility):
def __init__(self, *inputs):
_Compatibility.__init__(self, None)
for i in inputs:
self.reasons += i.reasons
def _buildinstance(self):
return self.__class__()
def _level(self):
return -1
class _Aged(_Compatibility):
def combine(self, other):
if self._level() == other._level():
return self._buildclone(other)
if int(self._level()) == int(other._level()):
return Mixed(self, other)
return _Compatibility.combine(self, other)
class Older(_Aged):
def _level(self):
return -0.25
class Newer(_Aged):
def _level(self):
return 0.25
class Same(_Compatibility):
def __init__(self):
_Compatibility.__init__(self, None)
def _buildinstance(self):
return self.__class__()
def _level(self):
return 1
+372
View File
@@ -0,0 +1,372 @@
"""\
@file llmessage.py
@brief Message template parsing and compatiblity
$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 .compatibility import Incompatible, Older, Newer, Same
from .tokenstream import TokenStream
###
### Message Template
###
class Template:
def __init__(self):
self.messages = { }
def addMessage(self, m):
self.messages[m.name] = m
def compatibleWithBase(self, base):
messagenames = (
frozenset(list(self.messages.keys()))
| frozenset(list(base.messages.keys()))
)
compatibility = Same()
for name in messagenames:
selfmessage = self.messages.get(name, None)
basemessage = base.messages.get(name, None)
if not selfmessage:
c = Older("missing message %s, did you mean to deprecate?" % name)
elif not basemessage:
c = Newer("added message %s" % name)
else:
c = selfmessage.compatibleWithBase(basemessage)
c.prefix("in message %s: " % name)
compatibility = compatibility.combine(c)
return compatibility
class Message:
HIGH = "High"
MEDIUM = "Medium"
LOW = "Low"
FIXED = "Fixed"
priorities = [ HIGH, MEDIUM, LOW, FIXED ]
prioritieswithnumber = [ FIXED ]
TRUSTED = "Trusted"
NOTTRUSTED = "NotTrusted"
trusts = [ TRUSTED, NOTTRUSTED ]
UNENCODED = "Unencoded"
ZEROCODED = "Zerocoded"
encodings = [ UNENCODED, ZEROCODED ]
NOTDEPRECATED = "NotDeprecated"
DEPRECATED = "Deprecated"
UDPDEPRECATED = "UDPDeprecated"
UDPBLACKLISTED = "UDPBlackListed"
deprecations = [ NOTDEPRECATED, UDPDEPRECATED, UDPBLACKLISTED, DEPRECATED ]
# in order of increasing deprecation
def __init__(self, name, number, priority, trust, coding):
self.name = name
self.number = number
self.priority = priority
self.trust = trust
self.coding = coding
self.deprecateLevel = 0
self.blocks = [ ]
def deprecated(self):
return self.deprecateLevel != 0
def deprecate(self, deprecation):
self.deprecateLevel = self.deprecations.index(deprecation)
def addBlock(self, block):
self.blocks.append(block)
def compatibleWithBase(self, base):
if self.name != base.name:
# this should never happen in real life because of the
# way Template matches up messages by name
return Incompatible("has different name: %s vs. %s in base"
% (self.name, base.name))
if self.priority != base.priority:
return Incompatible("has different priority: %s vs. %s in base"
% (self.priority, base.priority))
if self.trust != base.trust:
return Incompatible("has different trust: %s vs. %s in base"
% (self.trust, base.trust))
if self.coding != base.coding:
return Incompatible("has different coding: %s vs. %s in base"
% (self.coding, base.coding))
if self.number != base.number:
return Incompatible("has different number: %s vs. %s in base"
% (self.number, base.number))
compatibility = Same()
if self.deprecateLevel != base.deprecateLevel:
if self.deprecateLevel < base.deprecateLevel:
c = Older("is less deprecated: %s vs. %s in base" % (
self.deprecations[self.deprecateLevel],
self.deprecations[base.deprecateLevel]))
else:
c = Newer("is more deprecated: %s vs. %s in base" % (
self.deprecations[self.deprecateLevel],
self.deprecations[base.deprecateLevel]))
compatibility = compatibility.combine(c)
selflen = len(self.blocks)
baselen = len(base.blocks)
samelen = min(selflen, baselen)
for i in range(0, samelen):
selfblock = self.blocks[i]
baseblock = base.blocks[i]
c = selfblock.compatibleWithBase(baseblock)
if not c.same():
c = Incompatible("block %d isn't identical" % i)
compatibility = compatibility.combine(c)
if selflen > baselen:
c = Newer("has %d extra blocks" % (selflen - baselen))
elif selflen < baselen:
c = Older("missing %d extra blocks" % (baselen - selflen))
else:
c = Same()
compatibility = compatibility.combine(c)
return compatibility
class Block(object):
SINGLE = "Single"
MULTIPLE = "Multiple"
VARIABLE = "Variable"
repeats = [ SINGLE, MULTIPLE, VARIABLE ]
repeatswithcount = [ MULTIPLE ]
def __init__(self, name, repeat, count=None):
self.name = name
self.repeat = repeat
self.count = count
self.variables = [ ]
def addVariable(self, variable):
self.variables.append(variable)
def compatibleWithBase(self, base):
if self.name != base.name:
return Incompatible("has different name: %s vs. %s in base"
% (self.name, base.name))
if self.repeat != base.repeat:
return Incompatible("has different repeat: %s vs. %s in base"
% (self.repeat, base.repeat))
if self.repeat in Block.repeatswithcount:
if self.count != base.count:
return Incompatible("has different count: %s vs. %s in base"
% (self.count, base.count))
compatibility = Same()
selflen = len(self.variables)
baselen = len(base.variables)
for i in range(0, min(selflen, baselen)):
selfvar = self.variables[i]
basevar = base.variables[i]
c = selfvar.compatibleWithBase(basevar)
if not c.same():
c = Incompatible("variable %d isn't identical" % i)
compatibility = compatibility.combine(c)
if selflen > baselen:
c = Newer("has %d extra variables" % (selflen - baselen))
elif selflen < baselen:
c = Older("missing %d extra variables" % (baselen - selflen))
else:
c = Same()
compatibility = compatibility.combine(c)
return compatibility
class Variable:
U8 = "U8"; U16 = "U16"; U32 = "U32"; U64 = "U64"
S8 = "S8"; S16 = "S16"; S32 = "S32"; S64 = "S64"
F32 = "F32"; F64 = "F64"
LLVECTOR3 = "LLVector3"; LLVECTOR3D = "LLVector3d"; LLVECTOR4 = "LLVector4"
LLQUATERNION = "LLQuaternion"
LLUUID = "LLUUID"
BOOL = "BOOL"
IPADDR = "IPADDR"; IPPORT = "IPPORT"
FIXED = "Fixed"
VARIABLE = "Variable"
types = [ U8, U16, U32, U64, S8, S16, S32, S64, F32, F64,
LLVECTOR3, LLVECTOR3D, LLVECTOR4, LLQUATERNION,
LLUUID, BOOL, IPADDR, IPPORT, FIXED, VARIABLE ]
typeswithsize = [ FIXED, VARIABLE ]
def __init__(self, name, type, size):
self.name = name
self.type = type
self.size = size
def compatibleWithBase(self, base):
if self.name != base.name:
return Incompatible("has different name: %s vs. %s in base"
% (self.name, base.name))
if self.type != base.type:
return Incompatible("has different type: %s vs. %s in base"
% (self.type, base.type))
if self.type in Variable.typeswithsize:
if self.size != base.size:
return Incompatible("has different size: %s vs. %s in base"
% (self.size, base.size))
return Same()
###
### Parsing Message Templates
###
class TemplateParser:
def __init__(self, tokens):
self._tokens = tokens
self._version = 0
self._numbers = { }
for p in Message.priorities:
self._numbers[p] = 0
def parseTemplate(self):
tokens = self._tokens
t = Template()
while True:
if tokens.want("version"):
v = float(tokens.require(tokens.wantFloat()))
self._version = v
t.version = v
continue
m = self.parseMessage()
if m:
t.addMessage(m)
continue
if self._version >= 2.0:
tokens.require(tokens.wantEOF())
break
else:
if tokens.wantEOF():
break
tokens.consume()
# just assume (gulp) that this is a comment
# line 468: "sim -> dataserver"
return t
def parseMessage(self):
tokens = self._tokens
if not tokens.want("{"):
return None
name = tokens.require(tokens.wantSymbol())
priority = tokens.require(tokens.wantOneOf(Message.priorities))
if self._version >= 2.0 or priority in Message.prioritieswithnumber:
number = int("+" + tokens.require(tokens.wantInteger()), 0)
else:
self._numbers[priority] += 1
number = self._numbers[priority]
trust = tokens.require(tokens.wantOneOf(Message.trusts))
coding = tokens.require(tokens.wantOneOf(Message.encodings))
m = Message(name, number, priority, trust, coding)
if self._version >= 2.0:
d = tokens.wantOneOf(Message.deprecations)
if d:
m.deprecate(d)
while True:
b = self.parseBlock()
if not b:
break
m.addBlock(b)
tokens.require(tokens.want("}"))
return m
def parseBlock(self):
tokens = self._tokens
if not tokens.want("{"):
return None
name = tokens.require(tokens.wantSymbol())
repeat = tokens.require(tokens.wantOneOf(Block.repeats))
if repeat in Block.repeatswithcount:
count = int(tokens.require(tokens.wantInteger()))
else:
count = None
b = Block(name, repeat, count)
while True:
v = self.parseVariable()
if not v:
break
b.addVariable(v)
tokens.require(tokens.want("}"))
return b
def parseVariable(self):
tokens = self._tokens
if not tokens.want("{"):
return None
name = tokens.require(tokens.wantSymbol())
type = tokens.require(tokens.wantOneOf(Variable.types))
if type in Variable.typeswithsize:
size = tokens.require(tokens.wantInteger())
else:
tokens.wantInteger() # in LandStatRequest: "{ ParcelLocalID S32 1 }"
size = None
tokens.require(tokens.want("}"))
return Variable(name, type, size)
def parseTemplateString(s):
return TemplateParser(TokenStream().fromString(s)).parseTemplate()
def parseTemplateFile(f):
return TemplateParser(TokenStream().fromFile(f)).parseTemplate()
+154
View File
@@ -0,0 +1,154 @@
"""\
@file tokenstream.py
@brief Message template parsing utility class
$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 re
class _EOF(object):
pass
EOF = _EOF()
class _LineMarker(int):
pass
_commentRE = re.compile(r'//.*')
_symbolRE = re.compile(r'[a-zA-Z_][a-zA-Z_0-9]*')
_integerRE = re.compile(r'(0x[0-9A-Fa-f]+|0\d*|[1-9]\d*)')
_floatRE = re.compile(r'\d+(\.\d*)?')
class ParseError(Exception):
def __init__(self, stream, reason):
self.line = stream.line
self.context = stream._context()
self.reason = reason
def _contextString(self):
c = [ ]
for t in self.context:
if isinstance(t, _LineMarker):
break
c.append(t)
return " ".join(c)
def __str__(self):
return "line %d: %s @ ... %s" % (
self.line, self.reason, self._contextString())
def __bool__(self):
return False
def _optionText(options):
n = len(options)
if n == 1:
return '"%s"' % options[0]
return '"' + '", "'.join(options[0:(n-1)]) + '" or "' + options[-1] + '"'
class TokenStream(object):
def __init__(self):
self.line = 0
self.tokens = [ ]
def fromString(self, string):
return self.fromLines(string.split('\n'))
def fromFile(self, file):
return self.fromLines(file)
def fromLines(self, lines):
i = 0
for line in lines:
i += 1
self.tokens.append(_LineMarker(i))
self.tokens.extend(_commentRE.sub(" ", line).split())
self._consumeLines()
return self
def consume(self):
if not self.tokens:
return EOF
t = self.tokens.pop(0)
self._consumeLines()
return t
def _consumeLines(self):
while self.tokens and isinstance(self.tokens[0], _LineMarker):
self.line = self.tokens.pop(0)
def peek(self):
if not self.tokens:
return EOF
return self.tokens[0]
def want(self, t):
if t == self.peek():
return self.consume()
return ParseError(self, 'expected "%s"' % t)
def wantOneOf(self, options):
assert len(options)
if self.peek() in options:
return self.consume()
return ParseError(self, 'expected one of %s' % _optionText(options))
def wantEOF(self):
return self.want(EOF)
def wantRE(self, re, message=None):
t = self.peek()
if t != EOF:
m = re.match(t)
if m and m.end() == len(t):
return self.consume()
if not message:
message = "expected match for r'%s'" % re.pattern
return ParseError(self, message)
def wantSymbol(self):
return self.wantRE(_symbolRE, "expected symbol")
def wantInteger(self):
return self.wantRE(_integerRE, "expected integer")
def wantFloat(self):
return self.wantRE(_floatRE, "expected float")
def _context(self):
n = min(5, len(self.tokens))
return self.tokens[0:n]
def require(self, t):
if t:
return t
if isinstance(t, ParseError):
raise t
else:
raise ParseError(self, "unmet requirement")
+27
View File
@@ -0,0 +1,27 @@
"""\
@file __init__.py
@brief Initialization file for the indra util module.
$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$
"""
+969
View File
@@ -0,0 +1,969 @@
"""\
@file llmanifest.py
@author Ryan Williams
@brief Library for specifying operations on a set of files.
$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 collections import namedtuple, defaultdict
import subprocess
import errno
import filecmp
import fnmatch
import getopt
import glob
import itertools
import operator
import os
import re
import shlex
import shutil
import subprocess
import sys
import tarfile
class ManifestError(RuntimeError):
"""Use an exception more specific than generic Python RuntimeError"""
def __init__(self, msg):
self.msg = msg
super(ManifestError, self).__init__(self.msg)
class MissingError(ManifestError):
"""You specified a file that doesn't exist"""
def __init__(self, msg):
self.msg = msg
super(MissingError, self).__init__(self.msg)
def path_ancestors(path):
drive, path = os.path.splitdrive(os.path.normpath(path))
result = []
while len(path) > 0 and path != os.path.sep:
result.append(drive+path)
path, sub = os.path.split(path)
return result
def proper_windows_path(path, current_platform = sys.platform):
""" This function takes an absolute Windows or Cygwin path and
returns a path appropriately formatted for the platform it's
running on (as determined by sys.platform)"""
path = path.strip()
drive_letter = None
rel = None
match = re.match("/cygdrive/([a-z])/(.*)", path)
if not match:
# <FS:Beq> Use raw strings to avoid python 3.6 complaints
# match = re.match('([a-zA-Z]):\\\(.*)', path)
match = re.match(r'([a-zA-Z]):\\(.*)', path)
# </FS:Beq>
if not match:
return None # not an absolute path
drive_letter = match.group(1)
rel = match.group(2)
if current_platform == "cygwin":
return "/cygdrive/" + drive_letter.lower() + '/' + rel.replace('\\', '/')
else:
return drive_letter.upper() + ':\\' + rel.replace('/', '\\')
def get_default_platform(dummy):
return {'linux':'linux',
'cygwin':'windows',
'win32':'windows',
'darwin':'darwin'
}[sys.platform]
DEFAULT_SRCTREE = os.path.dirname(sys.argv[0])
CHANNEL_VENDOR_BASE = 'Firestorm'
RELEASE_CHANNEL = CHANNEL_VENDOR_BASE + ' Development'
BASE_ARGUMENTS=[
dict(name='actions',
description="""This argument specifies the actions that are to be taken when the
script is run. The meaningful actions are currently:
copy - copies the files specified by the manifest into the
destination directory.
package - bundles up the files in the destination directory into
an installer for the current platform
unpacked - bundles up the files in the destination directory into
a simple tarball
Example use: %(name)s --actions="copy unpacked" """,
default="copy package"),
dict(name='arch',
description="""This argument is appended to the platform string for
determining which manifest class to run.
Example use: %(name)s --arch=i686
On Linux this would try to use Linux_i686Manifest.""",
default=""),
dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE),
dict(name='buildtype', description='Build type (i.e. Debug, Release, RelWithDebInfo).', default=None),
dict(name='bundleid',
description="""The macOS Bundle identifier.""",
default="com.secondlife.indra.viewer"),
dict(name='channel',
description="""The channel to use for updates, packaging, settings name, etc.""",
default='CHANNEL UNSET'),
dict(name='channel_suffix',
description="""Addition to the channel for packaging and channel value,
but not application name (used internally)""",
default=None),
dict(name='configuration',
description="""The build configurations sub directory used.""",
default="Release"),
dict(name='dest', description='Destination directory.', default=DEFAULT_SRCTREE),
dict(name='grid',
description="""Which grid the client will try to connect to.""",
default=None),
dict(name='installer_name',
description=""" The name of the file that the installer should be
packaged up into. Only used on Linux at the moment.""",
default=None),
dict(name='login_url',
description="""The url that the login screen displays in the client.""",
default=None),
dict(name='platform',
description="""The current platform, to be used for looking up which
manifest class to run.""",
default=get_default_platform),
dict(name='signature',
description="""This specifies an identity to sign the viewer with, if any.
If no value is supplied, the default signature will be used, if any. Currently
only used on macOS.""",
default=None),
dict(name='source',
description='Source directory.',
default=DEFAULT_SRCTREE),
dict(name='touch',
description="""File to touch when action is finished. Touch file will
contain the name of the final package in a form suitable
for use by a .bat file.""",
default=None),
dict(name='versionfile',
description="""The name of a file containing the full version number."""),
dict(name='viewer_flavor',
description='Type of viewer build. Can be oss or hvk.', default="oss"),
]
def usage(arguments, srctree=""):
nd = {'name':sys.argv[0]}
print("""Usage:
%(name)s [options] [destdir]
Options:
""" % nd)
for arg in arguments:
default = arg['default']
if hasattr(default, '__call__'):
default = "(computed value) \"" + str(default(srctree)) + '"'
elif default is not None:
default = '"' + default + '"'
print("\t--%s Default: %s\n\t%s\n" % (
arg['name'],
default,
arg['description'] % nd))
def main(extra=[]):
## print ' '.join((("'%s'" % item) if ' ' in item else item)
## for item in itertools.chain([sys.executable], sys.argv))
# Supplement our default command-line switches with any desired by
# application-specific caller.
arguments = list(itertools.chain(BASE_ARGUMENTS, extra))
# Alphabetize them by option name in case we display usage.
arguments.sort(key=operator.itemgetter('name'))
option_names = [arg['name'] + '=' for arg in arguments]
option_names.append('help')
options, remainder = getopt.getopt(sys.argv[1:], "", option_names)
# convert options to a hash
args = {'source': DEFAULT_SRCTREE,
'artwork': DEFAULT_SRCTREE,
'build': DEFAULT_SRCTREE,
'dest': DEFAULT_SRCTREE }
for opt in options:
args[opt[0].replace("--", "")] = opt[1]
for k in 'artwork build dest source'.split():
args[k] = os.path.normpath(args[k])
print("Source tree:", args['source'])
print("Artwork tree:", args['artwork'])
print("Build tree:", args['build'])
print("Destination tree:", args['dest'])
# early out for help
if 'help' in args:
# *TODO: it is a huge hack to pass around the srctree like this
usage(arguments, srctree=args['source'])
return
# defaults
for arg in arguments:
if arg['name'] not in args:
default = arg['default']
if hasattr(default, '__call__'):
default = default(args['source'])
if default is not None:
args[arg['name']] = default
# fix up version
if isinstance(args.get('versionfile'), str):
try: # read in the version string
vf = open(args['versionfile'], 'r')
args['version'] = vf.read().strip().split('.')
except:
print("Unable to read versionfile '%s'" % args['versionfile'])
# <FS:ND> This will break copy_w_viewer_manifest on Windows 32 and 64 bit builds, the versionfile will not create until the firestorm project.
# As copy_w_viewer_manifest does not seem to need the version attribute, we supress the exception for now.
# raise
# unspecified, default, and agni are default
if args['grid'] in ['', 'default', 'agni']:
args['grid'] = None
if 'actions' in args:
args['actions'] = args['actions'].split()
# debugging
for opt in args:
print("Option:", opt, "=", args[opt])
# pass in sourceid as an argument now instead of an environment variable
args['sourceid'] = os.environ.get("sourceid", "")
# Build base package.
touch = args.get('touch')
if touch:
print('================ Creating base package')
else:
print('================ Starting base copy')
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
wm.do(*args['actions'])
# Store package file for later if making touched file.
base_package_file = ""
if touch:
print('================ Created base package ', wm.package_file)
base_package_file = "" + wm.package_file
else:
print('================ Finished base copy')
# handle multiple packages if set
# ''.split() produces empty list
additional_packages = os.environ.get("additional_packages", "").split()
if additional_packages:
# Determine destination prefix / suffix for additional packages.
base_dest_parts = list(os.path.split(args['dest']))
base_dest_parts.insert(-1, "{}")
base_dest_template = os.path.join(*base_dest_parts)
# Determine touched prefix / suffix for additional packages.
if touch:
base_touch_parts = list(os.path.split(touch))
# Because of the special insert() logic below, we don't just want
# [dirpath, basename]; we want [dirpath, directory, basename].
# Further split the dirpath and replace it in the list.
base_touch_parts[0:1] = os.path.split(base_touch_parts[0])
if "arwin" in args['platform']:
base_touch_parts.insert(-1, "{}")
else:
base_touch_parts.insert(-2, "{}")
base_touch_template = os.path.join(*base_touch_parts)
for package_id in additional_packages:
args['channel_suffix'] = os.environ.get(package_id + "_viewer_channel_suffix")
args['sourceid'] = os.environ.get(package_id + "_sourceid")
args['dest'] = base_dest_template.format(package_id)
if touch:
print('================ Creating additional package for "', package_id, '" in ', args['dest'])
else:
print('================ Starting additional copy for "', package_id, '" in ', args['dest'])
try:
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
wm.do(*args['actions'])
except Exception as err:
sys.exit(str(err))
if touch:
print('================ Created additional package ', wm.package_file, ' for ', package_id)
with open(base_touch_template.format(package_id), 'w') as fp:
fp.write('set package_file=%s\n' % wm.package_file)
else:
print('================ Finished additional copy "', package_id, '" in ', args['dest'])
# Write out the package file in this format, so that it can easily be called
# and used in a .bat file - yeah, it sucks, but this is the simplest...
if touch:
with open(touch, 'w') as fp:
fp.write('set package_file=%s\n' % base_package_file)
print('touched', touch)
return 0
class LLManifestRegistry(type):
def __init__(cls, name, bases, dct):
super(LLManifestRegistry, cls).__init__(name, bases, dct)
match = re.match(r"(\w+)Manifest", name) # <FS:Beq/> fix up for python 3.6 string behaviour
if match:
cls.manifests[match.group(1).lower()] = cls
MissingFile = namedtuple("MissingFile", ("pattern", "tried"))
class LLManifest(object, metaclass=LLManifestRegistry):
manifests = {}
def for_platform(self, platform, arch = None):
if arch:
platform = platform + '_' + arch + '_'
return self.manifests[platform.lower()]
for_platform = classmethod(for_platform)
def __init__(self, args):
super(LLManifest, self).__init__()
self.args = args
self.file_list = []
self.excludes = []
self.actions = []
self.src_prefix = [args['source']]
self.artwork_prefix = [args['artwork']]
self.build_prefix = [args['build']]
self.dst_prefix = [args['dest']]
self.created_paths = []
self.package_name = "Unknown"
self.missing = []
def default_channel(self):
return self.args.get('channel', None) == RELEASE_CHANNEL
def construct(self):
""" Meant to be overriden by LLManifest implementors with code that
constructs the complete destination hierarchy."""
pass # override this method
def exclude(self, glob):
""" Excludes all files that match the glob from being included
in the file list by path()."""
self.excludes.append(glob)
def prefix(self, src='', build='', dst='', src_dst=None):
"""
Usage:
with self.prefix(...args as described...):
self.path(...)
For the duration of the 'with' block, pushes a prefix onto the stack.
Within that block, all relevant method calls (esp. to path()) will
prefix paths with the entire prefix stack. Source and destination
prefixes are independent; if omitted (or passed as the empty string),
the prefix has no effect. Thus:
with self.prefix(src='foo'):
# no effect on dst
with self.prefix(dst='bar'):
# no effect on src
If you want to set both at once, use src_dst:
with self.prefix(src_dst='subdir'):
# same as self.prefix(src='subdir', dst='subdir')
# Passing src_dst makes any src or dst argument in the same
# parameter list irrelevant.
Also supports the older (pre-Python-2.5) syntax:
if self.prefix(...args as described...):
self.path(...)
self.end_prefix(...)
Before the arrival of the 'with' statement, one was required to code
self.prefix() and self.end_prefix() in matching pairs to push and to
pop the prefix stacks, respectively. The older prefix() method
returned True specifically so that the caller could indent the
relevant block of code with 'if', just for aesthetic purposes.
"""
if src_dst is not None:
src = src_dst
dst = src_dst
self.src_prefix.append(src)
self.artwork_prefix.append(src)
self.build_prefix.append(build)
self.dst_prefix.append(dst)
## self.display_stacks()
# The above code is unchanged from the original implementation. What's
# new is the return value. We're going to return an instance of
# PrefixManager that binds this LLManifest instance and Does The Right
# Thing on exit.
return self.PrefixManager(self)
def display_stacks(self):
width = 1 + max(len(stack) for stack in self.PrefixManager.stacks)
for stack in self.PrefixManager.stacks:
print("{} {}".format((stack + ':').ljust(width),
os.path.join(*getattr(self, stack))))
class PrefixManager(object):
# stack attributes we manage in this LLManifest (sub)class
# instance
stacks = ("src_prefix", "artwork_prefix", "build_prefix", "dst_prefix")
def __init__(self, manifest):
self.manifest = manifest
# If the caller wrote:
# with self.prefix(...):
# as intended, then bind the state of each prefix stack as it was
# just BEFORE the call to prefix(). Since prefix() appended an
# entry to each prefix stack, capture len()-1.
self.prevlen = { stack: len(getattr(self.manifest, stack)) - 1
for stack in self.stacks }
def __bool__(self):
# If the caller wrote:
# if self.prefix(...):
# then a value of this class had better evaluate as 'True'.
return True
def __enter__(self):
# nobody uses 'with self.prefix(...) as variable:'
return None
def __exit__(self, type, value, traceback):
# First, if the 'with' block raised an exception, just propagate.
# Do NOT swallow it.
if type is not None:
return False
# Okay, 'with' block completed successfully. Restore previous
# state of each of the prefix stacks in self.stacks.
# Note that we do NOT simply call pop() on them as end_prefix()
# does. This is to cope with the possibility that the coder
# changed 'if self.prefix(...):' to 'with self.prefix(...):' yet
# forgot to remove the self.end_prefix(...) call at the bottom of
# the block. In that case, calling pop() again would be Bad! But
# if we restore the length of each stack to what it was before the
# current prefix() block, it doesn't matter whether end_prefix()
# was called or not.
for stack, prevlen in list(self.prevlen.items()):
# find the attribute in 'self.manifest' named by 'stack', and
# truncate that list back to 'prevlen'
del getattr(self.manifest, stack)[prevlen:]
## self.manifest.display_stacks()
def end_prefix(self, descr=None):
"""Pops a prefix off the stack. If given an argument, checks
the argument against the top of the stack. If the argument
matches neither the source or destination prefixes at the top
of the stack, then misnesting must have occurred and an
exception is raised."""
# as an error-prevention mechanism, check the prefix and see if it matches the source or destination prefix. If not, improper nesting may have occurred.
src = self.src_prefix.pop()
artwork = self.artwork_prefix.pop()
build = self.build_prefix.pop()
dst = self.dst_prefix.pop()
if descr and not(src == descr or build == descr or dst == descr):
raise ValueError("End prefix '" + descr + "' didn't match '" +src+ "' or '" +dst + "'")
def get_src_prefix(self):
""" Returns the current source prefix."""
return os.path.join(*self.src_prefix)
def get_artwork_prefix(self):
""" Returns the current artwork prefix."""
return os.path.join(*self.artwork_prefix)
def get_build_prefix(self):
""" Returns the current build prefix."""
return os.path.join(*self.build_prefix)
def get_dst_prefix(self):
""" Returns the current destination prefix."""
return os.path.join(*self.dst_prefix)
def src_path_of(self, relpath):
"""Returns the full path to a file or directory specified
relative to the source directory."""
return os.path.join(self.get_src_prefix(), relpath)
def build_path_of(self, relpath):
"""Returns the full path to a file or directory specified
relative to the build directory."""
return os.path.join(self.get_build_prefix(), relpath)
def dst_path_of(self, relpath):
"""Returns the full path to a file or directory specified
relative to the destination directory."""
return os.path.join(self.get_dst_prefix(), relpath)
def _relative_dst_path(self, dstpath):
"""
Returns the path to a file or directory relative to the destination directory.
This should only be used for generating diagnostic output in the path method.
"""
dest_root=self.dst_prefix[0]
if dstpath.startswith(dest_root+os.path.sep):
return dstpath[len(dest_root)+1:]
elif dstpath.startswith(dest_root):
return dstpath[len(dest_root):]
else:
return dstpath
def ensure_src_dir(self, reldir):
"""Construct the path for a directory relative to the
source path, and ensures that it exists. Returns the
full path."""
path = os.path.join(self.get_src_prefix(), reldir)
self.cmakedirs(path)
return path
def ensure_dst_dir(self, reldir):
"""Construct the path for a directory relative to the
destination path, and ensures that it exists. Returns the
full path."""
path = os.path.join(self.get_dst_prefix(), reldir)
self.cmakedirs(path)
return path
def run_command(self, command, **kwds):
"""
Runs an external command.
Raises ManifestError exception if the command returns a nonzero status.
"""
print("Running command:", shlex.join(command))
sys.stdout.flush()
try:
subprocess.check_call(command, **kwds)
except subprocess.CalledProcessError as err:
raise ManifestError( "Command %s returned non-zero status (%s)"
% (command, err.returncode) )
# <FS:Ansariel> Added for compatibility reasons
def run_command_shell(self, command):
"""
Runs an external command.
Raises ManifestError exception if the command returns a nonzero status.
"""
print("Running command:", command)
sys.stdout.flush()
try:
subprocess.check_call(command, shell=True)
except subprocess.CalledProcessError as err:
raise ManifestError( "Command %s returned non-zero status (%s)"
% (command, err.returncode) )
# </FS:Ansariel>
def created_path(self, path):
""" Declare that you've created a path in order to
a) verify that you really have created it
b) schedule it for cleanup"""
if not os.path.exists(path):
raise ManifestError("Should be something at path " + path)
self.created_paths.append(path)
def put_in_file(self, contents, dst, src=None):
# write contents as dst
dst_path = self.dst_path_of(dst)
self.cmakedirs(os.path.dirname(dst_path))
with open(dst_path, 'wb') as f:
f.write(contents)
# Why would we create a file in the destination tree if not to include
# it in the installer? The default src=None (plus the fact that the
# src param is last) is to preserve backwards compatibility.
if src:
self.file_list.append([src, dst_path])
return dst_path
def replace_in(self, src, dst=None, searchdict={}):
if dst == None:
dst = src
# read src
with open(self.src_path_of(src), "r") as f:
contents = f.read()
# apply dict replacements
for old, new in searchdict.items():
contents = contents.replace(old, new)
self.put_in_file(contents.encode(), dst)
self.created_paths.append(dst)
def copy_action(self, src, dst):
if src and (os.path.exists(src) or os.path.islink(src)):
# ensure that destination path exists
self.cmakedirs(os.path.dirname(dst))
self.created_paths.append(dst)
self.ccopymumble(src, dst)
else:
print("Doesn't exist:", src)
def package_action(self, src, dst):
pass
def finish(self):
"""
generic finish, always called before the ${action}_finish() methods
"""
# Collecting MissingFile instances in self.missing, and checking that
# here, is intended to minimize the number of (potentially lengthy)
# build cycles a developer must run in order to fix missing-files
# errors. The manifest processing is necessarily the last step in a
# build, and if we only caught a single missing file error per run,
# the developer would need to run a build for each additional missing-
# file error until all were resolved. This way permits the developer
# to resolve them all at once.
if self.missing:
print('*' * 72)
print("Missing files:")
# Instead of just dumping each missing file and all the places we
# looked for it, group by common sets of places we looked. Use a
# set to store the 'tried' directories, to avoid mismatches due to
# reordering -- but since we intend to use the set of 'tried'
# directories as a dict key, it must be a frozenset.
organize = defaultdict(set)
for missingfile in self.missing:
organize[frozenset(missingfile.tried)].add(missingfile.pattern)
# Now dump all the patterns sought in each group of 'tried'
# directories.
for tried, patterns in list(organize.items()):
print(" Could not find in:")
for dir in sorted(tried):
print(" %s" % dir)
for pattern in sorted(patterns):
print(" %s" % pattern)
print('*' * 72)
raise MissingError('%s patterns could not be found' % len(self.missing))
def copy_finish(self):
pass
def package_finish(self):
pass
def unpacked_finish(self):
unpacked_file_name = "unpacked_%(plat)s_%(vers)s.tar" % {
'plat':self.args['platform'],
'vers':'_'.join(self.args['version'])}
print("Creating unpacked file:", unpacked_file_name)
# could add a gz here but that doubles the time it takes to do this step
tf = tarfile.open(self.build_path_of(unpacked_file_name), 'w:')
# add the entire installation package, at the very top level
tf.add(self.get_dst_prefix(), "")
tf.close()
def cleanup_finish(self):
""" Delete paths that were specified to have been created by this script"""
for c in self.created_paths:
# *TODO is this gonna be useful?
print("Cleaning up " + c)
def process_either(self, src, dst):
# If it's a real directory, recurse through it --
# but not a symlink! Handle those like files.
if os.path.isdir(src) and not os.path.islink(src):
return self.process_directory(src, dst)
else:
return self.process_file(src, dst)
def process_file(self, src, dst):
if self.includes(src, dst):
for action in self.actions:
methodname = action + "_action"
method = getattr(self, methodname, None)
if method is not None:
method(src, dst)
self.file_list.append([src, dst])
return 1
else:
sys.stdout.write(" (excluding %r, %r)" % (src, dst))
sys.stdout.flush()
return 0
def process_directory(self, src, dst):
if not self.includes(src, dst):
sys.stdout.write(" (excluding %r, %r)" % (src, dst))
sys.stdout.flush()
return 0
names = os.listdir(src)
self.cmakedirs(dst)
errors = []
count = 0
for name in names:
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
count += self.process_either(srcname, dstname)
return count
def includes(self, src, dst):
if src:
for excl in self.excludes:
if fnmatch.fnmatch(src, excl):
return False
return True
def remove(self, *paths):
for path in paths:
if os.path.exists(path):
print("Removing path", path)
if os.path.isdir(path):
shutil.rmtree(path)
else:
os.remove(path)
def ccopymumble(self, src, dst):
"""Copy a single symlink, file or directory."""
if os.path.islink(src):
linkto = os.readlink(src)
if os.path.islink(dst) or os.path.isfile(dst):
os.remove(dst) # because symlinking over an existing link fails
elif os.path.isdir(dst):
shutil.rmtree(dst)
os.symlink(linkto, dst)
elif os.path.isdir(src):
self.ccopytree(src, dst)
else:
self.ccopyfile(src, dst)
# XXX What about devices, sockets etc.?
# YYY would we put such things into a viewer package?!
def ccopyfile(self, src, dst):
""" Copy a single file. Uses filecmp to skip copying for existing files."""
# Don't recopy file if it's up-to-date.
# If we seem to be not not overwriting files that have been
# updated, set the last arg to False, but it will take longer.
## reldst = (dst[len(self.dst_prefix[0]):]
## if dst.startswith(self.dst_prefix[0])
## else dst).lstrip(r'\/')
if os.path.exists(dst) and filecmp.cmp(src, dst, True):
## print "{} (skipping, {} exists)".format(src, reldst)
return
# only copy if it's not excluded
if self.includes(src, dst):
try:
os.unlink(dst)
except OSError as err:
if err.errno != errno.ENOENT:
raise
## print "{} => {}".format(src, reldst)
shutil.copy2(src, dst)
def ccopytree(self, src, dst):
"""Direct copy of shutil.copytree with the additional
feature that the destination directory can exist. It
is so dumb that Python doesn't come with this. Also it
implements the excludes functionality."""
if not self.includes(src, dst):
return
names = os.listdir(src)
self.cmakedirs(dst)
errors = []
for name in names:
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
try:
self.ccopymumble(srcname, dstname)
except (IOError, os.error) as why:
errors.append((srcname, dstname, why))
if errors:
raise ManifestError(errors)
def cmakedirs(self, path):
"""Ensures that a directory exists, and doesn't throw an exception
if you call it on an existing directory."""
# print "making path: ", path
path = os.path.normpath(path)
self.created_paths.append(path)
if not os.path.exists(path):
os.makedirs(path)
def find_existing_file(self, *list):
for f in list:
if os.path.exists(f):
return f
# didn't find it, return last item in list
if len(list) > 0:
return list[-1]
else:
return None
def contents_of_tar(self, src_tar, dst_dir):
""" Extracts the contents of the tarfile (specified
relative to the source prefix) into the directory
specified relative to the destination directory."""
self.check_file_exists(src_tar)
tf = tarfile.open(self.src_path_of(src_tar), 'r')
for member in tf.getmembers():
tf.extract(member, self.ensure_dst_dir(dst_dir))
# TODO get actions working on these dudes, perhaps we should extract to a temporary directory and then process_directory on it?
self.file_list.append([src_tar,
self.dst_path_of(os.path.join(dst_dir,member.name))])
tf.close()
def wildcard_regex(self, src_glob, dst_glob):
# assume src_glob of form "foo/*.bar"
src_re = re.escape(src_glob)
# <FS:Beq> fix up python 3.6 literal support
# src_re = src_re.replace('\*', '([-a-zA-Z0-9._ ]*)')
# src_re is foo/\\*\\.bar
# replace '\\*' with ([-a-zA-Z0-9._ ]*) in the source regex
src_re = src_re.replace(r'\*', r'([-a-zA-Z0-9._ ]*)')
# </FS:Beq>
dst_temp = dst_glob
i = 1
while dst_temp.count("*") > 0:
# <FS:Beq> fix up python 3.6 literal support
# dst_temp = dst_temp.replace('\*', '\g<' + str(i) + '>', 1)
dst_temp = dst_temp.replace('*', r'\g<' + str(i) + '>', 1)
i = i + 1
# </FS:Beq>
return re.compile(src_re), dst_temp
def check_file_exists(self, path):
if not os.path.exists(path) and not os.path.islink(path):
raise MissingError("Path %s doesn't exist" % (os.path.abspath(path),))
wildcard_pattern = re.compile(r'\*')
def expand_globs(self, src, dst):
src_list = glob.glob(src)
src_re, d_template = self.wildcard_regex(src.replace('\\', '/'),
dst.replace('\\', '/'))
for s in src_list:
d = src_re.sub(d_template, s.replace('\\', '/'))
yield os.path.normpath(s), os.path.normpath(d)
def path2basename(self, path, file):
"""
It is a common idiom to write:
self.path(os.path.join(somedir, somefile), somefile)
So instead you can write:
self.path2basename(somedir, somefile)
Note that this is NOT the same as:
self.path(os.path.join(somedir, somefile))
which is the same as:
temppath = os.path.join(somedir, somefile)
self.path(temppath, temppath)
"""
return self.path(os.path.join(path, file), file)
def path(self, src, dst=None):
sys.stdout.flush()
if src == None:
raise ManifestError("No source file, dst is " + dst)
if dst == None:
dst = src
dst = os.path.join(self.get_dst_prefix(), dst)
sys.stdout.write("Processing %s => %s ... " % (src, self._relative_dst_path(dst)))
def try_path(src):
# expand globs
count = 0
if self.wildcard_pattern.search(src):
for s,d in self.expand_globs(src, dst):
assert(s != d)
count += self.process_file(s, d)
else:
# if we're specifying a single path (not a glob),
# we should error out if it doesn't exist
self.check_file_exists(src)
count += self.process_either(src, dst)
return count
try_prefixes = [self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix()]
for pfx in try_prefixes:
try:
count = try_path(os.path.join(pfx, src))
except MissingError:
# if we produce MissingError, just try the next prefix
continue
# If we actually found nonzero files, stop looking
if count:
break
else:
# no more prefixes left to try
print(("\nunable to find '%s'; looked in:\n %s" % (src, '\n '.join(try_prefixes))))
self.missing.append(MissingFile(pattern=src, tried=try_prefixes))
# At this point 'count' might never have been successfully
# assigned! Even if it was, though, we can be sure it is 0.
return 0
print("%d files" % count)
# Let caller check whether we processed as many files as expected. In
# particular, let caller notice 0.
return count
def path_optional(self, src, dst=None):
sys.stdout.flush()
if src == None:
raise ManifestError("No source file, dst is " + dst)
if dst == None:
dst = src
dst = os.path.join(self.get_dst_prefix(), dst)
sys.stdout.write("Processing %s => %s ... " % (src, self._relative_dst_path(dst)))
def try_path(src):
# expand globs
count = 0
if self.wildcard_pattern.search(src):
for s,d in self.expand_globs(src, dst):
assert(s != d)
count += self.process_file(s, d)
else:
# if we're specifying a single path (not a glob),
# we should error out if it doesn't exist
self.check_file_exists(src)
count += self.process_either(src, dst)
return count
try_prefixes = [self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix()]
for pfx in try_prefixes:
try:
count = try_path(os.path.join(pfx, src))
except MissingError:
# if we produce MissingError, just try the next prefix
continue
# If we actually found nonzero files, stop looking
if count:
break
else:
sys.stdout.write("Skipping %s\n" % (src))
return 0
print("%d files" % count)
# Let caller check whether we processed as many files as expected. In
# particular, let caller notice 0.
return count
def do(self, *actions):
self.actions = actions
self.construct()
# perform finish actions
# generic finish first
self.finish()
for action in self.actions:
methodname = action + "_finish"
method = getattr(self, methodname, None)
if method is not None:
method()
return self.file_list
+147
View File
@@ -0,0 +1,147 @@
#!/usr/bin/env python3
"""\
@file test_win32_manifest.py
@brief Test an assembly binding version and uniqueness in a windows dll or exe.
$LicenseInfo:firstyear=2009&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2009-2011, Linden Research, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2.1 of the License only.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
$/LicenseInfo$
"""
import sys, os
import tempfile
from xml.dom.minidom import parse
class AssemblyTestException(Exception):
pass
class NoManifestException(AssemblyTestException):
pass
class MultipleBindingsException(AssemblyTestException):
pass
class UnexpectedVersionException(AssemblyTestException):
pass
class NoMatchingAssemblyException(AssemblyTestException):
pass
def get_HKLM_registry_value(key_str, value_str):
import winreg
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
key = winreg.OpenKey(reg, key_str)
value = winreg.QueryValueEx(key, value_str)[0]
#print 'Found: %s' % value
return value
def find_vc_dir():
supported_products = ([(r'VisualStudio', r'VC'), (r'VCExpress', r'VC')])
supported_versions = (r'8.0', r'9.0')
supported_products = (r'VisualStudio', r'VCExpress')
value_str = (r'ProductDir')
searched = []
for product in supported_products:
for version in supported_versions:
key_str = (r'SOFTWARE\Microsoft\%s\%s\Setup\VC' %
(product, version))
try:
return get_HKLM_registry_value(key_str, value_str)
except WindowsError as err:
x64_key_str = (r'SOFTWARE\Wow6432Node\Microsoft\%s\%s\Setup\VC' % (product, version))
try:
return get_HKLM_registry_value(x64_key_str, value_str)
except:
print("Didn't find MS %s version %s " % (product,version), file=sys.stderr)
raise
def find_mt_path():
vc_dir = find_vc_dir()
mt_path = '\"%sbin\\mt.exe\"' % vc_dir
return mt_path
def test_assembly_binding(src_filename, assembly_name, assembly_ver):
print("checking %s dependency %s..." % (src_filename, assembly_name))
(tmp_file_fd, tmp_file_name) = tempfile.mkstemp(suffix='.xml')
tmp_file = os.fdopen(tmp_file_fd)
tmp_file.close()
mt_path = find_mt_path()
resource_id = ""
if os.path.splitext(src_filename)[1].lower() == ".dll":
resource_id = ";#2"
system_call = '%s -nologo -inputresource:%s%s -out:%s > NUL' % (mt_path, src_filename, resource_id, tmp_file_name)
print("Executing: %s" % system_call)
mt_result = os.system(system_call)
if mt_result == 31:
print("No manifest found in %s" % src_filename)
raise NoManifestException()
manifest_dom = parse(tmp_file_name)
nodes = manifest_dom.getElementsByTagName('assemblyIdentity')
versions = list()
for node in nodes:
if node.getAttribute('name') == assembly_name:
versions.append(node.getAttribute('version'))
if len(versions) == 0:
print("No matching assemblies found in %s" % src_filename)
raise NoMatchingAssemblyException()
#elif len(versions) > 1:
# print("Multiple bindings to %s found:" % assembly_name)
# print(versions)
# print()
# raise MultipleBindingsException(versions)
#elif versions[0] != assembly_ver:
# print("Unexpected version found for %s:" % assembly_name)
# print("Wanted %s, found %s" % (assembly_ver, versions[0]))
# print()
# raise UnexpectedVersionException(assembly_ver, versions[0])
os.remove(tmp_file_name)
print("SUCCESS: %s OK!" % src_filename)
print()
if __name__ == '__main__':
print()
print("Running test_win32_manifest.py...")
usage = 'test_win32_manfest <srcFileName> <assemblyName> <assemblyVersion>'
try:
src_filename = sys.argv[1]
assembly_name = sys.argv[2]
assembly_ver = sys.argv[3]
except:
print("Usage:")
print(usage)
print()
raise
test_assembly_binding(src_filename, assembly_name, assembly_ver)
+65
View File
@@ -0,0 +1,65 @@
# -*- cmake -*-
project(linux_crash_logger)
include(00-Common)
include(Linking)
include(UI)
include(CURL)
include(OpenSSL)
include(ZLIBNG)
include_directories(
${LLCOREHTTP_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${LLCRASHLOGGER_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
${LLFILESYSTEM_INCLUDE_DIRS}
${LLXML_INCLUDE_DIRS}
${FREETYPE_INCLUDE_DIRS}
)
include_directories(SYSTEM
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
${LLXML_SYSTEM_INCLUDE_DIRS}
)
include_directories(SYSTEM
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
${LLXML_SYSTEM_INCLUDE_DIRS}
)
set(linux_crash_logger_SOURCE_FILES
linux_crash_logger.cpp
)
set(linux_crash_logger_HEADER_FILES
CMakeLists.txt
llcrashloggerlinux.h
)
list(APPEND linux_crash_logger_SOURCE_FILES
${linux_crash_logger_HEADER_FILES}
)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
add_executable(linux-crash-logger ${linux_crash_logger_SOURCE_FILES})
# llcommon uses `clock_gettime' which is provided by librt on linux.
set(LIBRT_LIBRARY rt)
target_link_libraries(linux-crash-logger
# llcrashlogger
llfilesystem
llxml
llmessage
llmath
llcorehttp
llcommon
ll::uilibraries
X11
)
add_custom_target(linux-crash-logger-target ALL
DEPENDS linux-crash-logger)
+3
View File
@@ -0,0 +1,3 @@
This component is no longer used in Linden Lab builds.
Change requests to support continued use by open source
builds are welcome.
@@ -0,0 +1,146 @@
/**
* @file linux_crash_logger.cpp
* @brief Linux crash logger implementation
*
* $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include <iostream>
#include <string>
#include <curl/curl.h>
#include <FL/fl_ask.H>
/* Called via
execl( gCrashLogger.c_str(), gCrashLogger.c_str(), descriptor.path(), gVersion.c_str(), gBugsplatDB.c_str(), nullptr );
*/
int main(int argc, char **argv)
{
std::cerr << "linux crash logger called: ";
for( int i = 1; i < argc; ++i )
std::cerr << argv[i] << " ";
std::cerr << std::endl;
if( argc < 4 )
{
std::cerr << argv[0] << "Not enough arguments" << std::endl;
return 1;
}
std::string dmpFile{ argv[1] };
std::string version{ argv[2] };
std::string strDb{ argv[3] };
std::string strAsk{ argv[4] };
if( strAsk == "ask" )
{
auto choice = fl_choice( "Firestorm has crashed, submit the minidump?", "No", "Yes", nullptr );
if( choice == 0 )
{
std::cerr << "Abort send due to users choice" << std::endl;
return 0;
}
}
std::string url{ "https://" };
url += strDb;
url += ".bugsplat.com/post/bp/crash/crashpad.php";
curl_global_init(CURL_GLOBAL_ALL);
auto curl = curl_easy_init();
//Not compatible with LL's crusty old curl - support for the curl_mime functions
//was introduced in curl 7.57.0, LL is still using 7.54 :(
/*
if( curl)
{
auto form = curl_mime_init(curl);
auto field = curl_mime_addpart(form);
curl_mime_name(field, "upload_file_minidump");
curl_mime_filedata(field, dmpFile.c_str() );
field = curl_mime_addpart(form);
curl_mime_name(field, "product");
curl_mime_data(field, "Firestorm-Releasex64", CURL_ZERO_TERMINATED);
field = curl_mime_addpart(form);
curl_mime_name(field, "version");
curl_mime_data(field, version.c_str(), CURL_ZERO_TERMINATED);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str() );
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
auto res = curl_easy_perform(curl);
if(res != CURLE_OK)
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
curl_easy_cleanup(curl);
curl_mime_free(form);
}*/
if (auto curl_handle = curl_easy_init()) {
struct curl_httppost* formpost = NULL;
struct curl_httppost* lastptr = NULL;
// Add the file part
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "upload_file_minidump",
CURLFORM_FILE, dmpFile.c_str(),
CURLFORM_END);
// Add the 'product' part
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "product",
CURLFORM_COPYCONTENTS, "Firestorm-Releasex64",
CURLFORM_END);
// Add the 'version' part
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "version",
CURLFORM_COPYCONTENTS, version.c_str(),
CURLFORM_END);
// Set the URL
curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
// Set the form post data
curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, formpost);
// Perform the request
auto res = curl_easy_perform(curl_handle);
// Cleanup
curl_easy_cleanup(curl_handle);
curl_formfree(formpost);
// Check for errors
if (res != CURLE_OK)
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}
return 0;
}
@@ -0,0 +1,45 @@
/**
* @file llcrashloggerlinux.h
* @brief Linux crash logger definition
*
* $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LLCRASHLOGGERLINUX_H
#define LLCRASHLOGGERLINUX_H
#include "linden_common.h"
#include "llcrashlogger.h"
#include "llstring.h"
class LLCrashLoggerLinux : public LLCrashLogger
{
public:
LLCrashLoggerLinux(void);
~LLCrashLoggerLinux(void);
virtual bool frame();
virtual void updateApplication(const std::string& = LLStringUtil::null);
virtual void gatherPlatformSpecificFiles();
virtual bool cleanup();
};
#endif
+86
View File
@@ -0,0 +1,86 @@
# -*- cmake -*-
project(llappearance)
include(00-Common)
include(LLCommon)
include(LLImage)
include(LLCoreHttp)
include(LLWindow)
include(Linking)
set(llappearance_SOURCE_FILES
llavatarappearance.cpp
llavatarjoint.cpp
llavatarjointmesh.cpp
lldriverparam.cpp
lllocaltextureobject.cpp
llpolyskeletaldistortion.cpp
llpolymesh.cpp
llpolymorph.cpp
lltexglobalcolor.cpp
lltexlayer.cpp
lltexlayerparams.cpp
llwearable.cpp
llwearabledata.cpp
llwearabletype.cpp
llviewervisualparam.cpp
llavatarappearancedefines.cpp
)
set(llappearance_HEADER_FILES
CMakeLists.txt
llavatarappearance.h
llavatarjoint.h
llavatarjointmesh.h
lldriverparam.h
lljointpickname.h
lllocaltextureobject.h
llpolyskeletaldistortion.h
llpolymesh.h
llpolymorph.h
lltexglobalcolor.h
lltexlayer.h
lltexlayerparams.h
llwearable.h
llwearabledata.h
llwearabletype.h
llviewervisualparam.h
llavatarappearancedefines.h
)
list(APPEND llappearance_SOURCE_FILES ${llappearance_HEADER_FILES})
add_library (llappearance ${llappearance_SOURCE_FILES})
target_link_libraries(llappearance
llcharacter
llinventory
llimage
llrender
llfilesystem
llmath
llxml
llmessage
llcorehttp
llcommon
)
target_include_directories( llappearance INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
if (BUILD_HEADLESS)
add_library (llappearanceheadless ${llappearance_SOURCE_FILES})
target_include_directories( llappearanceheadless INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(llappearanceheadless
llcharacter
llinventory
llimage
llfilesystem
llmath
llxml
llmessage
llcorehttp
llcommon
)
endif (BUILD_HEADLESS)
File diff suppressed because it is too large Load Diff
+491
View File
@@ -0,0 +1,491 @@
/**
* @file llavatarappearance.h
* @brief Declaration of LLAvatarAppearance class
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_AVATAR_APPEARANCE_H
#define LL_AVATAR_APPEARANCE_H
#include "llcharacter.h"
#include "llavatarappearancedefines.h"
#include "llavatarjointmesh.h"
#include "lldriverparam.h"
#include "lltexlayer.h"
#include "llviewervisualparam.h"
#include "llxmltree.h"
class LLTexLayerSet;
class LLTexGlobalColor;
class LLTexGlobalColorInfo;
class LLWearableData;
class LLAvatarBoneInfo;
class LLAvatarSkeletonInfo;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLAvatarAppearance
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLAvatarAppearance : public LLCharacter
{
LOG_CLASS(LLAvatarAppearance);
protected:
struct LLAvatarXmlInfo;
/********************************************************************************
** **
** INITIALIZATION
**/
private:
// Hide default constructor.
LLAvatarAppearance() {}
public:
LLAvatarAppearance(LLWearableData* wearable_data);
virtual ~LLAvatarAppearance();
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.
S32 mInitFlags{ 0 };
virtual bool loadSkeletonNode();
bool loadMeshNodes();
bool loadLayersets();
/** Initialization
** **
*******************************************************************************/
/********************************************************************************
** **
** INHERITED
**/
//--------------------------------------------------------------------
// LLCharacter interface and related
//--------------------------------------------------------------------
public:
/*virtual*/ LLJoint* getCharacterJoint(U32 num);
/*virtual*/ const char* getAnimationPrefix() { return "avatar"; }
/*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset);
/*virtual*/ LLJoint* findCollisionVolume(S32 volume_id);
/*virtual*/ S32 getCollisionVolumeID(std::string &name);
/*virtual*/ LLPolyMesh* getHeadMesh();
/*virtual*/ LLPolyMesh* getUpperBodyMesh();
/** Inherited
** **
*******************************************************************************/
/********************************************************************************
** **
** STATE
**/
public:
virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
virtual bool isValid() const;
virtual bool isUsingLocalAppearance() const = 0;
virtual bool isEditingAppearance() const = 0;
bool isBuilt() const { return mIsBuilt; }
// <FS:Ansariel> [Legacy Bake]
virtual bool isUsingServerBakes() const = 0;
/** State
** **
*******************************************************************************/
/********************************************************************************
** **
** SKELETON
**/
protected:
virtual LLAvatarJoint* createAvatarJoint() = 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; }
LLVector3 mHeadOffset{}; // current head position
LLAvatarJoint* mRoot{ nullptr };
//<FS:Ansariel> Joint-lookup improvements
// typedef std::map<std::string, LLJoint*> joint_map_t;
typedef std::map<std::string, LLJoint*, std::less<>> 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, std::less<>> joint_alias_map_t;
const joint_alias_map_t& getJointAliases();
protected:
static bool parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree);
virtual void buildCharacter();
virtual bool loadAvatar();
// [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8)
virtual F32 getAvatarOffset() /*const*/;
// [/RLVa:KB]
// <FS:Ansariel> [Legacy Bake]
virtual void bodySizeChanged() = 0;
bool setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
bool allocateCharacterJoints(S32 num);
bool buildSkeleton(const LLAvatarSkeletonInfo *info);
void clearSkeleton();
bool mIsBuilt{ false }; // state of deferred character building
avatar_joint_list_t mSkeleton;
LLVector3OverrideMap mPelvisFixups;
joint_alias_map_t mJointAliasMap;
//--------------------------------------------------------------------
// Pelvis height adjustment members.
//--------------------------------------------------------------------
public:
void addPelvisFixup( F32 fixup, const LLUUID& mesh_id );
void removePelvisFixup( const LLUUID& mesh_id );
bool hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const;
bool hasPelvisFixup( F32& fixup ) const;
LLVector3 mBodySize;
LLVector3 mAvatarOffset;
protected:
F32 mPelvisToFoot{ 0.f };
//--------------------------------------------------------------------
// Cached pointers to well known joints
//--------------------------------------------------------------------
public:
LLJoint* mPelvisp{nullptr};
LLJoint* mTorsop{ nullptr };
LLJoint* mChestp{ nullptr };
LLJoint* mNeckp{ nullptr };
LLJoint* mHeadp{ nullptr };
LLJoint* mSkullp{ nullptr };
LLJoint* mEyeLeftp{ nullptr };
LLJoint* mEyeRightp{ nullptr };
LLJoint* mHipLeftp{ nullptr };
LLJoint* mHipRightp{ nullptr };
LLJoint* mKneeLeftp{ nullptr };
LLJoint* mKneeRightp{ nullptr };
LLJoint* mAnkleLeftp{ nullptr };
LLJoint* mAnkleRightp{ nullptr };
LLJoint* mFootLeftp{ nullptr };
LLJoint* mFootRightp{ nullptr };
LLJoint* mWristLeftp{ nullptr };
LLJoint* mWristRightp{ nullptr };
//--------------------------------------------------------------------
// XML parse tree
//--------------------------------------------------------------------
protected:
static LLAvatarSkeletonInfo* sAvatarSkeletonInfo;
static LLAvatarXmlInfo* sAvatarXmlInfo;
// <FS:Ansariel> Get attachment point name from ID
public:
static std::string getAttachmentPointName(S32 attachmentPointId);
// </FS:Ansariel>
/** Skeleton
** **
*******************************************************************************/
/********************************************************************************
** **
** RENDERING
**/
public:
bool mIsDummy{ false }; // for special views and animated object controllers; local to viewer
//--------------------------------------------------------------------
// Morph masks
//--------------------------------------------------------------------
public:
void addMaskedMorph(LLAvatarAppearanceDefines::EBakedTextureIndex index, LLVisualParam* morph_target, bool invert, std::string layer);
virtual void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0;
/** Rendering
** **
*******************************************************************************/
//--------------------------------------------------------------------
// Composites
//--------------------------------------------------------------------
public:
// <FS:Ansariel> [Legacy Bake]
//virtual void invalidateComposite(LLTexLayerSet* layerset) = 0;
virtual void invalidateComposite(LLTexLayerSet* layerset, bool upload_result) = 0;
/********************************************************************************
** **
** MESHES
**/
public:
virtual void updateMeshTextures() = 0;
virtual void dirtyMesh() = 0; // Dirty the avatar mesh
static const LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary *getDictionary() { return sAvatarDictionary; }
protected:
virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority
protected:
typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
polymesh_map_t mPolyMeshes;
avatar_joint_list_t mMeshLOD;
// mesh entries and backed textures
static LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* sAvatarDictionary;
/** Meshes
** **
*******************************************************************************/
/********************************************************************************
** **
** APPEARANCE
**/
//--------------------------------------------------------------------
// Clothing colors (convenience functions to access visual parameters)
//--------------------------------------------------------------------
public:
// <FS:Ansariel> [Legacy Bake]
//void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color);
void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te);
static bool teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name);
//--------------------------------------------------------------------
// Global colors
//--------------------------------------------------------------------
public:
LLColor4 getGlobalColor(const std::string& color_name ) const;
// <FS:Ansariel> [Legacy Bake]
//virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0;
virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, bool upload_bake) = 0;
// </FS:Ansariel> [Legacy Bake]
protected:
LLTexGlobalColor* mTexSkinColor{ nullptr };
LLTexGlobalColor* mTexHairColor{ nullptr };
LLTexGlobalColor* mTexEyeColor{ nullptr };
//--------------------------------------------------------------------
// Visibility
//--------------------------------------------------------------------
public:
static LLColor4 getDummyColor();
/** Appearance
** **
*******************************************************************************/
/********************************************************************************
** **
** WEARABLES
**/
public:
LLWearableData* getWearableData() { return mWearableData; }
const LLWearableData* getWearableData() const { return mWearableData; }
virtual bool isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex te, U32 index = 0 ) const = 0;
virtual bool isWearingWearableType(LLWearableType::EType type ) const;
private:
LLWearableData* mWearableData{ nullptr };
/********************************************************************************
** **
** BAKED TEXTURES
**/
public:
LLTexLayerSet* getAvatarLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
protected:
virtual LLTexLayerSet* createTexLayerSet() = 0;
protected:
class LLMaskedMorph;
typedef std::deque<LLMaskedMorph *> morph_list_t;
struct BakedTextureData
{
LLUUID mLastTextureID;
LLTexLayerSet* mTexLayerSet{ nullptr }; // Only exists for self
bool mIsLoaded{ false };
bool mIsUsed{ false };
LLAvatarAppearanceDefines::ETextureIndex mTextureIndex{ LLAvatarAppearanceDefines::ETextureIndex::TEX_INVALID };
U32 mMaskTexName{ 0 };
// Stores pointers to the joint meshes that this baked texture deals with
avatar_joint_mesh_list_t mJointMeshes;
morph_list_t mMaskedMorphs;
};
typedef std::vector<BakedTextureData> bakedtexturedata_vec_t;
bakedtexturedata_vec_t mBakedTextureDatas;
/********************************************************************************
** **
** PHYSICS
**/
//--------------------------------------------------------------------
// Collision volumes
//--------------------------------------------------------------------
public:
S32 mNumBones{ 0 };
S32 mNumCollisionVolumes{ 0 };
LLAvatarJointCollisionVolume* mCollisionVolumes{ nullptr };
protected:
bool allocateCollisionVolumes(U32 num);
/** Physics
** **
*******************************************************************************/
/********************************************************************************
** **
** SUPPORT CLASSES
**/
struct LLAvatarXmlInfo
{
LLAvatarXmlInfo();
~LLAvatarXmlInfo();
bool parseXmlSkeletonNode(LLXmlTreeNode* root);
bool parseXmlMeshNodes(LLXmlTreeNode* root);
bool parseXmlColorNodes(LLXmlTreeNode* root);
bool parseXmlLayerNodes(LLXmlTreeNode* root);
bool parseXmlDriverNodes(LLXmlTreeNode* root);
bool parseXmlMorphNodes(LLXmlTreeNode* root);
struct LLAvatarMeshInfo
{
typedef std::pair<LLViewerVisualParamInfo*,bool> morph_info_pair_t; // LLPolyMorphTargetInfo stored here
typedef std::vector<morph_info_pair_t> morph_info_list_t;
LLAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {}
~LLAvatarMeshInfo()
{
for (morph_info_list_t::value_type& pair : mPolyMorphTargetInfoList)
{
delete pair.first;
}
mPolyMorphTargetInfoList.clear();
}
std::string mType;
S32 mLOD;
std::string mMeshFileName;
std::string mReferenceMeshName;
F32 mMinPixelArea;
morph_info_list_t mPolyMorphTargetInfoList;
};
typedef std::vector<LLAvatarMeshInfo*> mesh_info_list_t;
mesh_info_list_t mMeshInfoList;
typedef std::vector<LLViewerVisualParamInfo*> skeletal_distortion_info_list_t; // LLPolySkeletalDistortionInfo stored here
skeletal_distortion_info_list_t mSkeletalDistortionInfoList;
struct LLAvatarAttachmentInfo
{
LLAvatarAttachmentInfo()
: mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(false),
mIsHUDAttachment(false), mHasPosition(false), mHasRotation(false) {}
std::string mName;
std::string mJointName;
LLVector3 mPosition;
LLVector3 mRotationEuler;
S32 mGroup;
S32 mAttachmentID;
S32 mPieMenuSlice;
bool mVisibleFirstPerson;
bool mIsHUDAttachment;
bool mHasPosition;
bool mHasRotation;
};
typedef std::vector<LLAvatarAttachmentInfo*> attachment_info_list_t;
attachment_info_list_t mAttachmentInfoList;
LLTexGlobalColorInfo *mTexSkinColorInfo;
LLTexGlobalColorInfo *mTexHairColorInfo;
LLTexGlobalColorInfo *mTexEyeColorInfo;
typedef std::vector<LLTexLayerSetInfo*> layer_info_list_t;
layer_info_list_t mLayerInfoList;
typedef std::vector<LLDriverParamInfo*> driver_info_list_t;
driver_info_list_t mDriverInfoList;
struct LLAvatarMorphInfo
{
LLAvatarMorphInfo()
: mInvert(false) {}
std::string mName;
std::string mRegion;
std::string mLayer;
bool mInvert;
};
typedef std::vector<LLAvatarMorphInfo*> morph_info_list_t;
morph_info_list_t mMorphMaskInfoList;
};
class LLMaskedMorph
{
public:
LLMaskedMorph(LLVisualParam *morph_target, bool invert, std::string layer);
LLVisualParam *mMorphTarget;
bool mInvert;
std::string mLayer;
};
/** Support Classes
** **
*******************************************************************************/
};
#endif // LL_AVATAR_APPEARANCE_H

Some files were not shown because too many files have changed in this diff Show More