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
+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
@@ -0,0 +1,415 @@
/**
* @file llavatarappearancedefines.cpp
* @brief Implementation of LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llavatarappearancedefines.h"
#include "indra_constants.h"
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 2048;
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 2048;
using namespace LLAvatarAppearanceDefines;
/*********************************************************************************
* Edit this function to add/remove/change textures and mesh definitions for avatars.
*/
LLAvatarAppearanceDictionary::Textures::Textures()
{
addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", true, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", true, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", LLWearableType::WT_SHIRT));
addEntry(TEX_LOWER_PANTS, new TextureEntry("lower_pants", true, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", LLWearableType::WT_PANTS));
addEntry(TEX_EYES_IRIS, new TextureEntry("eyes_iris", true, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", LLWearableType::WT_EYES));
addEntry(TEX_HAIR, new TextureEntry("hair_grain", true, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", LLWearableType::WT_HAIR));
addEntry(TEX_UPPER_BODYPAINT, new TextureEntry("upper_bodypaint", true, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
addEntry(TEX_LOWER_BODYPAINT, new TextureEntry("lower_bodypaint", true, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
addEntry(TEX_LOWER_SHOES, new TextureEntry("lower_shoes", true, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", LLWearableType::WT_SHOES));
addEntry(TEX_LOWER_SOCKS, new TextureEntry("lower_socks", true, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", LLWearableType::WT_SOCKS));
addEntry(TEX_UPPER_JACKET, new TextureEntry("upper_jacket", true, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET));
addEntry(TEX_LOWER_JACKET, new TextureEntry("lower_jacket", true, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET));
addEntry(TEX_UPPER_GLOVES, new TextureEntry("upper_gloves", true, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", LLWearableType::WT_GLOVES));
addEntry(TEX_UPPER_UNDERSHIRT, new TextureEntry("upper_undershirt", true, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERSHIRT));
addEntry(TEX_LOWER_UNDERPANTS, new TextureEntry("lower_underpants", true, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERPANTS));
addEntry(TEX_SKIRT, new TextureEntry("skirt", true, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", LLWearableType::WT_SKIRT));
addEntry(TEX_LOWER_ALPHA, new TextureEntry("lower_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
addEntry(TEX_UPPER_ALPHA, new TextureEntry("upper_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
addEntry(TEX_HEAD_ALPHA, new TextureEntry("head_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
addEntry(TEX_EYES_ALPHA, new TextureEntry("eyes_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
addEntry(TEX_HAIR_ALPHA, new TextureEntry("hair_alpha", true, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
addEntry(TEX_HEAD_TATTOO, new TextureEntry("head_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
addEntry(TEX_HEAD_UNIVERSAL_TATTOO, new TextureEntry("head_universal_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_UPPER_UNIVERSAL_TATTOO, new TextureEntry("upper_universal_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_LOWER_UNIVERSAL_TATTOO, new TextureEntry("lower_universal_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_SKIRT_TATTOO, new TextureEntry("skirt_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_HAIR_TATTOO, new TextureEntry("hair_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_EYES_TATTOO, new TextureEntry("eyes_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_LEFT_ARM_TATTOO, new TextureEntry("leftarm_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_LEFT_LEG_TATTOO, new TextureEntry("leftleg_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_AUX1_TATTOO, new TextureEntry("aux1_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_AUX2_TATTOO, new TextureEntry("aux2_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_AUX3_TATTOO, new TextureEntry("aux3_tattoo", true, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", false, BAKED_HEAD, "head"));
addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", false, BAKED_UPPER, "upper"));
addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", false, BAKED_LOWER, "lower"));
addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", false, BAKED_EYES, "eyes"));
addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", false, BAKED_HAIR, "hair"));
addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", false, BAKED_SKIRT, "skirt"));
addEntry(TEX_LEFT_ARM_BAKED, new TextureEntry("leftarm-baked", false, BAKED_LEFT_ARM, "leftarm"));
addEntry(TEX_LEFT_LEG_BAKED, new TextureEntry("leftleg-baked", false, BAKED_LEFT_LEG, "leftleg"));
addEntry(TEX_AUX1_BAKED, new TextureEntry("aux1-baked", false, BAKED_AUX1, "aux1"));
addEntry(TEX_AUX2_BAKED, new TextureEntry("aux2-baked", false, BAKED_AUX2, "aux2"));
addEntry(TEX_AUX3_BAKED, new TextureEntry("aux3-baked", false, BAKED_AUX3, "aux3"));
}
LLAvatarAppearanceDictionary::BakedTextures::BakedTextures()
{
// Baked textures
addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED,
"head", "a4b9dc38-e13b-4df9-b284-751efb0566ff",
4, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, TEX_HEAD_UNIVERSAL_TATTOO,
6, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED,
"upper_body", "5943ff64-d26c-4a90-a8c0-d61f56bd98d4",
8, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET,
TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, TEX_UPPER_UNIVERSAL_TATTOO,
9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED,
"lower_body", "2944ee70-90a7-425d-a5fb-d749c782ed7d",
9, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS,
TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, TEX_LOWER_UNIVERSAL_TATTOO,
10, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED,
"eyes", "27b1bc0f-979f-4b13-95fe-b981c2ba9788",
3, TEX_EYES_IRIS, TEX_EYES_TATTOO, TEX_EYES_ALPHA,
3, LLWearableType::WT_EYES, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA));
addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED,
"skirt", "03e7e8cb-1368-483b-b6f3-74850838ba63",
2, TEX_SKIRT, TEX_SKIRT_TATTOO,
2, LLWearableType::WT_SKIRT, LLWearableType::WT_UNIVERSAL ));
addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED,
"hair", "a60e85a9-74e8-48d8-8a2d-8129f28d9b61",
3, TEX_HAIR, TEX_HAIR_TATTOO, TEX_HAIR_ALPHA,
3, LLWearableType::WT_HAIR, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA));
addEntry(BAKED_LEFT_ARM, new BakedEntry(TEX_LEFT_ARM_BAKED,
"leftarm", "9f39febf-22d7-0087-79d1-e9e8c6c9ed19",
1, TEX_LEFT_ARM_TATTOO,
1, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_LEFT_LEG, new BakedEntry(TEX_LEFT_LEG_BAKED,
"leftleg", "054a7a58-8ed5-6386-0add-3b636fb28b78",
1, TEX_LEFT_LEG_TATTOO,
1, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_AUX1, new BakedEntry(TEX_AUX1_BAKED,
"aux1", "790c11be-b25c-c17e-b4d2-6a4ad786b752",
1, TEX_AUX1_TATTOO,
1, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_AUX2, new BakedEntry(TEX_AUX2_BAKED,
"aux2", "d78c478f-48c7-5928-5864-8d99fb1f521e",
1, TEX_AUX2_TATTOO,
1, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_AUX3, new BakedEntry(TEX_AUX3_BAKED,
"aux3", "6a95dd53-edd9-aac8-f6d3-27ed99f3c3eb",
1, TEX_AUX3_TATTOO,
1, LLWearableType::WT_UNIVERSAL));
}
LLAvatarAppearanceDictionary::MeshEntries::MeshEntries()
{
// MeshEntries
addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, PN_4));
addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, PN_5));
addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, PN_0)); // no baked mesh associated currently
addEntry(MESH_ID_UPPER_BODY, new MeshEntry(BAKED_UPPER, "upperBodyMesh", 5, PN_1));
addEntry(MESH_ID_LOWER_BODY, new MeshEntry(BAKED_LOWER, "lowerBodyMesh", 5, PN_2));
addEntry(MESH_ID_EYEBALL_LEFT, new MeshEntry(BAKED_EYES, "eyeBallLeftMesh", 2, PN_3));
addEntry(MESH_ID_EYEBALL_RIGHT, new MeshEntry(BAKED_EYES, "eyeBallRightMesh", 2, PN_3));
addEntry(MESH_ID_SKIRT, new MeshEntry(BAKED_SKIRT, "skirtMesh", 5, PN_5));
}
/*
*
*********************************************************************************/
LLAvatarAppearanceDictionary::LLAvatarAppearanceDictionary()
{
createAssociations();
}
//virtual
LLAvatarAppearanceDictionary::~LLAvatarAppearanceDictionary()
{
}
// Baked textures are composites of textures; for each such composited texture,
// map it to the baked texture.
void LLAvatarAppearanceDictionary::createAssociations()
{
for (BakedTextures::value_type& baked_pair : mBakedTextures)
{
const EBakedTextureIndex baked_index = baked_pair.first;
const BakedEntry *dict = baked_pair.second;
// For each texture that this baked texture index affects, associate those textures
// with this baked texture index.
for (const ETextureIndex local_texture_index : dict->mLocalTextures)
{
mTextures[local_texture_index]->mIsUsedByBakedTexture = true;
mTextures[local_texture_index]->mBakedTextureIndex = baked_index;
}
}
}
LLAvatarAppearanceDictionary::TextureEntry::TextureEntry(const std::string &name,
bool is_local_texture,
EBakedTextureIndex baked_texture_index,
const std::string &default_image_name,
LLWearableType::EType wearable_type) :
LLDictionaryEntry(name),
mIsLocalTexture(is_local_texture),
mIsBakedTexture(!is_local_texture),
mIsUsedByBakedTexture(baked_texture_index != BAKED_NUM_INDICES),
mBakedTextureIndex(baked_texture_index),
mDefaultImageName(default_image_name),
mWearableType(wearable_type)
{
}
LLAvatarAppearanceDictionary::MeshEntry::MeshEntry(EBakedTextureIndex baked_index,
const std::string &name,
U8 level,
LLJointPickName pick) :
LLDictionaryEntry(name),
mBakedID(baked_index),
mLOD(level),
mPickName(pick)
{
}
LLAvatarAppearanceDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index,
const std::string &name,
const std::string &hash_name,
U32 num_local_textures,
... ) :
LLDictionaryEntry(name),
mWearablesHashID(LLUUID(hash_name)),
mTextureIndex(tex_index)
{
va_list argp;
va_start(argp, num_local_textures);
// Read in local textures
for (U8 i=0; i < num_local_textures; i++)
{
ETextureIndex t = (ETextureIndex)va_arg(argp,int);
mLocalTextures.push_back(t);
}
// Read in number of wearables
const U32 num_wearables = (U32)va_arg(argp,int);
// Read in wearables
for (U8 i=0; i < num_wearables; i++)
{
LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int);
mWearables.push_back(t);
}
va_end(argp);
}
ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) const
{
return getBakedTexture(index)->mTextureIndex;
}
EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name)
{
U8 index = 0;
while (index < BAKED_NUM_INDICES)
{
const BakedEntry *be = getBakedTexture((EBakedTextureIndex) index);
if (be && be->mName.compare(name) == 0)
{
// baked texture found
return (EBakedTextureIndex) index;
}
index++;
}
// baked texture could not be found
return BAKED_NUM_INDICES;
}
EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::string name)
{
U8 index = 0;
while (index < BAKED_NUM_INDICES)
{
const BakedEntry *be = getBakedTexture((EBakedTextureIndex) index);
if (be)
{
const TextureEntry *te = getTexture(be->mTextureIndex);
if (te && te->mDefaultImageName.compare(name) == 0)
{
// baked texture found
return (EBakedTextureIndex) index;
}
}
index++;
}
// baked texture could not be found
return BAKED_NUM_INDICES;
}
LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIndex index ) const
{
auto* tex = getTexture(index);
return tex ? tex->mWearableType : LLWearableType::WT_INVALID;
}
// static
bool LLAvatarAppearanceDictionary::isBakedImageId(const LLUUID& id)
{
if ((id == IMG_USE_BAKED_EYES) || (id == IMG_USE_BAKED_HAIR) || (id == IMG_USE_BAKED_HEAD) || (id == IMG_USE_BAKED_LOWER) || (id == IMG_USE_BAKED_SKIRT) || (id == IMG_USE_BAKED_UPPER)
|| (id == IMG_USE_BAKED_LEFTARM) || (id == IMG_USE_BAKED_LEFTLEG) || (id == IMG_USE_BAKED_AUX1) || (id == IMG_USE_BAKED_AUX2) || (id == IMG_USE_BAKED_AUX3) )
{
return true;
}
return false;
}
// static
EBakedTextureIndex LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(const LLUUID& id)
{
if (id == IMG_USE_BAKED_EYES)
{
return BAKED_EYES;
}
else if (id == IMG_USE_BAKED_HAIR)
{
return BAKED_HAIR;
}
else if (id == IMG_USE_BAKED_HEAD)
{
return BAKED_HEAD;
}
else if (id == IMG_USE_BAKED_LOWER)
{
return BAKED_LOWER;
}
else if (id == IMG_USE_BAKED_SKIRT)
{
return BAKED_SKIRT;
}
else if (id == IMG_USE_BAKED_UPPER)
{
return BAKED_UPPER;
}
else if (id == IMG_USE_BAKED_LEFTARM)
{
return BAKED_LEFT_ARM;
}
else if (id == IMG_USE_BAKED_LEFTLEG)
{
return BAKED_LEFT_LEG;
}
else if (id == IMG_USE_BAKED_AUX1)
{
return BAKED_AUX1;
}
else if (id == IMG_USE_BAKED_AUX2)
{
return BAKED_AUX2;
}
else if (id == IMG_USE_BAKED_AUX3)
{
return BAKED_AUX3;
}
return BAKED_NUM_INDICES;
}
//static
LLUUID LLAvatarAppearanceDictionary::localTextureIndexToMagicId(ETextureIndex t)
{
LLUUID id = LLUUID::null;
switch (t)
{
case LLAvatarAppearanceDefines::TEX_HEAD_BAKED:
id = IMG_USE_BAKED_HEAD;
break;
case LLAvatarAppearanceDefines::TEX_UPPER_BAKED:
id = IMG_USE_BAKED_UPPER;
break;
case LLAvatarAppearanceDefines::TEX_LOWER_BAKED:
id = IMG_USE_BAKED_LOWER;
break;
case LLAvatarAppearanceDefines::TEX_EYES_BAKED:
id = IMG_USE_BAKED_EYES;
break;
case LLAvatarAppearanceDefines::TEX_SKIRT_BAKED:
id = IMG_USE_BAKED_SKIRT;
break;
case LLAvatarAppearanceDefines::TEX_HAIR_BAKED:
id = IMG_USE_BAKED_HAIR;
break;
case LLAvatarAppearanceDefines::TEX_LEFT_ARM_BAKED:
id = IMG_USE_BAKED_LEFTARM;
break;
case LLAvatarAppearanceDefines::TEX_LEFT_LEG_BAKED:
id = IMG_USE_BAKED_LEFTLEG;
break;
case LLAvatarAppearanceDefines::TEX_AUX1_BAKED:
id = IMG_USE_BAKED_AUX1;
break;
case LLAvatarAppearanceDefines::TEX_AUX2_BAKED:
id = IMG_USE_BAKED_AUX2;
break;
case LLAvatarAppearanceDefines::TEX_AUX3_BAKED:
id = IMG_USE_BAKED_AUX3;
break;
default:
break;
}
return id;
}
@@ -0,0 +1,255 @@
/**
* @file llavatarappearancedefines.h
* @brief Various LLAvatarAppearance related definitions
* LLViewerObject
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_AVATARAPPEARANCE_DEFINES_H
#define LL_AVATARAPPEARANCE_DEFINES_H
#include <vector>
#include "lljointpickname.h"
#include "lldictionary.h"
#include "llwearabletype.h"
#include "lluuid.h"
namespace LLAvatarAppearanceDefines
{
extern const S32 SCRATCH_TEX_WIDTH;
extern const S32 SCRATCH_TEX_HEIGHT;
static constexpr U32 AVATAR_HOVER = 11001;
//--------------------------------------------------------------------
// Enums
//--------------------------------------------------------------------
enum ETextureIndex
{
TEX_INVALID = -1,
TEX_HEAD_BODYPAINT = 0,
TEX_UPPER_SHIRT,
TEX_LOWER_PANTS,
TEX_EYES_IRIS,
TEX_HAIR,
TEX_UPPER_BODYPAINT,
TEX_LOWER_BODYPAINT,
TEX_LOWER_SHOES,
TEX_HEAD_BAKED, // Pre-composited
TEX_UPPER_BAKED, // Pre-composited
TEX_LOWER_BAKED, // Pre-composited
TEX_EYES_BAKED, // Pre-composited
TEX_LOWER_SOCKS,
TEX_UPPER_JACKET,
TEX_LOWER_JACKET,
TEX_UPPER_GLOVES,
TEX_UPPER_UNDERSHIRT,
TEX_LOWER_UNDERPANTS,
TEX_SKIRT,
TEX_SKIRT_BAKED, // Pre-composited
TEX_HAIR_BAKED, // Pre-composited
TEX_LOWER_ALPHA,
TEX_UPPER_ALPHA,
TEX_HEAD_ALPHA,
TEX_EYES_ALPHA,
TEX_HAIR_ALPHA,
TEX_HEAD_TATTOO,
TEX_UPPER_TATTOO,
TEX_LOWER_TATTOO,
TEX_HEAD_UNIVERSAL_TATTOO,
TEX_UPPER_UNIVERSAL_TATTOO,
TEX_LOWER_UNIVERSAL_TATTOO,
TEX_SKIRT_TATTOO,
TEX_HAIR_TATTOO,
TEX_EYES_TATTOO,
TEX_LEFT_ARM_TATTOO,
TEX_LEFT_LEG_TATTOO,
TEX_AUX1_TATTOO,
TEX_AUX2_TATTOO,
TEX_AUX3_TATTOO,
TEX_LEFT_ARM_BAKED, // Pre-composited
TEX_LEFT_LEG_BAKED, // Pre-composited
TEX_AUX1_BAKED, // Pre-composited
TEX_AUX2_BAKED, // Pre-composited
TEX_AUX3_BAKED, // Pre-composited
TEX_NUM_INDICES
};
enum EBakedTextureIndex
{
BAKED_HEAD = 0,
BAKED_UPPER,
BAKED_LOWER,
BAKED_EYES,
BAKED_SKIRT,
BAKED_HAIR,
BAKED_LEFT_ARM,
BAKED_LEFT_LEG,
BAKED_AUX1,
BAKED_AUX2,
BAKED_AUX3,
BAKED_NUM_INDICES
};
// Reference IDs for each mesh. Used as indices for vector of joints
enum EMeshIndex
{
MESH_ID_HAIR = 0,
MESH_ID_HEAD,
MESH_ID_EYELASH,
MESH_ID_UPPER_BODY,
MESH_ID_LOWER_BODY,
MESH_ID_EYEBALL_LEFT,
MESH_ID_EYEBALL_RIGHT,
MESH_ID_SKIRT,
MESH_ID_NUM_INDICES
};
//--------------------------------------------------------------------
// Vector Types
//--------------------------------------------------------------------
typedef std::vector<ETextureIndex> texture_vec_t;
typedef std::vector<EBakedTextureIndex> bakedtexture_vec_t;
typedef std::vector<EMeshIndex> mesh_vec_t;
typedef std::vector<LLWearableType::EType> wearables_vec_t;
//------------------------------------------------------------------------
// LLAvatarAppearanceDictionary
//
// Holds dictionary static entries for textures, baked textures, meshes, etc.; i.e.
// information that is common to all avatars.
//
// This holds const data - it is initialized once and the contents never change after that.
//------------------------------------------------------------------------
class LLAvatarAppearanceDictionary
{
//--------------------------------------------------------------------
// Constructors and Destructors
//--------------------------------------------------------------------
public:
LLAvatarAppearanceDictionary();
~LLAvatarAppearanceDictionary();
private:
void createAssociations();
//--------------------------------------------------------------------
// Local and baked textures
//--------------------------------------------------------------------
public:
struct TextureEntry : public LLDictionaryEntry
{
TextureEntry(const std::string &name, // this must match the xml name used by LLTexLayerInfo::parseXml
bool is_local_texture,
EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES,
const std::string& default_image_name = "",
LLWearableType::EType wearable_type = LLWearableType::WT_INVALID);
const std::string mDefaultImageName;
const LLWearableType::EType mWearableType;
// It's either a local texture xor baked
bool mIsLocalTexture;
bool mIsBakedTexture;
// If it's a local texture, it may be used by a baked texture
bool mIsUsedByBakedTexture;
EBakedTextureIndex mBakedTextureIndex;
};
struct Textures : public LLDictionary<ETextureIndex, TextureEntry>
{
Textures();
} mTextures;
const TextureEntry* getTexture(ETextureIndex index) const { return mTextures.lookup(index); }
const Textures& getTextures() const { return mTextures; }
//--------------------------------------------------------------------
// Meshes
//--------------------------------------------------------------------
public:
struct MeshEntry : public LLDictionaryEntry
{
MeshEntry(EBakedTextureIndex baked_index,
const std::string &name, // names of mesh types as they are used in avatar_lad.xml
U8 level,
LLJointPickName pick);
// Levels of Detail for each mesh. Must match levels of detail present in avatar_lad.xml
// Otherwise meshes will be unable to be found, or levels of detail will be ignored
const U8 mLOD;
const EBakedTextureIndex mBakedID;
const LLJointPickName mPickName;
};
struct MeshEntries : public LLDictionary<EMeshIndex, MeshEntry>
{
MeshEntries();
} mMeshEntries;
const MeshEntry* getMeshEntry(EMeshIndex index) const { return mMeshEntries.lookup(index); }
const MeshEntries& getMeshEntries() const { return mMeshEntries; }
//--------------------------------------------------------------------
// Baked Textures
//--------------------------------------------------------------------
public:
struct BakedEntry : public LLDictionaryEntry
{
BakedEntry(ETextureIndex tex_index,
const std::string &name, // unused, but necessary for templating.
const std::string &hash_name,
U32 num_local_textures, ... ); // # local textures, local texture list, # wearables, wearable list
// Local Textures
const ETextureIndex mTextureIndex;
texture_vec_t mLocalTextures;
// Wearables
const LLUUID mWearablesHashID;
wearables_vec_t mWearables;
};
struct BakedTextures: public LLDictionary<EBakedTextureIndex, BakedEntry>
{
BakedTextures();
} mBakedTextures;
const BakedEntry* getBakedTexture(EBakedTextureIndex index) const { return mBakedTextures.lookup(index); }
const BakedTextures& getBakedTextures() const { return mBakedTextures; }
//--------------------------------------------------------------------
// Convenience Functions
//--------------------------------------------------------------------
public:
// Convert from baked texture to associated texture; e.g. BAKED_HEAD -> TEX_HEAD_BAKED
ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t) const;
// find a baked texture index based on its name
EBakedTextureIndex findBakedByRegionName(std::string name);
EBakedTextureIndex findBakedByImageName(std::string name);
// Given a texture entry, determine which wearable type owns it.
LLWearableType::EType getTEWearableType(ETextureIndex index) const;
static bool isBakedImageId(const LLUUID& id);
static EBakedTextureIndex assetIdToBakedTextureIndex(const LLUUID& id);
static LLUUID localTextureIndexToMagicId(ETextureIndex t);
}; // End LLAvatarAppearanceDictionary
} // End namespace LLAvatarAppearanceDefines
#endif //LL_AVATARAPPEARANCE_DEFINES_H
+316
View File
@@ -0,0 +1,316 @@
/**
* @file llavatarjoint.cpp
* @brief Implementation of LLAvatarJoint class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "llavatarjoint.h"
#include "llgl.h"
#include "llrender.h"
#include "llmath.h"
#include "llglheaders.h"
#include "llavatarappearance.h"
const F32 DEFAULT_AVATAR_JOINT_LOD = 0.0f;
//-----------------------------------------------------------------------------
// Static Data
//-----------------------------------------------------------------------------
bool LLAvatarJoint::sDisableLOD = false;
//-----------------------------------------------------------------------------
// LLAvatarJoint()
// Class Constructors
//-----------------------------------------------------------------------------
LLAvatarJoint::LLAvatarJoint() :
LLJoint()
{
init();
}
LLAvatarJoint::LLAvatarJoint(S32 joint_num) :
LLJoint(joint_num)
{
init();
}
LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) :
LLJoint(name, parent)
{
init();
}
void LLAvatarJoint::init()
{
mValid = false;
mComponents = SC_JOINT | SC_BONE | SC_AXES;
mMinPixelArea = DEFAULT_AVATAR_JOINT_LOD;
mPickName = PN_DEFAULT;
mVisible = true;
mMeshID = 0;
mIsTransparent = false;
}
//-----------------------------------------------------------------------------
// ~LLAvatarJoint()
// Class Destructor
//-----------------------------------------------------------------------------
LLAvatarJoint::~LLAvatarJoint()
{
}
//--------------------------------------------------------------------
// setValid()
//--------------------------------------------------------------------
void LLAvatarJoint::setValid( bool valid, bool recursive )
{
//----------------------------------------------------------------
// set visibility for this joint
//----------------------------------------------------------------
mValid = valid;
//----------------------------------------------------------------
// set visibility for children
//----------------------------------------------------------------
if (recursive)
{
for (LLJoint* child : mChildren)
{
LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
joint->setValid(valid, true);
}
}
}
//--------------------------------------------------------------------
// setSkeletonComponents()
//--------------------------------------------------------------------
void LLAvatarJoint::setSkeletonComponents( U32 comp, bool recursive )
{
mComponents = comp;
if (recursive)
{
for (auto child : mChildren)
{
LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
joint->setSkeletonComponents(comp, recursive);
}
}
}
void LLAvatarJoint::setVisible(bool visible, bool recursive)
{
mVisible = visible;
if (recursive)
{
for (LLJoint* child : mChildren)
{
LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
joint->setVisible(visible, recursive);
}
}
}
void LLAvatarJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area)
{
for (LLJoint* child : mChildren)
{
LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
joint->updateFaceSizes(num_vertices, num_indices, pixel_area);
}
}
void LLAvatarJoint::updateFaceData(LLFace *face, F32 pixel_area, bool damp_wind, bool terse_update)
{
for (LLJoint* child : mChildren)
{
LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
joint->updateFaceData(face, pixel_area, damp_wind, terse_update);
}
}
void LLAvatarJoint::updateJointGeometry()
{
for (LLJoint* child : mChildren)
{
LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
joint->updateJointGeometry();
}
}
bool LLAvatarJoint::updateLOD(F32 pixel_area, bool activate)
{
bool lod_changed = false;
bool found_lod = false;
for (LLJoint* child : mChildren)
{
LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
F32 jointLOD = joint->getLOD();
if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD)
{
// we've already found a joint to enable, so enable the rest as alternatives
lod_changed |= joint->updateLOD(pixel_area, true);
}
else
{
if (pixel_area >= jointLOD || sDisableLOD)
{
lod_changed |= joint->updateLOD(pixel_area, true);
found_lod = true;
}
else
{
lod_changed |= joint->updateLOD(pixel_area, false);
}
}
}
return lod_changed;
}
void LLAvatarJoint::dump()
{
for (LLJoint* child : mChildren)
{
LLAvatarJoint* joint = static_cast<LLAvatarJoint*>(child);
joint->dump();
}
}
void LLAvatarJoint::setMeshesToChildren()
{
removeAllChildren();
for (LLAvatarJointMesh* mesh : mMeshParts)
{
addChild(mesh);
}
}
//-----------------------------------------------------------------------------
// LLAvatarJointCollisionVolume()
//-----------------------------------------------------------------------------
LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume()
{
mUpdateXform = false;
}
/*virtual*/
U32 LLAvatarJointCollisionVolume::render( F32 pixelArea, bool first_pass, bool is_dummy )
{
LL_ERRS() << "Cannot call render() on LLAvatarJointCollisionVolume" << LL_ENDL;
return 0;
}
LLVector3 LLAvatarJointCollisionVolume::getVolumePos(LLVector3 &offset)
{
mUpdateXform = true;
LLVector3 result = offset;
result.scaleVec(getScale());
result.rotVec(getWorldRotation());
result += getWorldPosition();
return result;
}
void LLAvatarJointCollisionVolume::renderCollision()
{
updateWorldMatrix();
gGL.pushMatrix();
gGL.multMatrix( &mXform.getWorldMatrix().mMatrix[0][0] );
gGL.diffuseColor3f( 0.f, 0.f, 1.f );
gGL.begin(LLRender::LINES);
LLVector3 v[] =
{
LLVector3(1,0,0),
LLVector3(-1,0,0),
LLVector3(0,1,0),
LLVector3(0,-1,0),
LLVector3(0,0,-1),
LLVector3(0,0,1),
};
//sides
gGL.vertex3fv(v[0].mV);
gGL.vertex3fv(v[2].mV);
gGL.vertex3fv(v[0].mV);
gGL.vertex3fv(v[3].mV);
gGL.vertex3fv(v[1].mV);
gGL.vertex3fv(v[2].mV);
gGL.vertex3fv(v[1].mV);
gGL.vertex3fv(v[3].mV);
//top
gGL.vertex3fv(v[0].mV);
gGL.vertex3fv(v[4].mV);
gGL.vertex3fv(v[1].mV);
gGL.vertex3fv(v[4].mV);
gGL.vertex3fv(v[2].mV);
gGL.vertex3fv(v[4].mV);
gGL.vertex3fv(v[3].mV);
gGL.vertex3fv(v[4].mV);
//bottom
gGL.vertex3fv(v[0].mV);
gGL.vertex3fv(v[5].mV);
gGL.vertex3fv(v[1].mV);
gGL.vertex3fv(v[5].mV);
gGL.vertex3fv(v[2].mV);
gGL.vertex3fv(v[5].mV);
gGL.vertex3fv(v[3].mV);
gGL.vertex3fv(v[5].mV);
gGL.end();
gGL.popMatrix();
}
// End
+140
View File
@@ -0,0 +1,140 @@
/**
* @file llavatarjoint.h
* @brief Implementation of LLAvatarJoint class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLAVATARJOINT_H
#define LL_LLAVATARJOINT_H
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "lljoint.h"
#include "lljointpickname.h"
class LLFace;
class LLAvatarJointMesh;
extern const F32 DEFAULT_AVATAR_JOINT_LOD;
//-----------------------------------------------------------------------------
// class LLViewerJoint
//-----------------------------------------------------------------------------
class LLAvatarJoint :
public LLJoint
{
public:
LLAvatarJoint();
LLAvatarJoint(S32 joint_num);
// *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform*
LLAvatarJoint(const std::string &name, LLJoint *parent = NULL);
virtual ~LLAvatarJoint();
// Gets the validity of this joint
bool getValid() { return mValid; }
// Sets the validity of this joint
virtual void setValid( bool valid, bool recursive=false );
// Returns true if this object is transparent.
// This is used to determine in which order to draw objects.
virtual bool isTransparent() { return mIsTransparent; }
// Returns true if this object should inherit scale modifiers from its immediate parent
virtual bool inheritScale() { return false; }
enum Components
{
SC_BONE = 1,
SC_JOINT = 2,
SC_AXES = 4
};
// Selects which skeleton components to draw
void setSkeletonComponents( U32 comp, bool recursive = true );
// Returns which skeleton components are enables for drawing
U32 getSkeletonComponents() { return mComponents; }
// Sets the level of detail for this node as a minimum
// pixel area threshold. If the current pixel area for this
// object is less than the specified threshold, the node is
// not traversed. In addition, if a value is specified (not
// default of 0.0), and the pixel area is larger than the
// specified minimum, the node is rendered, but no other siblings
// of this node under the same parent will be.
F32 getLOD() { return mMinPixelArea; }
void setLOD( F32 pixelArea ) { mMinPixelArea = pixelArea; }
void setPickName(LLJointPickName name) { mPickName = name; }
LLJointPickName getPickName() { return mPickName; }
void setVisible( bool visible, bool recursive );
// Takes meshes in mMeshParts and sets each one as a child joint
void setMeshesToChildren();
// LLViewerJoint interface
virtual U32 render( F32 pixelArea, bool first_pass = true, bool is_dummy = false ) = 0;
virtual void updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area);
virtual void updateFaceData(LLFace *face, F32 pixel_area, bool damp_wind = false, bool terse_update = false);
virtual bool updateLOD(F32 pixel_area, bool activate);
virtual void updateJointGeometry();
virtual void dump();
public:
static bool sDisableLOD;
avatar_joint_mesh_list_t mMeshParts; //LLViewerJointMesh*
void setMeshID( S32 id ) {mMeshID = id;}
protected:
void init();
bool mValid;
bool mIsTransparent;
U32 mComponents;
F32 mMinPixelArea;
LLJointPickName mPickName;
bool mVisible;
S32 mMeshID;
};
class LLAvatarJointCollisionVolume : public LLAvatarJoint
{
public:
LLAvatarJointCollisionVolume();
virtual ~LLAvatarJointCollisionVolume() {};
/*virtual*/ bool inheritScale() { return true; }
/*virtual*/ U32 render( F32 pixelArea, bool first_pass = true, bool is_dummy = false );
void renderCollision();
LLVector3 getVolumePos(LLVector3 &offset);
};
#endif // LL_LLAVATARJOINT_H
+390
View File
@@ -0,0 +1,390 @@
/**
* @file LLAvatarJointMesh.cpp
* @brief Implementation of LLAvatarJointMesh class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "linden_common.h"
#include "llfasttimer.h"
#include "llrender.h"
#include "llavatarjointmesh.h"
#include "llavatarappearance.h"
#include "lltexlayer.h"
#include "llmath.h"
#include "v4math.h"
#include "m3math.h"
#include "m4math.h"
#include "llmatrix4a.h"
// Utility functions added with Bento to simplify handling of extra
// spine joints, or other new joints internal to the original
// skeleton, and unknown to the system avatar.
//-----------------------------------------------------------------------------
// getBaseSkeletonAncestor()
//-----------------------------------------------------------------------------
LLAvatarJoint *getBaseSkeletonAncestor(LLAvatarJoint* joint)
{
LLJoint *ancestor = joint->getParent();
while (ancestor->getParent() && (ancestor->getSupport() != LLJoint::SUPPORT_BASE))
{
LL_DEBUGS("Avatar") << "skipping non-base ancestor " << ancestor->getName() << LL_ENDL;
ancestor = ancestor->getParent();
}
return (LLAvatarJoint*) ancestor;
}
//-----------------------------------------------------------------------------
// totalSkinOffset()
//-----------------------------------------------------------------------------
LLVector3 totalSkinOffset(LLAvatarJoint *joint)
{
LLVector3 totalOffset;
while (joint)
{
if (joint->getSupport() == LLJoint::SUPPORT_BASE)
{
totalOffset += joint->getSkinOffset();
}
joint = (LLAvatarJoint*)joint->getParent();
}
return totalOffset;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLAvatarJointMesh::LLSkinJoint
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLSkinJoint
//-----------------------------------------------------------------------------
LLSkinJoint::LLSkinJoint()
{
mJoint = NULL;
}
//-----------------------------------------------------------------------------
// ~LLSkinJoint
//-----------------------------------------------------------------------------
LLSkinJoint::~LLSkinJoint()
{
mJoint = NULL;
}
//-----------------------------------------------------------------------------
// LLSkinJoint::setupSkinJoint()
//-----------------------------------------------------------------------------
bool LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint)
{
// find the named joint
mJoint = joint;
if ( !mJoint )
{
LL_INFOS() << "Can't find joint" << LL_ENDL;
}
// compute the inverse root skin matrix
mRootToJointSkinOffset = totalSkinOffset(joint);
mRootToJointSkinOffset = -mRootToJointSkinOffset;
//mRootToParentJointSkinOffset = totalSkinOffset((LLAvatarJoint*)joint->getParent());
mRootToParentJointSkinOffset = totalSkinOffset(getBaseSkeletonAncestor(joint));
mRootToParentJointSkinOffset = -mRootToParentJointSkinOffset;
return true;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLAvatarJointMesh
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool LLAvatarJointMesh::sPipelineRender = false;
U32 LLAvatarJointMesh::sClothingMaskImageName = 0;
LLColor4 LLAvatarJointMesh::sClothingInnerColor;
//-----------------------------------------------------------------------------
// LLAvatarJointMesh()
//-----------------------------------------------------------------------------
LLAvatarJointMesh::LLAvatarJointMesh()
:
mTexture( NULL ),
mLayerSet( NULL ),
mTestImageName( 0 ),
mFaceIndexCount(0)
{
mColor[0] = 1.0f;
mColor[1] = 1.0f;
mColor[2] = 1.0f;
mColor[3] = 1.0f;
mShiny = 0.0f;
mCullBackFaces = true;
mMesh = NULL;
mNumSkinJoints = 0;
mSkinJoints = NULL;
mFace = NULL;
mMeshID = 0;
mUpdateXform = false;
mValid = false;
mIsTransparent = false;
}
//-----------------------------------------------------------------------------
// ~LLAvatarJointMesh()
// Class Destructor
//-----------------------------------------------------------------------------
LLAvatarJointMesh::~LLAvatarJointMesh()
{
mMesh = NULL;
mTexture = NULL;
freeSkinData();
}
//-----------------------------------------------------------------------------
// LLAvatarJointMesh::allocateSkinData()
//-----------------------------------------------------------------------------
bool LLAvatarJointMesh::allocateSkinData( U32 numSkinJoints )
{
mSkinJoints = new LLSkinJoint[ numSkinJoints ];
mNumSkinJoints = numSkinJoints;
return true;
}
//-----------------------------------------------------------------------------
// LLAvatarJointMesh::freeSkinData()
//-----------------------------------------------------------------------------
void LLAvatarJointMesh::freeSkinData()
{
mNumSkinJoints = 0;
delete [] mSkinJoints;
mSkinJoints = NULL;
}
//--------------------------------------------------------------------
// LLAvatarJointMesh::getColor()
//--------------------------------------------------------------------
void LLAvatarJointMesh::getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha )
{
*red = mColor[0];
*green = mColor[1];
*blue = mColor[2];
*alpha = mColor[3];
}
//--------------------------------------------------------------------
// LLAvatarJointMesh::setColor()
//--------------------------------------------------------------------
void LLAvatarJointMesh::setColor( F32 red, F32 green, F32 blue, F32 alpha )
{
mColor[0] = red;
mColor[1] = green;
mColor[2] = blue;
mColor[3] = alpha;
}
void LLAvatarJointMesh::setColor( const LLColor4& color )
{
mColor = color;
}
//--------------------------------------------------------------------
// LLAvatarJointMesh::getTexture()
//--------------------------------------------------------------------
//LLViewerTexture *LLAvatarJointMesh::getTexture()
//{
// return mTexture;
//}
//--------------------------------------------------------------------
// LLAvatarJointMesh::setTexture()
//--------------------------------------------------------------------
void LLAvatarJointMesh::setTexture( LLGLTexture *texture )
{
mTexture = texture;
// texture and dynamic_texture are mutually exclusive
if( texture )
{
mLayerSet = NULL;
//texture->bindTexture(0);
//texture->setClamp(true, true);
}
}
bool LLAvatarJointMesh::hasGLTexture() const
{
return mTexture.notNull() && mTexture->hasGLTexture();
}
//--------------------------------------------------------------------
// LLAvatarJointMesh::setLayerSet()
// Sets the shape texture (takes precedence over normal texture)
//--------------------------------------------------------------------
void LLAvatarJointMesh::setLayerSet( LLTexLayerSet* layer_set )
{
mLayerSet = layer_set;
// texture and dynamic_texture are mutually exclusive
if( layer_set )
{
mTexture = NULL;
}
}
bool LLAvatarJointMesh::hasComposite() const
{
return (mLayerSet && mLayerSet->hasComposite());
}
//--------------------------------------------------------------------
// LLAvatarJointMesh::getMesh()
//--------------------------------------------------------------------
LLPolyMesh *LLAvatarJointMesh::getMesh()
{
return mMesh;
}
//-----------------------------------------------------------------------------
// LLAvatarJointMesh::setMesh()
//-----------------------------------------------------------------------------
void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
{
// set the mesh pointer
mMesh = mesh;
// release any existing skin joints
freeSkinData();
if ( mMesh == NULL )
{
return;
}
// acquire the transform from the mesh object
// SL-315
setPosition( mMesh->getPosition() );
setRotation( mMesh->getRotation() );
setScale( mMesh->getScale() );
// create skin joints if necessary
if ( mMesh->hasWeights() && !mMesh->isLOD())
{
U32 numJointNames = mMesh->getNumJointNames();
allocateSkinData( numJointNames );
std::string *jointNames = mMesh->getJointNames();
U32 jn;
for (jn = 0; jn < numJointNames; jn++)
{
//LL_INFOS() << "Setting up joint " << jointNames[jn] << LL_ENDL;
LLAvatarJoint* joint = (LLAvatarJoint*)(getRoot()->findJoint(jointNames[jn]) );
mSkinJoints[jn].setupSkinJoint( joint );
}
}
// setup joint array
if (!mMesh->isLOD())
{
setupJoint((LLAvatarJoint*)getRoot());
LL_DEBUGS("Avatar") << getName() << " joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL;
}
}
//-----------------------------------------------------------------------------
// setupJoint()
//-----------------------------------------------------------------------------
void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
{
U32 sj;
for (sj=0; sj<mNumSkinJoints; sj++)
{
LLSkinJoint &js = mSkinJoints[sj];
if (js.mJoint != current_joint)
{
continue;
}
// we've found a skinjoint for this joint..
LL_DEBUGS("Avatar") << "Mesh: " << getName() << " joint " << current_joint->getName() << " matches skinjoint " << sj << LL_ENDL;
// is the last joint in the array our parent?
std::vector<LLJointRenderData*> &jrd = mMesh->mJointRenderData;
// SL-287 - need to update this so the results are the same if
// additional extended-skeleton joints lie between this joint
// and the original parent.
LLJoint *ancestor = getBaseSkeletonAncestor(current_joint);
if(jrd.size() && jrd.back()->mWorldMatrix == &ancestor->getWorldMatrix())
{
// ...then just add ourselves
LLAvatarJoint* jointp = js.mJoint;
jrd.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
LL_DEBUGS("Avatar") << "add joint[" << (jrd.size()-1) << "] = " << js.mJoint->getName() << LL_ENDL;
}
// otherwise add our ancestor and ourselves
else
{
jrd.push_back(new LLJointRenderData(&ancestor->getWorldMatrix(), NULL));
LL_DEBUGS("Avatar") << "add2 ancestor joint[" << (jrd.size()-1) << "] = " << ancestor->getName() << LL_ENDL;
jrd.push_back(new LLJointRenderData(&current_joint->getWorldMatrix(), &js));
LL_DEBUGS("Avatar") << "add2 joint[" << (jrd.size()-1) << "] = " << current_joint->getName() << LL_ENDL;
}
}
// depth-first traversal
for (LLJoint* joint : current_joint->mChildren)
{
LLAvatarJoint* child_joint = (LLAvatarJoint*)joint;
setupJoint(child_joint);
}
}
// End
+141
View File
@@ -0,0 +1,141 @@
/**
* @file llavatarjointmesh.h
* @brief Declaration of LLAvatarJointMesh class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLAVATARJOINTMESH_H
#define LL_LLAVATARJOINTMESH_H
#include "llavatarjoint.h"
#include "llgltexture.h"
#include "llpolymesh.h"
#include "v4color.h"
class LLDrawable;
class LLFace;
class LLCharacter;
class LLTexLayerSet;
typedef enum e_avatar_render_pass
{
AVATAR_RENDER_PASS_SINGLE,
AVATAR_RENDER_PASS_CLOTHING_INNER,
AVATAR_RENDER_PASS_CLOTHING_OUTER
} EAvatarRenderPass;
class LLSkinJoint
{
public:
LLSkinJoint();
~LLSkinJoint();
bool setupSkinJoint( LLAvatarJoint *joint);
LLAvatarJoint *mJoint;
LLVector3 mRootToJointSkinOffset;
LLVector3 mRootToParentJointSkinOffset;
};
//-----------------------------------------------------------------------------
// class LLViewerJointMesh
//-----------------------------------------------------------------------------
class LLAvatarJointMesh : public virtual LLAvatarJoint
{
protected:
LLColor4 mColor; // color value
// LLColor4 mSpecular; // specular color (always white for now)
F32 mShiny; // shiny value
LLPointer<LLGLTexture> mTexture; // ptr to a global texture
LLTexLayerSet* mLayerSet; // ptr to a layer set owned by the avatar
U32 mTestImageName; // handle to a temporary texture for previewing uploads
LLPolyMesh* mMesh; // ptr to a global polymesh
bool mCullBackFaces; // true by default
LLFace* mFace; // ptr to a face w/ AGP copy of mesh
U32 mFaceIndexCount;
U32 mNumSkinJoints;
LLSkinJoint* mSkinJoints;
S32 mMeshID;
public:
static bool sPipelineRender;
//RN: this is here for testing purposes
static U32 sClothingMaskImageName;
static LLColor4 sClothingInnerColor;
public:
// Constructor
LLAvatarJointMesh();
// Destructor
virtual ~LLAvatarJointMesh();
// Gets the shape color
void getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha );
// Sets the shape color
void setColor( F32 red, F32 green, F32 blue, F32 alpha );
void setColor( const LLColor4& color );
// Sets the shininess
void setSpecular( const LLColor4& color, F32 shiny ) { /*mSpecular = color;*/ mShiny = shiny; };
// Sets the shape texture
void setTexture( LLGLTexture *texture );
bool hasGLTexture() const;
void setTestTexture( U32 name ) { mTestImageName = name; }
// Sets layer set responsible for a dynamic shape texture (takes precedence over normal texture)
void setLayerSet( LLTexLayerSet* layer_set );
bool hasComposite() const;
// Gets the poly mesh
LLPolyMesh *getMesh();
// Sets the poly mesh
void setMesh( LLPolyMesh *mesh );
// Sets up joint matrix data for rendering
void setupJoint(LLAvatarJoint* current_joint);
// Sets ID for picking
void setMeshID( S32 id ) {mMeshID = id;}
// Gets ID for picking
S32 getMeshID() { return mMeshID; }
void setIsTransparent(bool is_transparent) { mIsTransparent = is_transparent; }
private:
// Allocate skin data
bool allocateSkinData( U32 numSkinJoints );
// Free skin data
void freeSkinData();
};
#endif // LL_LLAVATARJOINTMESH_H
+657
View File
@@ -0,0 +1,657 @@
/**
* @file lldriverparam.cpp
* @brief A visual parameter that drives (controls) other visual parameters.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "lldriverparam.h"
#include "llavatarappearance.h"
#include "llwearable.h"
#include "llwearabledata.h"
//-----------------------------------------------------------------------------
// LLDriverParamInfo
//-----------------------------------------------------------------------------
LLDriverParamInfo::LLDriverParamInfo() :
mDriverParam(NULL)
{
}
bool LLDriverParamInfo::parseXml(LLXmlTreeNode* node)
{
llassert( node->hasName( "param" ) && node->getChildByName( "param_driver" ) );
if( !LLViewerVisualParamInfo::parseXml( node ))
return false;
LLXmlTreeNode* param_driver_node = node->getChildByName( "param_driver" );
if( !param_driver_node )
return false;
for (LLXmlTreeNode* child = param_driver_node->getChildByName( "driven" );
child;
child = param_driver_node->getNextNamedChild())
{
S32 driven_id;
static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
if( child->getFastAttributeS32( id_string, driven_id ) )
{
F32 min1 = mMinWeight;
F32 max1 = mMaxWeight;
F32 max2 = max1;
F32 min2 = max1;
// driven ________ //
// ^ /| |\ //
// | / | | \ //
// | / | | \ //
// | / | | \ //
// | / | | \ //
//-------|----|-------|----|-------> driver //
// | min1 max1 max2 min2
static LLStdStringHandle min1_string = LLXmlTree::addAttributeString("min1");
child->getFastAttributeF32( min1_string, min1 ); // optional
static LLStdStringHandle max1_string = LLXmlTree::addAttributeString("max1");
child->getFastAttributeF32( max1_string, max1 ); // optional
static LLStdStringHandle max2_string = LLXmlTree::addAttributeString("max2");
child->getFastAttributeF32( max2_string, max2 ); // optional
static LLStdStringHandle min2_string = LLXmlTree::addAttributeString("min2");
child->getFastAttributeF32( min2_string, min2 ); // optional
// Push these on the front of the deque, so that we can construct
// them in order later (faster)
mDrivenInfoList.push_front( LLDrivenEntryInfo( driven_id, min1, max1, max2, min2 ) );
}
else
{
LL_ERRS() << "<driven> Unable to resolve driven parameter: " << driven_id << LL_ENDL;
return false;
}
}
return true;
}
//virtual
void LLDriverParamInfo::toStream(std::ostream &out)
{
LLViewerVisualParamInfo::toStream(out);
out << "driver" << "\t";
out << mDrivenInfoList.size() << "\t";
for (LLDrivenEntryInfo& driven : mDrivenInfoList)
{
out << driven.mDrivenID << "\t";
}
out << std::endl;
// FIXME - this mDriverParam backlink makes no sense, because the
// LLDriverParamInfos are static objects - there's only one copy
// for each param type, so the backlink will just reference the
// corresponding param in the most recently created
// avatar. Apparently these toStream() methods are not currently
// used anywhere, so it's not an urgent problem.
LL_WARNS_ONCE() << "Invalid usage of mDriverParam." << LL_ENDL;
if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() &&
mDriverParam->getAvatarAppearance()->isValid())
{
for (LLDrivenEntryInfo& driven : mDrivenInfoList)
{
LLViewerVisualParam *param =
(LLViewerVisualParam*)mDriverParam->getAvatarAppearance()->getVisualParam(driven.mDrivenID);
if (param)
{
param->getInfo()->toStream(out);
if (param->getWearableType() != mWearableType)
{
if(param->getCrossWearable())
{
out << "cross-wearable" << "\t";
}
else
{
out << "ERROR!" << "\t";
}
}
else
{
out << "valid" << "\t";
}
}
else
{
LL_WARNS() << "could not get parameter " << driven.mDrivenID << " from avatar "
<< mDriverParam->getAvatarAppearance()
<< " for driver parameter " << getID() << LL_ENDL;
}
out << std::endl;
}
}
}
//-----------------------------------------------------------------------------
// LLDriverParam
//-----------------------------------------------------------------------------
LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */)
: LLViewerVisualParam(),
mDefaultVec(),
mDriven(),
mCurrentDistortionParam( NULL ),
mAvatarAppearance(appearance),
mWearablep(wearable)
{
llassert(mAvatarAppearance);
llassert((mWearablep == NULL) || mAvatarAppearance->isSelf());
mDefaultVec.clear();
}
LLDriverParam::LLDriverParam(const LLDriverParam& pOther)
: LLViewerVisualParam(pOther),
mDefaultVec(pOther.mDefaultVec),
mDriven(pOther.mDriven),
mCurrentDistortionParam(pOther.mCurrentDistortionParam),
mAvatarAppearance(pOther.mAvatarAppearance),
mWearablep(pOther.mWearablep)
{
llassert(mAvatarAppearance);
llassert((mWearablep == NULL) || mAvatarAppearance->isSelf());
}
LLDriverParam::~LLDriverParam()
{
}
bool LLDriverParam::setInfo(LLDriverParamInfo *info)
{
llassert(mInfo == NULL);
if (info->mID < 0)
return false;
mInfo = info;
mID = info->mID;
info->mDriverParam = this;
// <FS:Ansariel> [Legacy Bake]
//setWeight(getDefaultWeight());
setWeight(getDefaultWeight(), false );
return true;
}
/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const
{
llassert(wearable);
return new LLDriverParam(*this);
}
// <FS:Ansariel> [Legacy Bake]
//void LLDriverParam::setWeight(F32 weight)
void LLDriverParam::setWeight(F32 weight, bool upload_bake)
// </FS:Ansariel> [Legacy Bake]
{
F32 min_weight = getMinWeight();
F32 max_weight = getMaxWeight();
if (mIsAnimating)
{
// allow overshoot when animating
mCurWeight = weight;
}
else
{
mCurWeight = llclamp(weight, min_weight, max_weight);
}
// driven ________
// ^ /| |\ ^
// | / | | \ |
// | / | | \ |
// | / | | \ |
// | / | | \ |
//-------|----|-------|----|-------> driver
// | min1 max1 max2 min2
for(LLDrivenEntry& driven : mDriven)
{
LLDrivenEntry* drivenp = &driven;
LLDrivenEntryInfo* info = drivenp->mInfo;
F32 driven_weight = 0.f;
F32 driven_min = drivenp->mParam->getMinWeight();
F32 driven_max = drivenp->mParam->getMaxWeight();
if (mIsAnimating)
{
// driven param doesn't interpolate (textures, for example)
if (!drivenp->mParam->getAnimating())
{
continue;
}
if( mCurWeight < info->mMin1 )
{
if (info->mMin1 == min_weight)
{
if (info->mMin1 == info->mMax1)
{
driven_weight = driven_max;
}
else
{
//up slope extrapolation
F32 t = (mCurWeight - info->mMin1) / (info->mMax1 - info->mMin1 );
driven_weight = driven_min + t * (driven_max - driven_min);
}
}
else
{
driven_weight = driven_min;
}
// <FS:Ansariel> [Legacy Bake]
//setDrivenWeight(drivenp,driven_weight);
setDrivenWeight(drivenp,driven_weight,upload_bake);
// </FS:Ansariel> [Legacy Bake]
continue;
}
else
if ( mCurWeight > info->mMin2 )
{
if (info->mMin2 == max_weight)
{
if (info->mMin2 == info->mMax2)
{
driven_weight = driven_max;
}
else
{
//down slope extrapolation
F32 t = (mCurWeight - info->mMax2) / (info->mMin2 - info->mMax2 );
driven_weight = driven_max + t * (driven_min - driven_max);
}
}
else
{
driven_weight = driven_min;
}
// <FS:Ansariel> [Legacy Bake]
//setDrivenWeight(drivenp,driven_weight);
setDrivenWeight(drivenp,driven_weight,upload_bake);
// </FS:Ansariel> [Legacy Bake]
continue;
}
}
driven_weight = getDrivenWeight(drivenp, mCurWeight);
// <FS:Ansariel> [Legacy Bake]
//setDrivenWeight(drivenp,driven_weight);
setDrivenWeight(drivenp,driven_weight, upload_bake);
}
}
F32 LLDriverParam::getTotalDistortion()
{
F32 sum = 0.f;
for(LLDrivenEntry& driven : mDriven)
{
sum += driven.mParam->getTotalDistortion();
}
return sum;
}
const LLVector4a &LLDriverParam::getAvgDistortion()
{
// It's not actually correct to take the average of averages, but it good enough here.
LLVector4a sum;
sum.clear();
S32 count = 0;
for(LLDrivenEntry& driven : mDriven)
{
sum.add(driven.mParam->getAvgDistortion());
count++;
}
sum.mul( 1.f/(F32)count);
mDefaultVec = sum;
return mDefaultVec;
}
F32 LLDriverParam::getMaxDistortion()
{
F32 max = 0.f;
for(LLDrivenEntry& driven : mDriven)
{
F32 param_max = driven.mParam->getMaxDistortion();
if( param_max > max )
{
max = param_max;
}
}
return max;
}
LLVector4a LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)
{
LLVector4a sum;
sum.clear();
for(LLDrivenEntry& driven : mDriven)
{
sum.add(driven.mParam->getVertexDistortion(index, poly_mesh));
}
return sum;
}
const LLVector4a* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
{
mCurrentDistortionParam = NULL;
const LLVector4a* v = NULL;
for(LLDrivenEntry& driven : mDriven)
{
v = driven.mParam->getFirstDistortion(index, poly_mesh);
if( v )
{
mCurrentDistortionParam = driven.mParam;
break;
}
}
return v;
};
const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
{
llassert( mCurrentDistortionParam );
if( !mCurrentDistortionParam )
{
return NULL;
}
LLDrivenEntry* driven = NULL;
entry_list_t::iterator iter;
// Set mDriven iteration to the right point
for( iter = mDriven.begin(); iter != mDriven.end(); iter++ )
{
driven = &(*iter);
if( driven->mParam == mCurrentDistortionParam )
{
break;
}
}
llassert(driven);
if (!driven)
{
return NULL; // shouldn't happen, but...
}
// We're already in the middle of a param's distortions, so get the next one.
const LLVector4a* v = driven->mParam->getNextDistortion( index, poly_mesh );
if( (!v) && (iter != mDriven.end()) )
{
// This param is finished, so start the next param. It might not have any
// distortions, though, so we have to loop to find the next param that does.
for( iter++; iter != mDriven.end(); iter++ )
{
driven = &(*iter);
v = driven->mParam->getFirstDistortion(index, poly_mesh);
if( v )
{
mCurrentDistortionParam = driven->mParam;
break;
}
}
}
return v;
};
S32 LLDriverParam::getDrivenParamsCount() const
{
return static_cast<S32>(mDriven.size());
}
const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const
{
if (0 > index || index >= mDriven.size())
{
return NULL;
}
return mDriven[index].mParam;
}
//-----------------------------------------------------------------------------
// setAnimationTarget()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//void LLDriverParam::setAnimationTarget( F32 target_value)
//{
// LLVisualParam::setAnimationTarget(target_value);
void LLDriverParam::setAnimationTarget( F32 target_value, bool upload_bake )
{
LLVisualParam::setAnimationTarget(target_value, upload_bake);
// </FS:Ansariel> [Legacy Bake]
for(LLDrivenEntry& driven : mDriven)
{
LLDrivenEntry* drivenp = &driven;
F32 driven_weight = getDrivenWeight(drivenp, mTargetWeight);
// this isn't normally necessary, as driver params handle interpolation of their driven params
// but texture params need to know to assume their final value at beginning of interpolation
// <FS:Ansariel> [Legacy Bake]
//drivenp->mParam->setAnimationTarget(driven_weight);
drivenp->mParam->setAnimationTarget(driven_weight, upload_bake);
// </FS:Ansariel> [Legacy Bake]
}
}
//-----------------------------------------------------------------------------
// stopAnimating()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//void LLDriverParam::stopAnimating()
//{
// LLVisualParam::stopAnimating();
void LLDriverParam::stopAnimating(bool upload_bake)
{
LLVisualParam::stopAnimating(upload_bake);
// </FS:Ansariel> [Legacy Bake]
for(LLDrivenEntry& driven : mDriven)
{
driven.mParam->setAnimating(false);
}
}
/*virtual*/
bool LLDriverParam::linkDrivenParams(visual_param_mapper mapper, bool only_cross_params)
{
bool success = true;
for (LLDrivenEntryInfo& driven_info : getInfo()->mDrivenInfoList)
{
S32 driven_id = driven_info.mDrivenID;
// check for already existing links. Do not overwrite.
bool found = false;
for (auto& driven : mDriven)
{
if (driven.mInfo->mDrivenID == driven_id)
{
found = true;
}
}
if (!found)
{
LLViewerVisualParam* param = (LLViewerVisualParam*)mapper(driven_id);
if (param) param->setParamLocation(this->getParamLocation());
bool push = param && (!only_cross_params || param->getCrossWearable());
if (push)
{
mDriven.push_back(LLDrivenEntry( param, &driven_info ));
}
else
{
success = false;
}
}
}
return success;
}
void LLDriverParam::resetDrivenParams()
{
mDriven.clear();
mDriven.reserve(getInfo()->mDrivenInfoList.size());
}
void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
{
bool needs_update = (getWearableType()==driven_type);
// if the driver has a driven entry for the passed-in wearable type, we need to refresh the value
for(LLDrivenEntry& driven : mDriven)
{
if (driven.mParam && driven.mParam->getCrossWearable() && driven.mParam->getWearableType() == driven_type)
{
needs_update = true;
}
}
if (needs_update)
{
LLWearableType::EType driver_type = (LLWearableType::EType)getWearableType();
// If we've gotten here, we've added a new wearable of type "type"
// Thus this wearable needs to get updates from the driver wearable.
// The call to setVisualParamWeight seems redundant, but is necessary
// as the number of driven wearables has changed since the last update. -Nyx
LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type);
if (wearable)
{
// <FS:Ansariel> [Legacy Bake]
//wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID));
wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false);
}
}
}
//-----------------------------------------------------------------------------
// getDrivenWeight()
//-----------------------------------------------------------------------------
F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight)
{
F32 min_weight = getMinWeight();
F32 max_weight = getMaxWeight();
const LLDrivenEntryInfo* info = driven->mInfo;
F32 driven_weight = 0.f;
F32 driven_min = driven->mParam->getMinWeight();
F32 driven_max = driven->mParam->getMaxWeight();
if( input_weight <= info->mMin1 )
{
if( info->mMin1 == info->mMax1 &&
info->mMin1 <= min_weight)
{
driven_weight = driven_max;
}
else
{
driven_weight = driven_min;
}
}
else
if( input_weight <= info->mMax1 )
{
F32 t = (input_weight - info->mMin1) / (info->mMax1 - info->mMin1 );
driven_weight = driven_min + t * (driven_max - driven_min);
}
else
if( input_weight <= info->mMax2 )
{
driven_weight = driven_max;
}
else
if( input_weight <= info->mMin2 )
{
F32 t = (input_weight - info->mMax2) / (info->mMin2 - info->mMax2 );
driven_weight = driven_max + t * (driven_min - driven_max);
}
else
{
if (info->mMax2 >= max_weight)
{
driven_weight = driven_max;
}
else
{
driven_weight = driven_min;
}
}
return driven_weight;
}
// <FS:Ansariel> [Legacy Bake]
//void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight)
void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake)
// </FS:Ansariel> [Legacy Bake]
{
bool use_self = false;
if(mWearablep &&
mAvatarAppearance->isValid() &&
driven->mParam->getCrossWearable())
{
LLWearable* wearable = mWearablep;
if (mAvatarAppearance->getWearableData()->isOnTop(wearable))
{
use_self = true;
}
}
if (use_self)
{
// call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values
// <FS:Ansariel> [Legacy Bake]
//mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight);
mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake);
}
else
{
// <FS:Ansariel> [Legacy Bake]
//driven->mParam->setWeight( driven_weight);
driven->mParam->setWeight( driven_weight, upload_bake);
}
}
+147
View File
@@ -0,0 +1,147 @@
/**
* @file lldriverparam.h
* @brief A visual parameter that drives (controls) other visual parameters.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLDRIVERPARAM_H
#define LL_LLDRIVERPARAM_H
#include "llviewervisualparam.h"
#include "llwearabletype.h"
#include <deque>
class LLAvatarAppearance;
class LLDriverParam;
class LLWearable;
//-----------------------------------------------------------------------------
struct LLDrivenEntryInfo
{
LLDrivenEntryInfo( S32 id, F32 min1, F32 max1, F32 max2, F32 min2 )
: mDrivenID( id ), mMin1( min1 ), mMax1( max1 ), mMax2( max2 ), mMin2( min2 ) {}
S32 mDrivenID;
F32 mMin1;
F32 mMax1;
F32 mMax2;
F32 mMin2;
};
struct LLDrivenEntry
{
LLDrivenEntry( LLViewerVisualParam* param, LLDrivenEntryInfo *info )
: mParam( param ), mInfo( info ) {}
LLViewerVisualParam* mParam;
LLDrivenEntryInfo* mInfo;
};
//-----------------------------------------------------------------------------
class LLDriverParamInfo : public LLViewerVisualParamInfo
{
friend class LLDriverParam;
public:
LLDriverParamInfo();
/*virtual*/ ~LLDriverParamInfo() {};
/*virtual*/ bool parseXml(LLXmlTreeNode* node);
/*virtual*/ void toStream(std::ostream &out);
protected:
typedef std::deque<LLDrivenEntryInfo> entry_info_list_t;
entry_info_list_t mDrivenInfoList;
LLDriverParam* mDriverParam; // backpointer
};
//-----------------------------------------------------------------------------
class alignas(16) LLDriverParam : public LLViewerVisualParam
{
LL_ALIGN_NEW
private:
// Hide the default constructor. Force construction with LLAvatarAppearance.
LLDriverParam() {}
public:
LLDriverParam(LLAvatarAppearance* appearance, LLWearable* wearable = NULL);
~LLDriverParam();
// Special: These functions are overridden by child classes
LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; }
// This sets mInfo and calls initialization functions
bool setInfo(LLDriverParamInfo* info);
LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
void updateCrossDrivenParams(LLWearableType::EType driven_type);
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
// LLVisualParam Virtual functions
/*virtual*/ void apply(ESex sex) {} // apply is called separately for each driven param.
// <FS:Ansariel> [Legacy Bake]
///*virtual*/ void setWeight(F32 weight);
///*virtual*/ void setAnimationTarget(F32 target_value);
///*virtual*/ void stopAnimating();
/*virtual*/ void setWeight(F32 weight, bool upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, bool upload_bake);
/*virtual*/ void stopAnimating(bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
/*virtual*/ bool linkDrivenParams(visual_param_mapper mapper, bool only_cross_params);
/*virtual*/ void resetDrivenParams();
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion();
/*virtual*/ const LLVector4a& getAvgDistortion();
/*virtual*/ F32 getMaxDistortion();
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh* poly_mesh);
/*virtual*/ const LLVector4a* getFirstDistortion(U32* index, LLPolyMesh** poly_mesh);
/*virtual*/ const LLVector4a* getNextDistortion(U32* index, LLPolyMesh** poly_mesh);
S32 getDrivenParamsCount() const;
const LLViewerVisualParam* getDrivenParam(S32 index) const;
typedef std::vector<LLDrivenEntry> entry_list_t;
entry_list_t& getDrivenList() { return mDriven; }
void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; }
protected:
LLDriverParam(const LLDriverParam& pOther);
F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
// <FS:Ansariel> [Legacy Bake]
//void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight);
void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight, bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
entry_list_t mDriven;
LLViewerVisualParam* mCurrentDistortionParam{ nullptr };
// Backlink only; don't make this an LLPointer.
LLAvatarAppearance* mAvatarAppearance{ nullptr };
LLWearable* mWearablep{ nullptr };
};
#endif // LL_LLDRIVERPARAM_H
+49
View File
@@ -0,0 +1,49 @@
/**
* @file lljointpickname.h
* @brief Defines OpenGL seleciton stack names
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLJOINTPICKNAME_H
#define LL_LLJOINTPICKNAME_H
class LLAvatarJointMesh;
// Sets the OpenGL selection stack name that is pushed and popped
// with this joint state. The default value indicates that no name
// should be pushed/popped.
enum LLJointPickName
{
PN_DEFAULT = -1,
PN_0 = 0,
PN_1 = 1,
PN_2 = 2,
PN_3 = 3,
PN_4 = 4,
PN_5 = 5
};
typedef std::vector<LLAvatarJointMesh*> avatar_joint_mesh_list_t;
#endif // LL_LLJOINTPICKNAME_H
+212
View File
@@ -0,0 +1,212 @@
/**
* @file lllocaltextureobject.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 "lllocaltextureobject.h"
#include "llimage.h"
#include "llrender.h"
#include "lltexlayer.h"
#include "llgltexture.h"
#include "lluuid.h"
#include "llwearable.h"
LLLocalTextureObject::LLLocalTextureObject() :
mIsBakedReady(false),
mDiscard(MAX_DISCARD_LEVEL+1)
{
mImage = NULL;
}
LLLocalTextureObject::LLLocalTextureObject(LLGLTexture* image, const LLUUID& id) :
mIsBakedReady(false),
mDiscard(MAX_DISCARD_LEVEL+1)
{
mImage = image;
gGL.getTexUnit(0)->bind(mImage);
mID = id;
}
LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) :
mImage(lto.mImage),
mID(lto.mID),
mIsBakedReady(lto.mIsBakedReady),
mDiscard(lto.mDiscard)
{
U32 num_layers = lto.getNumTexLayers();
mTexLayers.reserve(num_layers);
for (U32 index = 0; index < num_layers; index++)
{
LLTexLayer* original_layer = lto.getTexLayer(index);
if (!original_layer)
{
LL_ERRS() << "could not clone Local Texture Object: unable to extract texlayer!" << LL_ENDL;
continue;
}
LLTexLayer* new_layer = new LLTexLayer(*original_layer);
new_layer->setLTO(this);
mTexLayers.push_back(new_layer);
}
}
LLLocalTextureObject::~LLLocalTextureObject()
{
delete_and_clear(mTexLayers);
}
LLGLTexture* LLLocalTextureObject::getImage() const
{
return mImage;
}
LLTexLayer* LLLocalTextureObject::getTexLayer(U32 index) const
{
if (index >= getNumTexLayers())
{
return NULL;
}
return mTexLayers[index];
}
LLTexLayer* LLLocalTextureObject::getTexLayer(const std::string &name)
{
for(LLTexLayer* layer : mTexLayers)
{
if (layer->getName().compare(name) == 0)
{
return layer;
}
}
return NULL;
}
U32 LLLocalTextureObject::getNumTexLayers() const
{
return static_cast<U32>(mTexLayers.size());
}
LLUUID LLLocalTextureObject::getID() const
{
return mID;
}
S32 LLLocalTextureObject::getDiscard() const
{
return mDiscard;
}
bool LLLocalTextureObject::getBakedReady() const
{
return mIsBakedReady;
}
void LLLocalTextureObject::setImage(LLGLTexture* new_image)
{
mImage = new_image;
}
bool LLLocalTextureObject::setTexLayer(LLTexLayer *new_tex_layer, U32 index)
{
if (index >= getNumTexLayers() )
{
return false;
}
if (new_tex_layer == NULL)
{
return removeTexLayer(index);
}
LLTexLayer *layer = new LLTexLayer(*new_tex_layer);
layer->setLTO(this);
if (mTexLayers[index])
{
delete mTexLayers[index];
}
mTexLayers[index] = layer;
return true;
}
bool LLLocalTextureObject::addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable)
{
if (new_tex_layer == NULL)
{
return false;
}
LLTexLayer *layer = new LLTexLayer(*new_tex_layer, wearable);
layer->setLTO(this);
mTexLayers.push_back(layer);
return true;
}
bool LLLocalTextureObject::addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable)
{
if (new_tex_layer == NULL)
{
return false;
}
LLTexLayer *layer = new LLTexLayer(*new_tex_layer, this, wearable);
layer->setLTO(this);
mTexLayers.push_back(layer);
return true;
}
bool LLLocalTextureObject::removeTexLayer(U32 index)
{
if (index >= getNumTexLayers())
{
return false;
}
tex_layer_vec_t::iterator iter = mTexLayers.begin();
iter += index;
delete *iter;
mTexLayers.erase(iter);
return true;
}
void LLLocalTextureObject::setID(LLUUID new_id)
{
mID = new_id;
}
void LLLocalTextureObject::setDiscard(S32 new_discard)
{
mDiscard = new_discard;
}
void LLLocalTextureObject::setBakedReady(bool ready)
{
mIsBakedReady = ready;
}
+84
View File
@@ -0,0 +1,84 @@
/**
* @file lllocaltextureobject.h
* @brief LLLocalTextureObject class header file
*
* $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 LL_LOCALTEXTUREOBJECT_H
#define LL_LOCALTEXTUREOBJECT_H
#include "llpointer.h"
#include "llgltexture.h"
class LLTexLayer;
class LLTexLayerTemplate;
class LLWearable;
// Stores all relevant information for a single texture
// assumed to have ownership of all objects referred to -
// will delete objects when being replaced or if object is destroyed.
class LLLocalTextureObject
{
public:
LLLocalTextureObject();
LLLocalTextureObject(LLGLTexture* image, const LLUUID& id);
LLLocalTextureObject(const LLLocalTextureObject& lto);
~LLLocalTextureObject();
LLGLTexture* getImage() const;
LLTexLayer* getTexLayer(U32 index) const;
LLTexLayer* getTexLayer(const std::string &name);
U32 getNumTexLayers() const;
LLUUID getID() const;
S32 getDiscard() const;
bool getBakedReady() const;
void setImage(LLGLTexture* new_image);
bool setTexLayer(LLTexLayer *new_tex_layer, U32 index);
bool addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable);
bool addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable);
bool removeTexLayer(U32 index);
void setID(LLUUID new_id);
void setDiscard(S32 new_discard);
void setBakedReady(bool ready);
protected:
private:
LLPointer<LLGLTexture> mImage;
// NOTE: LLLocalTextureObject should be the exclusive owner of mTexEntry and mTexLayer
// using shared pointers here only for smart assignment & cleanup
// do NOT create new shared pointers to these objects, or keep pointers to them around
typedef std::vector<LLTexLayer*> tex_layer_vec_t;
tex_layer_vec_t mTexLayers;
LLUUID mID;
bool mIsBakedReady;
S32 mDiscard;
};
#endif // LL_LOCALTEXTUREOBJECT_H
File diff suppressed because it is too large Load Diff
+368
View File
@@ -0,0 +1,368 @@
/**
* @file llpolymesh.h
* @brief Implementation of LLPolyMesh class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLPOLYMESHINTERFACE_H
#define LL_LLPOLYMESHINTERFACE_H
#include <string>
#include <map>
#include "llstl.h"
#include "v3math.h"
#include "v2math.h"
#include "llquaternion.h"
#include "llpolymorph.h"
#include "lljoint.h"
class LLSkinJoint;
class LLAvatarAppearance;
class LLWearable;
//#define USE_STRIPS // Use tri-strips for rendering.
//-----------------------------------------------------------------------------
// LLPolyFace
// A set of 4 vertex indices.
// An LLPolyFace can represent either a triangle or quad.
// If the last index is -1, it's a triangle.
//-----------------------------------------------------------------------------
typedef S32 LLPolyFace[3];
//struct PrimitiveGroup;
//-----------------------------------------------------------------------------
// LLPolyMesh
// A polyhedra consisting of any number of triangles and quads.
// All instances contain a set of faces, and optionally may include
// faces grouped into named face sets.
//-----------------------------------------------------------------------------
class LLPolyMorphTarget;
class LLPolyMeshSharedData
{
friend class LLPolyMesh;
private:
// transform data
LLVector3 mPosition;
LLQuaternion mRotation;
LLVector3 mScale;
// vertex data
S32 mNumVertices;
LLVector4a *mBaseCoords;
LLVector4a *mBaseNormals;
LLVector4a *mBaseBinormals;
LLVector2 *mTexCoords;
LLVector2 *mDetailTexCoords;
F32 *mWeights;
bool mHasWeights;
bool mHasDetailTexCoords;
// face data
S32 mNumFaces;
LLPolyFace *mFaces;
// face set data
U32 mNumJointNames;
std::string* mJointNames;
// morph targets
typedef std::set<LLPolyMorphData*> morphdata_list_t;
morphdata_list_t mMorphData;
std::map<S32, S32> mSharedVerts;
LLPolyMeshSharedData* mReferenceData;
S32 mLastIndexOffset;
public:
// Temporarily...
// Triangle indices
U32 mNumTriangleIndices;
U32 *mTriangleIndices;
public:
LLPolyMeshSharedData();
~LLPolyMeshSharedData();
private:
void setupLOD(LLPolyMeshSharedData* reference_data);
// Frees all mesh memory resources
void freeMeshData();
void setPosition( const LLVector3 &pos ) { mPosition = pos; }
void setRotation( const LLQuaternion &rot ) { mRotation = rot; }
void setScale( const LLVector3 &scale ) { mScale = scale; }
bool allocateVertexData( U32 numVertices );
bool allocateFaceData( U32 numFaces );
bool allocateJointNames( U32 numJointNames );
// Retrieve the number of KB of memory used by this instance
U32 getNumKB();
// Load mesh data from file
bool loadMesh( const std::string& fileName );
public:
void genIndices(S32 offset);
const LLVector2 &getUVs(U32 index);
const S32 *getSharedVert(S32 vert);
bool isLOD() { return (mReferenceData != NULL); }
};
class LLJointRenderData
{
public:
LLJointRenderData(const LLMatrix4* world_matrix, LLSkinJoint* skin_joint) : mWorldMatrix(world_matrix), mSkinJoint(skin_joint) {}
~LLJointRenderData(){}
const LLMatrix4* mWorldMatrix;
LLSkinJoint* mSkinJoint;
};
class LLPolyMesh
{
public:
// Constructor
LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh);
// Destructor
~LLPolyMesh();
// Requests a mesh by name.
// If the mesh already exists in the global mesh table, it is returned,
// otherwise it is loaded from file, added to the table, and returned.
static LLPolyMesh *getMesh( const std::string &name, LLPolyMesh* reference_mesh = NULL);
// Frees all loaded meshes.
// This should only be called once you know there are no outstanding
// references to these objects. Generally, upon exit of the application.
static void freeAllMeshes();
//--------------------------------------------------------------------
// Transform Data Access
//--------------------------------------------------------------------
// Get position
const LLVector3 &getPosition() {
llassert (mSharedData);
return mSharedData->mPosition;
}
// Get rotation
const LLQuaternion &getRotation() {
llassert (mSharedData);
return mSharedData->mRotation;
}
// Get scale
const LLVector3 &getScale() {
llassert (mSharedData);
return mSharedData->mScale;
}
//--------------------------------------------------------------------
// Vertex Data Access
//--------------------------------------------------------------------
// Get number of vertices
U32 getNumVertices() {
llassert (mSharedData);
return mSharedData->mNumVertices;
}
// Returns whether or not the mesh has detail texture coords
bool hasDetailTexCoords() {
llassert (mSharedData);
return mSharedData->mHasDetailTexCoords;
}
// Returns whether or not the mesh has vertex weights
bool hasWeights() const{
llassert (mSharedData);
return mSharedData->mHasWeights;
}
// Get coords
const LLVector4a *getCoords() const{
return mCoords;
}
// non const version
LLVector4a *getWritableCoords();
// Get normals
const LLVector4a *getNormals() const{
return mNormals;
}
// Get normals
const LLVector4a *getBinormals() const{
return mBinormals;
}
// Get base mesh normals
const LLVector4a *getBaseNormals() const{
llassert(mSharedData);
return mSharedData->mBaseNormals;
}
// Get base mesh normals
const LLVector4a *getBaseBinormals() const{
llassert(mSharedData);
return mSharedData->mBaseBinormals;
}
// intermediate morphed normals and output normals
LLVector4a *getWritableNormals();
LLVector4a *getScaledNormals();
LLVector4a *getWritableBinormals();
LLVector4a *getScaledBinormals();
// Get texCoords
const LLVector2 *getTexCoords() const {
return mTexCoords;
}
// non const version
LLVector2 *getWritableTexCoords();
// Get detailTexCoords
const LLVector2 *getDetailTexCoords() const {
llassert (mSharedData);
return mSharedData->mDetailTexCoords;
}
// Get weights
const F32 *getWeights() const {
llassert (mSharedData);
return mSharedData->mWeights;
}
F32 *getWritableWeights() const;
LLVector4a *getWritableClothingWeights();
const LLVector4a *getClothingWeights()
{
return mClothingWeights;
}
//--------------------------------------------------------------------
// Face Data Access
//--------------------------------------------------------------------
// Get number of faces
S32 getNumFaces() {
llassert (mSharedData);
return mSharedData->mNumFaces;
}
// Get faces
LLPolyFace *getFaces() {
llassert (mSharedData);
return mSharedData->mFaces;
}
U32 getNumJointNames() {
llassert (mSharedData);
return mSharedData->mNumJointNames;
}
std::string *getJointNames() {
llassert (mSharedData);
return mSharedData->mJointNames;
}
LLPolyMorphData* getMorphData(const std::string& morph_name);
// void removeMorphData(LLPolyMorphData *morph_target);
// void deleteAllMorphData();
LLPolyMeshSharedData *getSharedData() const;
LLPolyMesh *getReferenceMesh() { return mReferenceMesh ? mReferenceMesh : this; }
// Get indices
U32* getIndices() { return mSharedData ? mSharedData->mTriangleIndices : NULL; }
bool isLOD() { return mSharedData && mSharedData->isLOD(); }
void setAvatar(LLAvatarAppearance* avatarp) { mAvatarp = avatarp; }
LLAvatarAppearance* getAvatar() { return mAvatarp; }
std::vector<LLJointRenderData*> mJointRenderData;
U32 mFaceVertexOffset;
U32 mFaceVertexCount;
U32 mFaceIndexOffset;
U32 mFaceIndexCount;
U32 mCurVertexCount;
private:
void initializeForMorph();
// Dumps diagnostic information about the global mesh table
static void dumpDiagInfo();
protected:
// mesh data shared across all instances of a given mesh
LLPolyMeshSharedData *mSharedData;
// Single array of floats for allocation / deletion
F32 *mVertexData;
// deformed vertices (resulting from application of morph targets)
LLVector4a *mCoords;
// deformed normals (resulting from application of morph targets)
LLVector4a *mScaledNormals;
// output normals (after normalization)
LLVector4a *mNormals;
// deformed binormals (resulting from application of morph targets)
LLVector4a *mScaledBinormals;
// output binormals (after normalization)
LLVector4a *mBinormals;
// weight values that mark verts as clothing/skin
LLVector4a *mClothingWeights;
// output texture coordinates
LLVector2 *mTexCoords;
LLPolyMesh *mReferenceMesh;
// global mesh list
typedef std::map<std::string, LLPolyMeshSharedData*> LLPolyMeshSharedDataTable;
static LLPolyMeshSharedDataTable sGlobalSharedMeshList;
// Backlink only; don't make this an LLPointer.
LLAvatarAppearance* mAvatarp;
};
#endif // LL_LLPOLYMESHINTERFACE_H
+846
View File
@@ -0,0 +1,846 @@
/**
* @file llpolymorph.cpp
* @brief Implementation of LLPolyMesh class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "llpolymorph.h"
#include "llavatarappearance.h"
#include "llavatarjoint.h"
#include "llwearable.h"
#include "llxmltree.h"
#include "llendianswizzle.h"
#include "llpolymesh.h"
#include "llfasttimer.h"
//#include "../tools/imdebug/imdebug.h"
const F32 NORMAL_SOFTEN_FACTOR = 0.65f;
//-----------------------------------------------------------------------------
// LLPolyMorphData()
//-----------------------------------------------------------------------------
LLPolyMorphData::LLPolyMorphData(const std::string& morph_name)
: mName(morph_name)
{
mNumIndices = 0;
mCurrentIndex = 0;
mTotalDistortion = 0.f;
mAvgDistortion.clear();
mMaxDistortion = 0.f;
mVertexIndices = NULL;
mCoords = NULL;
mNormals = NULL;
mBinormals = NULL;
mTexCoords = NULL;
mMesh = NULL;
}
LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) :
mName(rhs.mName),
mNumIndices(rhs.mNumIndices),
mTotalDistortion(rhs.mTotalDistortion),
mAvgDistortion(rhs.mAvgDistortion),
mMaxDistortion(rhs.mMaxDistortion),
mVertexIndices(NULL),
mCoords(NULL),
mNormals(NULL),
mBinormals(NULL),
mTexCoords(NULL)
{
const S32 numVertices = mNumIndices;
U32 size = sizeof(LLVector4a)*numVertices;
mCoords = static_cast<LLVector4a*>( ll_aligned_malloc_16(size) );
mNormals = static_cast<LLVector4a*>( ll_aligned_malloc_16(size) );
mBinormals = static_cast<LLVector4a*>( ll_aligned_malloc_16(size) );
mTexCoords = new LLVector2[numVertices];
mVertexIndices = new U32[numVertices];
for (S32 v=0; v < numVertices; v++)
{
mCoords[v] = rhs.mCoords[v];
mNormals[v] = rhs.mNormals[v];
mBinormals[v] = rhs.mBinormals[v];
mTexCoords[v] = rhs.mTexCoords[v];
mVertexIndices[v] = rhs.mVertexIndices[v];
}
}
//-----------------------------------------------------------------------------
// ~LLPolyMorphData()
//-----------------------------------------------------------------------------
LLPolyMorphData::~LLPolyMorphData()
{
freeData();
}
//-----------------------------------------------------------------------------
// loadBinary()
//-----------------------------------------------------------------------------
bool LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
{
S32 numVertices;
size_t numRead;
numRead = fread(&numVertices, sizeof(S32), 1, fp);
llendianswizzle(&numVertices, sizeof(S32), 1);
if (numRead != 1)
{
LL_WARNS() << "Can't read number of morph target vertices" << LL_ENDL;
return false;
}
//-------------------------------------------------------------------------
// free any existing data
//-------------------------------------------------------------------------
freeData();
//-------------------------------------------------------------------------
// allocate vertices
//-------------------------------------------------------------------------
U32 size = sizeof(LLVector4a)*numVertices;
mCoords = static_cast<LLVector4a*>(ll_aligned_malloc_16(size));
mNormals = static_cast<LLVector4a*>(ll_aligned_malloc_16(size));
mBinormals = static_cast<LLVector4a*>(ll_aligned_malloc_16(size));
mTexCoords = new LLVector2[numVertices];
// Actually, we are allocating more space than we need for the skiplist
mVertexIndices = new U32[numVertices];
mNumIndices = 0;
mTotalDistortion = 0.f;
mMaxDistortion = 0.f;
mAvgDistortion.clear();
mMesh = mesh;
//-------------------------------------------------------------------------
// read vertices
//-------------------------------------------------------------------------
for(S32 v = 0; v < numVertices; v++)
{
numRead = fread(&mVertexIndices[v], sizeof(U32), 1, fp);
llendianswizzle(&mVertexIndices[v], sizeof(U32), 1);
if (numRead != 1)
{
LL_WARNS() << "Can't read morph target vertex number" << LL_ENDL;
return false;
}
if (mVertexIndices[v] > 10000)
{
// Bad install? These are usually .llm files from 'character' fodler
LL_WARNS() << "Bad morph index " << v << ": " << mVertexIndices[v] << LL_ENDL;
return false;
}
numRead = fread(&mCoords[v], sizeof(F32), 3, fp);
llendianswizzle(&mCoords[v], sizeof(F32), 3);
if (numRead != 3)
{
LL_WARNS() << "Can't read morph target vertex coordinates" << LL_ENDL;
return false;
}
F32 magnitude = mCoords[v].getLength3().getF32();
mTotalDistortion += magnitude;
LLVector4a t;
t.setAbs(mCoords[v]);
mAvgDistortion.add(t);
if (magnitude > mMaxDistortion)
{
mMaxDistortion = magnitude;
}
numRead = fread(&mNormals[v], sizeof(F32), 3, fp);
llendianswizzle(&mNormals[v], sizeof(F32), 3);
if (numRead != 3)
{
LL_WARNS() << "Can't read morph target normal" << LL_ENDL;
return false;
}
numRead = fread(&mBinormals[v], sizeof(F32), 3, fp);
llendianswizzle(&mBinormals[v], sizeof(F32), 3);
if (numRead != 3)
{
LL_WARNS() << "Can't read morph target binormal" << LL_ENDL;
return false;
}
numRead = fread(&mTexCoords[v].mV, sizeof(F32), 2, fp);
llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2);
if (numRead != 2)
{
LL_WARNS() << "Can't read morph target uv" << LL_ENDL;
return false;
}
mNumIndices++;
}
mAvgDistortion.mul(1.f/(F32)mNumIndices);
mAvgDistortion.normalize3fast();
return true;
}
//-----------------------------------------------------------------------------
// freeData()
//-----------------------------------------------------------------------------
void LLPolyMorphData::freeData()
{
if (mCoords != NULL)
{
ll_aligned_free_16(mCoords);
mCoords = NULL;
}
if (mNormals != NULL)
{
ll_aligned_free_16(mNormals);
mNormals = NULL;
}
if (mBinormals != NULL)
{
ll_aligned_free_16(mBinormals);
mBinormals = NULL;
}
if (mTexCoords != NULL)
{
delete [] mTexCoords;
mTexCoords = NULL;
}
if (mVertexIndices != NULL)
{
delete [] mVertexIndices;
mVertexIndices = NULL;
}
}
//-----------------------------------------------------------------------------
// LLPolyMorphTargetInfo()
//-----------------------------------------------------------------------------
LLPolyMorphTargetInfo::LLPolyMorphTargetInfo()
: mIsClothingMorph(false)
{
}
bool LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node)
{
llassert( node->hasName( "param" ) && node->getChildByName( "param_morph" ) );
if (!LLViewerVisualParamInfo::parseXml(node))
return false;
// Get mixed-case name
static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
if( !node->getFastAttributeString( name_string, mMorphName ) )
{
LL_WARNS() << "Avatar file: <param> is missing name attribute" << LL_ENDL;
return false; // Continue, ignoring this tag
}
static LLStdStringHandle clothing_morph_string = LLXmlTree::addAttributeString("clothing_morph");
node->getFastAttributeBOOL(clothing_morph_string, mIsClothingMorph);
LLXmlTreeNode *paramNode = node->getChildByName("param_morph");
if (NULL == paramNode)
{
LL_WARNS() << "Failed to getChildByName(\"param_morph\")"
<< LL_ENDL;
return false;
}
for (LLXmlTreeNode* child_node = paramNode->getFirstChild();
child_node;
child_node = paramNode->getNextChild())
{
static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
if (child_node->hasName("volume_morph"))
{
std::string volume_name;
if (child_node->getFastAttributeString(name_string, volume_name))
{
LLVector3 scale;
static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
child_node->getFastAttributeVector3(scale_string, scale);
LLVector3 pos;
static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
child_node->getFastAttributeVector3(pos_string, pos);
mVolumeInfoList.push_back(LLPolyVolumeMorphInfo(volume_name,scale,pos));
}
}
}
return true;
}
//-----------------------------------------------------------------------------
// LLPolyMorphTarget()
//-----------------------------------------------------------------------------
LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh)
: LLViewerVisualParam(),
mMorphData(NULL),
mMesh(poly_mesh),
mVertMask(NULL),
mLastSex(SEX_FEMALE),
mNumMorphMasksPending(0),
mVolumeMorphs()
{
}
//-----------------------------------------------------------------------------
// LLPolyMorphTarget()
//-----------------------------------------------------------------------------
LLPolyMorphTarget::LLPolyMorphTarget(const LLPolyMorphTarget& pOther)
: LLViewerVisualParam(pOther),
mMorphData(pOther.mMorphData),
mMesh(pOther.mMesh),
mVertMask(pOther.mVertMask == NULL ? NULL : new LLPolyVertexMask(*pOther.mVertMask)),
mLastSex(pOther.mLastSex),
mNumMorphMasksPending(pOther.mNumMorphMasksPending),
mVolumeMorphs(pOther.mVolumeMorphs)
{
}
//-----------------------------------------------------------------------------
// ~LLPolyMorphTarget()
//-----------------------------------------------------------------------------
LLPolyMorphTarget::~LLPolyMorphTarget()
{
delete mVertMask;
mVertMask = NULL;
}
//-----------------------------------------------------------------------------
// setInfo()
//-----------------------------------------------------------------------------
bool LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
{
llassert(mInfo == NULL);
if (info->mID < 0)
return false;
mInfo = info;
mID = info->mID;
// <FS:Ansariel> [Legacy Bake]
//setWeight(getDefaultWeight());
setWeight(getDefaultWeight(), false);
LLAvatarAppearance* avatarp = mMesh->getAvatar();
for (LLPolyVolumeMorphInfo& volume_info : getInfo()->mVolumeInfoList)
{
for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++)
{
if (avatarp->mCollisionVolumes[i].getName() == volume_info.mName)
{
mVolumeMorphs.push_back(
LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i],
volume_info.mScale,
volume_info.mPos));
break;
}
}
}
std::string morph_param_name = getInfo()->mMorphName;
mMorphData = mMesh->getMorphData(morph_param_name);
if (!mMorphData)
{
const std::string driven_tag = "_Driven";
auto pos = morph_param_name.find(driven_tag);
if (pos != std::string::npos && pos > 0)
{
morph_param_name = morph_param_name.substr(0,pos);
mMorphData = mMesh->getMorphData(morph_param_name);
}
}
if (!mMorphData)
{
LL_WARNS() << "No morph target named " << morph_param_name << " found in mesh." << LL_ENDL;
return false; // Continue, ignoring this tag
}
return true;
}
/*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const
{
return new LLPolyMorphTarget(*this);
}
#if 0 // obsolete
//-----------------------------------------------------------------------------
// parseData()
//-----------------------------------------------------------------------------
bool LLPolyMorphTarget::parseData(LLXmlTreeNode* node)
{
LLPolyMorphTargetInfo* info = new LLPolyMorphTargetInfo;
info->parseXml(node);
if (!setInfo(info))
{
delete info;
return false;
}
return true;
}
#endif
//-----------------------------------------------------------------------------
// getVertexDistortion()
//-----------------------------------------------------------------------------
LLVector4a LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh)
{
if (!mMorphData || mMesh != mesh) return LLVector4a::getZero();
for(U32 index = 0; index < mMorphData->mNumIndices; index++)
{
if (mMorphData->mVertexIndices[index] == (U32)requested_index)
{
return mMorphData->mCoords[index];
}
}
return LLVector4a::getZero();
}
//-----------------------------------------------------------------------------
// getFirstDistortion()
//-----------------------------------------------------------------------------
const LLVector4a *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
{
if (!mMorphData) return &LLVector4a::getZero();
LLVector4a* resultVec;
mMorphData->mCurrentIndex = 0;
if (mMorphData->mNumIndices)
{
resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
if (index != NULL)
{
*index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
}
if (poly_mesh != NULL)
{
*poly_mesh = mMesh;
}
return resultVec;
}
return NULL;
}
//-----------------------------------------------------------------------------
// getNextDistortion()
//-----------------------------------------------------------------------------
const LLVector4a *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
{
if (!mMorphData) return &LLVector4a::getZero();
LLVector4a* resultVec;
mMorphData->mCurrentIndex++;
if (mMorphData->mCurrentIndex < mMorphData->mNumIndices)
{
resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
if (index != NULL)
{
*index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
}
if (poly_mesh != NULL)
{
*poly_mesh = mMesh;
}
return resultVec;
}
return NULL;
}
//-----------------------------------------------------------------------------
// getTotalDistortion()
//-----------------------------------------------------------------------------
F32 LLPolyMorphTarget::getTotalDistortion()
{
if (mMorphData)
{
return mMorphData->mTotalDistortion;
}
else
{
return 0.f;
}
}
//-----------------------------------------------------------------------------
// getAvgDistortion()
//-----------------------------------------------------------------------------
const LLVector4a& LLPolyMorphTarget::getAvgDistortion()
{
if (mMorphData)
{
return mMorphData->mAvgDistortion;
}
else
{
return LLVector4a::getZero();
}
}
//-----------------------------------------------------------------------------
// getMaxDistortion()
//-----------------------------------------------------------------------------
F32 LLPolyMorphTarget::getMaxDistortion()
{
if (mMorphData)
{
return mMorphData->mMaxDistortion;
}
else
{
return 0.f;
}
}
//-----------------------------------------------------------------------------
// apply()
//-----------------------------------------------------------------------------
void LLPolyMorphTarget::apply( ESex avatar_sex )
{
if (!mMorphData || mNumMorphMasksPending > 0)
{
return;
}
LL_PROFILE_ZONE_SCOPED;
mLastSex = avatar_sex;
// Check for NaN condition
if (llisnan(mCurWeight))
{
mCurWeight = 0.f;
}
if (llisnan(mLastWeight))
{
mLastWeight = mCurWeight+.001f;
}
// perform differential update of morph
F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight);
// store last weight
mLastWeight += delta_weight;
if (delta_weight != 0.f)
{
llassert(!mMesh->isLOD());
LLVector4a *coords = mMesh->getWritableCoords();
LLVector4a *scaled_normals = mMesh->getScaledNormals();
LLVector4a *normals = mMesh->getWritableNormals();
LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
LLVector4a *binormals = mMesh->getWritableBinormals();
LLVector4a *clothing_weights = mMesh->getWritableClothingWeights();
LLVector2 *tex_coords = mMesh->getWritableTexCoords();
F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++)
{
S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph];
F32 maskWeight = 1.f;
if (maskWeightArray)
{
maskWeight = maskWeightArray[vert_index_morph];
}
LLVector4a pos = mMorphData->mCoords[vert_index_morph];
pos.mul(delta_weight*maskWeight);
coords[vert_index_mesh].add(pos);
if (getInfo()->mIsClothingMorph && clothing_weights)
{
LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph];
clothing_offset.mul(delta_weight * maskWeight);
LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh];
clothing_weight->add(clothing_offset);
clothing_weight->getF32ptr()[VW] = maskWeight;
}
// calculate new normals based on half angles
LLVector4a norm = mMorphData->mNormals[vert_index_morph];
norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
scaled_normals[vert_index_mesh].add(norm);
norm = scaled_normals[vert_index_mesh];
// guard against degenerate input data before we create NaNs below!
//
norm.normalize3fast();
normals[vert_index_mesh] = norm;
// calculate new binormals
LLVector4a binorm = mMorphData->mBinormals[vert_index_morph];
// guard against degenerate input data before we create NaNs below!
//
if (!binorm.isFinite3() || (binorm.dot3(binorm).getF32() <= F_APPROXIMATELY_ZERO))
{
binorm.set(1,0,0,1);
}
binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
scaled_binormals[vert_index_mesh].add(binorm);
LLVector4a tangent;
tangent.setCross3(scaled_binormals[vert_index_mesh], norm);
LLVector4a& normalized_binormal = binormals[vert_index_mesh];
normalized_binormal.setCross3(norm, tangent);
normalized_binormal.normalize3fast();
tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight;
}
// now apply volume changes
for(LLPolyVolumeMorph& volume_morph : mVolumeMorphs)
{
LLVector3 scale_delta = volume_morph.mScale * delta_weight;
LLVector3 pos_delta = volume_morph.mPos * delta_weight;
volume_morph.mVolume->setScale(volume_morph.mVolume->getScale() + scale_delta);
// SL-315
volume_morph.mVolume->setPosition(volume_morph.mVolume->getPosition() + pos_delta);
}
}
if (mNext)
{
mNext->apply(avatar_sex);
}
}
//-----------------------------------------------------------------------------
// applyMask()
//-----------------------------------------------------------------------------
void LLPolyMorphTarget::applyMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, bool invert)
{
LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL;
if (!mVertMask)
{
mVertMask = new LLPolyVertexMask(mMorphData);
mNumMorphMasksPending--;
}
else
{
// remove effect of previous mask
F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
if (maskWeights)
{
LLVector4a *coords = mMesh->getWritableCoords();
LLVector4a *scaled_normals = mMesh->getScaledNormals();
LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
LLVector2 *tex_coords = mMesh->getWritableTexCoords();
LLVector4Logical clothing_mask;
clothing_mask.clear();
clothing_mask.setElement<0>();
clothing_mask.setElement<1>();
clothing_mask.setElement<2>();
for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++)
{
F32 lastMaskWeight = mLastWeight * maskWeights[vert];
S32 out_vert = mMorphData->mVertexIndices[vert];
// remove effect of existing masked morph
LLVector4a t;
t = mMorphData->mCoords[vert];
t.mul(lastMaskWeight);
coords[out_vert].sub(t);
t = mMorphData->mNormals[vert];
t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
scaled_normals[out_vert].sub(t);
t = mMorphData->mBinormals[vert];
t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
scaled_binormals[out_vert].sub(t);
tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight;
if (clothing_weights)
{
LLVector4a clothing_offset = mMorphData->mCoords[vert];
clothing_offset.mul(lastMaskWeight);
LLVector4a* clothing_weight = &clothing_weights[out_vert];
LLVector4a t;
t.setSub(*clothing_weight, clothing_offset);
clothing_weight->setSelectWithMask(clothing_mask, t, *clothing_weight);
}
}
}
}
// set last weight to 0, since we've removed the effect of this morph
mLastWeight = 0.f;
mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights);
apply(mLastSex);
}
void LLPolyMorphTarget::applyVolumeChanges(F32 delta_weight)
{
// now apply volume changes
for(LLPolyVolumeMorph& volume_morph : mVolumeMorphs)
{
LLVector3 scale_delta = volume_morph.mScale * delta_weight;
LLVector3 pos_delta = volume_morph.mPos * delta_weight;
volume_morph.mVolume->setScale(volume_morph.mVolume->getScale() + scale_delta);
// SL-315
volume_morph.mVolume->setPosition(volume_morph.mVolume->getPosition() + pos_delta);
}
}
//-----------------------------------------------------------------------------
// LLPolyVertexMask()
//-----------------------------------------------------------------------------
LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data)
: mWeights(new F32[morph_data->mNumIndices]),
mMorphData(morph_data),
mWeightsGenerated(false)
{
llassert(mMorphData != NULL);
llassert(mMorphData->mNumIndices > 0);
}
//-----------------------------------------------------------------------------
// LLPolyVertexMask()
//-----------------------------------------------------------------------------
LLPolyVertexMask::LLPolyVertexMask(const LLPolyVertexMask& pOther)
: mWeights(new F32[pOther.mMorphData->mNumIndices]),
mMorphData(pOther.mMorphData),
mWeightsGenerated(pOther.mWeightsGenerated)
{
llassert(mMorphData != NULL);
llassert(mMorphData->mNumIndices > 0);
memcpy(mWeights, pOther.mWeights, sizeof(F32) * mMorphData->mNumIndices);
}
//-----------------------------------------------------------------------------
// ~LLPolyVertexMask()
//-----------------------------------------------------------------------------
LLPolyVertexMask::~LLPolyVertexMask()
{
delete [] mWeights;
mWeights = NULL;
}
//-----------------------------------------------------------------------------
// generateMask()
//-----------------------------------------------------------------------------
void LLPolyVertexMask::generateMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, bool invert, LLVector4a *clothing_weights)
{
// RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/)
// bool debugImg = false;
// if (debugImg)
// {
// if (invert)
// {
// imdebug("lum rbga=rgba b=8 w=%d h=%d *-1 %p", width, height, maskTextureData);
// }
// else
// {
// imdebug("lum rbga=rgba b=8 w=%d h=%d %p", width, height, maskTextureData);
// }
// }
for (U32 index = 0; index < mMorphData->mNumIndices; index++)
{
S32 vertIndex = mMorphData->mVertexIndices[index];
const S32 *sharedVertIndex = mMorphData->mMesh->getSharedVert(vertIndex);
LLVector2 uvCoords;
if (sharedVertIndex)
{
uvCoords = mMorphData->mMesh->getUVs(*sharedVertIndex);
}
else
{
uvCoords = mMorphData->mMesh->getUVs(vertIndex);
}
U32 s = llclamp((U32)(uvCoords.mV[VX] * (F32)(width - 1)), (U32)0, (U32)width - 1);
U32 t = llclamp((U32)(uvCoords.mV[VY] * (F32)(height - 1)), (U32)0, (U32)height - 1);
mWeights[index] = maskTextureData ? ((F32) maskTextureData[((t * width + s) * num_components) + (num_components - 1)]) / 255.f : 0.0f;
if (invert)
{
mWeights[index] = 1.f - mWeights[index];
}
// now apply step function
// mWeights[index] = mWeights[index] > 0.95f ? 1.f : 0.f;
if (clothing_weights)
{
clothing_weights[vertIndex].getF32ptr()[VW] = mWeights[index];
}
}
mWeightsGenerated = true;
}
//-----------------------------------------------------------------------------
// getMaskForMorphIndex()
//-----------------------------------------------------------------------------
F32* LLPolyVertexMask::getMorphMaskWeights()
{
if (!mWeightsGenerated)
{
return NULL;
}
return mWeights;
}
+193
View File
@@ -0,0 +1,193 @@
/**
* @file llpolymorph.h
* @brief Implementation of LLPolyMesh class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLPOLYMORPH_H
#define LL_LLPOLYMORPH_H
#include <string>
#include <vector>
#include "llviewervisualparam.h"
class LLAvatarJointCollisionVolume;
class LLPolyMeshSharedData;
class LLVector2;
class LLAvatarJointCollisionVolume;
class LLWearable;
//-----------------------------------------------------------------------------
// LLPolyMorphData()
//-----------------------------------------------------------------------------
class alignas(16) LLPolyMorphData
{
LL_ALIGN_NEW
public:
LLPolyMorphData(const std::string& morph_name);
~LLPolyMorphData();
LLPolyMorphData(const LLPolyMorphData &rhs);
bool loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh);
const std::string& getName() { return mName; }
public:
std::string mName;
// morphology
U32 mNumIndices;
U32* mVertexIndices;
U32 mCurrentIndex;
LLVector4a* mCoords;
LLVector4a* mNormals;
LLVector4a* mBinormals;
LLVector2* mTexCoords;
F32 mTotalDistortion; // vertex distortion summed over entire morph
F32 mMaxDistortion; // maximum single vertex distortion in a given morph
LLVector4a mAvgDistortion; // average vertex distortion, to infer directionality of the morph
LLPolyMeshSharedData* mMesh;
private:
void freeData();
} LL_ALIGN_POSTFIX(16);
//-----------------------------------------------------------------------------
// LLPolyVertexMask()
//-----------------------------------------------------------------------------
class LLPolyVertexMask
{
public:
LLPolyVertexMask(LLPolyMorphData* morph_data);
LLPolyVertexMask(const LLPolyVertexMask& pOther);
~LLPolyVertexMask();
void generateMask(const U8 *maskData, S32 width, S32 height, S32 num_components, bool invert, LLVector4a *clothing_weights);
F32* getMorphMaskWeights();
protected:
F32* mWeights;
LLPolyMorphData *mMorphData;
bool mWeightsGenerated;
};
//-----------------------------------------------------------------------------
// LLPolyMorphTarget Data structs
//-----------------------------------------------------------------------------
struct LLPolyVolumeMorphInfo
{
LLPolyVolumeMorphInfo(std::string &name, LLVector3 &scale, LLVector3 &pos)
: mName(name), mScale(scale), mPos(pos) {};
std::string mName;
LLVector3 mScale;
LLVector3 mPos;
};
struct LLPolyVolumeMorph
{
LLPolyVolumeMorph(LLAvatarJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos)
: mVolume(volume), mScale(scale), mPos(pos) {};
LLAvatarJointCollisionVolume* mVolume;
LLVector3 mScale;
LLVector3 mPos;
};
//-----------------------------------------------------------------------------
// LLPolyMorphTargetInfo
// Shared information for LLPolyMorphTargets
//-----------------------------------------------------------------------------
class LLPolyMorphTargetInfo : public LLViewerVisualParamInfo
{
friend class LLPolyMorphTarget;
public:
LLPolyMorphTargetInfo();
/*virtual*/ ~LLPolyMorphTargetInfo() {};
/*virtual*/ bool parseXml(LLXmlTreeNode* node);
protected:
std::string mMorphName;
bool mIsClothingMorph;
typedef std::vector<LLPolyVolumeMorphInfo> volume_info_list_t;
volume_info_list_t mVolumeInfoList;
};
//-----------------------------------------------------------------------------
// LLPolyMorphTarget
// A set of vertex data associated with morph target.
// These morph targets must be topologically consistent with a given Polymesh
// (share face sets)
//-----------------------------------------------------------------------------
class alignas(16) LLPolyMorphTarget : public LLViewerVisualParam
{
LL_ALIGN_NEW
public:
LLPolyMorphTarget(LLPolyMesh *poly_mesh);
~LLPolyMorphTarget();
// Special: These functions are overridden by child classes
LLPolyMorphTargetInfo* getInfo() const { return (LLPolyMorphTargetInfo*)mInfo; }
// This sets mInfo and calls initialization functions
bool setInfo(LLPolyMorphTargetInfo *info);
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
// LLVisualParam Virtual functions
///*virtual*/ bool parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex sex );
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion();
/*virtual*/ const LLVector4a& getAvgDistortion();
/*virtual*/ F32 getMaxDistortion();
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
void applyMask(const U8 *maskData, S32 width, S32 height, S32 num_components, bool invert);
void addPendingMorphMask() { mNumMorphMasksPending++; }
void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton()
protected:
LLPolyMorphTarget(const LLPolyMorphTarget& pOther);
LLPolyMorphData* mMorphData;
LLPolyMesh* mMesh;
LLPolyVertexMask * mVertMask;
ESex mLastSex;
// number of morph masks that haven't been generated, must be 0 before this morph is applied
S32 mNumMorphMasksPending;
typedef std::vector<LLPolyVolumeMorph> volume_list_t;
volume_list_t mVolumeMorphs;
};
#endif // LL_LLPOLYMORPH_H
@@ -0,0 +1,293 @@
/**
* @file llpolyskeletaldistortion.cpp
* @brief Implementation of LLPolySkeletalDistortion classes
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "llpreprocessor.h"
#include "llerror.h"
#include "llavatarappearance.h"
#include "llavatarjoint.h"
#include "llpolymorph.h"
#include "llwearable.h"
#include "llfasttimer.h"
#include "llpolyskeletaldistortion.h"
//-----------------------------------------------------------------------------
// LLPolySkeletalDistortionInfo()
//-----------------------------------------------------------------------------
LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
{
}
bool LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
{
llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
if (!LLViewerVisualParamInfo::parseXml(node))
return false;
LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
if (NULL == skeletalParam)
{
LL_WARNS() << "Failed to getChildByName(\"param_skeleton\")"
<< LL_ENDL;
return false;
}
for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
{
if (bone->hasName("bone"))
{
std::string name;
LLVector3 scale;
LLVector3 pos;
bool haspos = false;
static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
if (!bone->getFastAttributeString(name_string, name))
{
LL_WARNS() << "No bone name specified for skeletal param." << LL_ENDL;
continue;
}
static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
if (!bone->getFastAttributeVector3(scale_string, scale))
{
LL_WARNS() << "No scale specified for bone " << name << "." << LL_ENDL;
continue;
}
// optional offset deformation (translation)
static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
if (bone->getFastAttributeVector3(offset_string, pos))
{
haspos = true;
}
mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
}
else
{
LL_WARNS() << "Unrecognized element " << bone->getName() << " in skeletal distortion" << LL_ENDL;
continue;
}
}
return true;
}
//-----------------------------------------------------------------------------
// LLPolySkeletalDistortion()
//-----------------------------------------------------------------------------
LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp)
: LLViewerVisualParam(),
mDefaultVec(),
mJointScales(),
mJointOffsets(),
mAvatar(avatarp)
{
mDefaultVec.splat(0.001f);
}
//-----------------------------------------------------------------------------
// LLPolySkeletalDistortion()
//-----------------------------------------------------------------------------
LLPolySkeletalDistortion::LLPolySkeletalDistortion(const LLPolySkeletalDistortion &pOther)
: LLViewerVisualParam(pOther),
mDefaultVec(pOther.mDefaultVec),
mJointScales(pOther.mJointScales),
mJointOffsets(pOther.mJointOffsets),
mAvatar(pOther.mAvatar)
{
}
//-----------------------------------------------------------------------------
// ~LLPolySkeletalDistortion()
//-----------------------------------------------------------------------------
LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
{
}
bool LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
{
if (info->mID < 0)
{
return false;
}
mInfo = info;
mID = info->mID;
// <FS:Ansariel> [Legacy Bake]
//setWeight(getDefaultWeight());
setWeight(getDefaultWeight(), false);
for (LLPolySkeletalBoneInfo& bone_info : getInfo()->mBoneInfoList)
{
LLJoint* joint = mAvatar->getJoint(bone_info.mBoneName);
if (!joint)
{
// There's no point continuing after this error - means
// that either the skeleton or lad file is broken.
LL_WARNS() << "Joint " << bone_info.mBoneName << " not found." << LL_ENDL;
return false;
}
// store it
mJointScales[joint] = bone_info.mScaleDeformation;
// apply to children that need to inherit it
for (LLJoint* joint : joint->mChildren)
{
LLAvatarJoint* child_joint = (LLAvatarJoint*)joint;
if (child_joint->inheritScale())
{
LLVector3 childDeformation = LLVector3(child_joint->getScale());
childDeformation.scaleVec(bone_info.mScaleDeformation);
mJointScales[child_joint] = childDeformation;
}
}
if (bone_info.mHasPositionDeformation)
{
mJointOffsets[joint] = bone_info.mPositionDeformation;
}
}
return true;
}
/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
{
return new LLPolySkeletalDistortion(*this);
}
//-----------------------------------------------------------------------------
// apply()
//-----------------------------------------------------------------------------
void LLPolySkeletalDistortion::apply( ESex avatar_sex )
{
LL_PROFILE_ZONE_SCOPED;
F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
LLJoint* joint;
for (joint_vec_map_t::value_type& scale_pair : mJointScales)
{
joint = scale_pair.first;
LLVector3 newScale = joint->getScale();
LLVector3 scaleDelta = scale_pair.second;
LLVector3 offset = (effective_weight - mLastWeight) * scaleDelta;
newScale = newScale + offset;
//An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached
// needed?
// joint->storeScaleForReset( newScale );
joint->setScale(newScale, true);
}
for (joint_vec_map_t::value_type& offset_pair : mJointOffsets)
{
joint = offset_pair.first;
LLVector3 newPosition = joint->getPosition();
LLVector3 positionDelta = offset_pair.second;
newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
// SL-315
bool allow_attachment_pos_overrides = true;
joint->setPosition(newPosition, allow_attachment_pos_overrides);
}
if (mLastWeight != effective_weight && !mIsAnimating)
{
mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
}
mLastWeight = effective_weight;
}
LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
const std::string &name)
{
LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
cloned_morph_data->mName = name;
for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
{
cloned_morph_data->mCoords[v] = src_data->mCoords[v];
cloned_morph_data->mNormals[v] = src_data->mNormals[v];
cloned_morph_data->mBinormals[v] = src_data->mBinormals[v];
}
return cloned_morph_data;
}
LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
const LLVector3 &direction,
const std::string &name)
{
LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
cloned_morph_data->mName = name;
LLVector4a dir;
dir.load3(direction.mV);
for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
{
cloned_morph_data->mCoords[v] = dir;
cloned_morph_data->mNormals[v].clear();
cloned_morph_data->mBinormals[v].clear();
}
return cloned_morph_data;
}
LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
F32 scale,
const std::string &name)
{
LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
cloned_morph_data->mName = name;
LLVector4a sc;
sc.splat(scale);
LLVector4a nsc;
nsc.set(scale, -scale, scale, scale);
for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
{
if (cloned_morph_data->mCoords[v][1] < 0)
{
cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc);
cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc);
cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc);
}
else
{
cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc);
cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc);
cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc);
}
}
return cloned_morph_data;
}
// End
@@ -0,0 +1,130 @@
/**
* @file llpolyskeletaldistortion.h
* @brief Implementation of LLPolyMesh class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLPOLYSKELETALDISTORTION_H
#define LL_LLPOLYSKELETALDISTORTION_H
#include "llcommon.h"
#include <string>
#include <map>
#include "llstl.h"
#include "v3math.h"
#include "v2math.h"
#include "llquaternion.h"
//#include "llpolymorph.h"
#include "lljoint.h"
#include "llviewervisualparam.h"
//class LLSkinJoint;
class LLAvatarAppearance;
//#define USE_STRIPS // Use tri-strips for rendering.
//-----------------------------------------------------------------------------
// LLPolySkeletalDeformationInfo
// Shared information for LLPolySkeletalDeformations
//-----------------------------------------------------------------------------
struct LLPolySkeletalBoneInfo
{
LLPolySkeletalBoneInfo(std::string &name, LLVector3 &scale, LLVector3 &pos, bool haspos)
: mBoneName(name),
mScaleDeformation(scale),
mPositionDeformation(pos),
mHasPositionDeformation(haspos) {}
std::string mBoneName;
LLVector3 mScaleDeformation;
LLVector3 mPositionDeformation;
bool mHasPositionDeformation;
};
class alignas(16) LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
{
LL_ALIGN_NEW
friend class LLPolySkeletalDistortion;
public:
LLPolySkeletalDistortionInfo();
/*virtual*/ ~LLPolySkeletalDistortionInfo() {};
/*virtual*/ bool parseXml(LLXmlTreeNode* node);
protected:
typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
bone_info_list_t mBoneInfoList;
};
//-----------------------------------------------------------------------------
// LLPolySkeletalDeformation
// A set of joint scale data for deforming the avatar mesh
//-----------------------------------------------------------------------------
class alignas(16) LLPolySkeletalDistortion : public LLViewerVisualParam
{
LL_ALIGN_NEW
public:
LLPolySkeletalDistortion(LLAvatarAppearance *avatarp);
~LLPolySkeletalDistortion();
// Special: These functions are overridden by child classes
LLPolySkeletalDistortionInfo* getInfo() const { return (LLPolySkeletalDistortionInfo*)mInfo; }
// This sets mInfo and calls initialization functions
bool setInfo(LLPolySkeletalDistortionInfo *info);
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
// LLVisualParam Virtual functions
///*virtual*/ bool parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex sex );
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 0.1f; }
/*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; }
/*virtual*/ F32 getMaxDistortion() { return 0.1f; }
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);}
// <FS:ND> This functions probably do not want to clear the argument, but the arguments content.
// /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;};
// /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { if( index ){ *index = 0;} if( poly_mesh ){ *poly_mesh = NULL; } return &mDefaultVec; };
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { if( index ){ *index = 0;} if( poly_mesh ){ *poly_mesh = NULL; } return NULL; };
// </FS:ND>
protected:
LLPolySkeletalDistortion(const LLPolySkeletalDistortion& pOther);
LL_ALIGN_16(LLVector4a mDefaultVec);
typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;
joint_vec_map_t mJointScales;
joint_vec_map_t mJointOffsets;
// Backlink only; don't make this an LLPointer.
LLAvatarAppearance *mAvatar;
} LL_ALIGN_POSTFIX(16);
#endif // LL_LLPOLYSKELETALDISTORTION_H
+170
View File
@@ -0,0 +1,170 @@
/**
* @file lltexlayerglobalcolor.cpp
* @brief Color for texture layers.
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llavatarappearance.h"
#include "lltexlayer.h"
#include "lltexglobalcolor.h"
class LLWearable;
//-----------------------------------------------------------------------------
// LLTexGlobalColor
//-----------------------------------------------------------------------------
LLTexGlobalColor::LLTexGlobalColor(LLAvatarAppearance* appearance)
:
mAvatarAppearance(appearance),
mInfo(NULL)
{
}
LLTexGlobalColor::~LLTexGlobalColor()
{
// mParamColorList are LLViewerVisualParam's and get deleted with ~LLCharacter()
//std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer());
}
bool LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info)
{
llassert(mInfo == NULL);
mInfo = info;
//mID = info->mID; // No ID
mParamGlobalColorList.reserve(mInfo->mParamColorInfoList.size());
for (LLTexLayerParamColorInfo* color_info : mInfo->mParamColorInfoList)
{
LLTexParamGlobalColor* param_color = new LLTexParamGlobalColor(this);
if (!param_color->setInfo(color_info, true))
{
mInfo = NULL;
return false;
}
mParamGlobalColorList.push_back(param_color);
}
return true;
}
LLColor4 LLTexGlobalColor::getColor() const
{
// Sum of color params
if (mParamGlobalColorList.empty())
return LLColor4(1.f, 1.f, 1.f, 1.f);
LLColor4 net_color(0.f, 0.f, 0.f, 0.f);
LLTexLayer::calculateTexLayerColor(mParamGlobalColorList, net_color);
return net_color;
}
const std::string& LLTexGlobalColor::getName() const
{
return mInfo->mName;
}
//-----------------------------------------------------------------------------
// LLTexParamGlobalColor
//-----------------------------------------------------------------------------
LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color)
: LLTexLayerParamColor(tex_global_color->getAvatarAppearance()),
mTexGlobalColor(tex_global_color)
{
}
//-----------------------------------------------------------------------------
// LLTexParamGlobalColor
//-----------------------------------------------------------------------------
LLTexParamGlobalColor::LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther)
: LLTexLayerParamColor(pOther),
mTexGlobalColor(pOther.mTexGlobalColor)
{
}
//-----------------------------------------------------------------------------
// ~LLTexParamGlobalColor
//-----------------------------------------------------------------------------
LLTexParamGlobalColor::~LLTexParamGlobalColor()
{
}
/*virtual*/ LLViewerVisualParam* LLTexParamGlobalColor::cloneParam(LLWearable* wearable) const
{
return new LLTexParamGlobalColor(*this);
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexParamGlobalColor::onGlobalColorChanged()
//{
// mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor);
void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake)
{
mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake);
// </FS:Ansariel> [Legacy Bake]
}
//-----------------------------------------------------------------------------
// LLTexGlobalColorInfo
//-----------------------------------------------------------------------------
LLTexGlobalColorInfo::LLTexGlobalColorInfo()
{
}
LLTexGlobalColorInfo::~LLTexGlobalColorInfo()
{
for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer());
mParamColorInfoList.clear();
}
bool LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node)
{
// name attribute
static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
if (!node->getFastAttributeString(name_string, mName))
{
LL_WARNS() << "<global_color> element is missing name attribute." << LL_ENDL;
return false;
}
// <param> sub-element
for (LLXmlTreeNode* child = node->getChildByName("param");
child;
child = node->getNextNamedChild())
{
if (child->getChildByName("param_color"))
{
// <param><param_color/></param>
LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo();
if (!info->parseXml(child))
{
delete info;
return false;
}
mParamColorInfoList.push_back(info);
}
}
return true;
}
+88
View File
@@ -0,0 +1,88 @@
/**
* @file lltexglobalcolor.h
* @brief This is global texture color info used by llavatarappearance.
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLTEXGLOBALCOLOR_H
#define LL_LLTEXGLOBALCOLOR_H
#include "lltexlayer.h"
#include "lltexlayerparams.h"
class LLAvatarAppearance;
class LLWearable;
class LLTexGlobalColorInfo;
class LLTexGlobalColor
{
public:
LLTexGlobalColor( LLAvatarAppearance* appearance );
~LLTexGlobalColor();
LLTexGlobalColorInfo* getInfo() const { return mInfo; }
// This sets mInfo and calls initialization functions
bool setInfo(LLTexGlobalColorInfo *info);
LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
LLColor4 getColor() const;
const std::string& getName() const;
private:
param_color_list_t mParamGlobalColorList;
LLAvatarAppearance* mAvatarAppearance; // just backlink, don't LLPointer
LLTexGlobalColorInfo *mInfo;
};
// Used by llavatarappearance to determine skin/eye/hair color.
class LLTexGlobalColorInfo
{
friend class LLTexGlobalColor;
public:
LLTexGlobalColorInfo();
~LLTexGlobalColorInfo();
bool parseXml(LLXmlTreeNode* node);
private:
param_color_info_list_t mParamColorInfoList;
std::string mName;
};
class LLTexParamGlobalColor : public LLTexLayerParamColor
{
public:
LLTexParamGlobalColor(LLTexGlobalColor *tex_color);
virtual ~LLTexParamGlobalColor();
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
protected:
LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther);
// <FS:Ansariel> [Legacy Bake]
///*virtual*/ void onGlobalColorChanged();
/*virtual*/ void onGlobalColorChanged(bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
private:
LLTexGlobalColor* mTexGlobalColor;
};
#endif
File diff suppressed because it is too large Load Diff
+316
View File
@@ -0,0 +1,316 @@
/**
* @file lltexlayer.h
* @brief Texture layer classes. Used for avatars.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLTEXLAYER_H
#define LL_LLTEXLAYER_H
#include <deque>
#include "llglslshader.h"
#include "llgltexture.h"
#include "llavatarappearancedefines.h"
#include "lltexlayerparams.h"
class LLAvatarAppearance;
class LLImageTGA;
class LLImageRaw;
class LLLocalTextureObject;
class LLXmlTreeNode;
class LLTexLayerSet;
class LLTexLayerSetInfo;
class LLTexLayerInfo;
class LLTexLayerSetBuffer;
class LLWearable;
class LLViewerVisualParam;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerInterface
//
// Interface class to generalize functionality shared by LLTexLayer
// and LLTexLayerTemplate.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerInterface
{
public:
enum ERenderPass
{
RP_COLOR,
RP_BUMP,
RP_SHINE
};
LLTexLayerInterface(LLTexLayerSet* const layer_set);
LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable);
virtual ~LLTexLayerInterface() {}
virtual bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target) = 0;
virtual void deleteCaches() = 0;
virtual bool blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) = 0;
virtual bool isInvisibleAlphaMask() const = 0;
const LLTexLayerInfo* getInfo() const { return mInfo; }
virtual bool setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // sets mInfo, calls initialization functions
LLWearableType::EType getWearableType() const;
LLAvatarAppearanceDefines::ETextureIndex getLocalTextureIndex() const;
const std::string& getName() const;
const LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; }
LLTexLayerSet* const getTexLayerSet() { return mTexLayerSet; }
void invalidateMorphMasks();
virtual void setHasMorph(bool newval) { mHasMorph = newval; }
bool hasMorph() const { return mHasMorph; }
bool isMorphValid() const { return mMorphMasksValid; }
void requestUpdate();
virtual void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target) = 0;
bool hasAlphaParams() const { return !mParamAlphaList.empty(); }
ERenderPass getRenderPass() const;
bool isVisibilityMask() const;
virtual void asLLSD(LLSD& sd) const {}
protected:
const std::string& getGlobalColor() const;
LLViewerVisualParam* getVisualParamPtr(S32 index) const;
protected:
LLTexLayerSet* const mTexLayerSet;
const LLTexLayerInfo* mInfo;
bool mMorphMasksValid;
bool mHasMorph;
// Layers can have either mParamColorList, mGlobalColor, or mFixedColor. They are looked for in that order.
param_color_list_t mParamColorList;
param_alpha_list_t mParamAlphaList;
// mGlobalColor name stored in mInfo
// mFixedColor value stored in mInfo
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerTemplate
//
// Only exists for llvoavatarself.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerTemplate : public LLTexLayerInterface
{
public:
LLTexLayerTemplate(LLTexLayerSet* const layer_set, LLAvatarAppearance* const appearance);
LLTexLayerTemplate(const LLTexLayerTemplate &layer);
/*virtual*/ ~LLTexLayerTemplate();
/*virtual*/ bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target);
/*virtual*/ bool setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions
/*virtual*/ bool blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
/*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target);
/*virtual*/ void setHasMorph(bool newval);
/*virtual*/ void deleteCaches();
/*virtual*/ bool isInvisibleAlphaMask() const;
protected:
U32 updateWearableCache() const;
LLTexLayer* getLayer(U32 i) const;
LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
private:
LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer.
typedef std::vector<LLWearable*> wearable_cache_t;
mutable wearable_cache_t mWearableCache; // mutable b/c most get- require updating this cache
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayer
//
// A single texture layer. Only exists for llvoavatarself.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayer : public LLTexLayerInterface
{
public:
LLTexLayer(LLTexLayerSet* const layer_set);
LLTexLayer(const LLTexLayer &layer, LLWearable *wearable);
LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable);
/*virtual*/ ~LLTexLayer();
/*virtual*/ bool setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions
/*virtual*/ bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target);
/*virtual*/ void deleteCaches();
const U8* getAlphaData() const;
bool findNetColor(LLColor4* color) const;
/*virtual*/ bool blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
/*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target);
void renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render);
void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target);
/*virtual*/ bool isInvisibleAlphaMask() const;
void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; }
LLLocalTextureObject* getLTO() { return mLocalTextureObject; }
/*virtual*/ void asLLSD(LLSD& sd) const;
static void calculateTexLayerColor(const param_color_list_t &param_list, LLColor4 &net_color);
protected:
LLUUID getUUID() const;
typedef std::map<U32, U8*> alpha_cache_t;
alpha_cache_t mAlphaCache;
LLLocalTextureObject* mLocalTextureObject;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerSet
//
// An ordered set of texture layers that gets composited into a single texture.
// Only exists for llvoavatarself.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerSet
{
friend class LLTexLayerSetBuffer;
public:
LLTexLayerSet(LLAvatarAppearance* const appearance);
virtual ~LLTexLayerSet();
LLTexLayerSetBuffer* getComposite();
const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist.
virtual void createComposite() = 0;
void destroyComposite();
void gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target);
const LLTexLayerSetInfo* getInfo() const { return mInfo; }
bool setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions
bool render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr);
void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr, bool forceClear = false);
bool isBodyRegion(const std::string& region) const;
void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components);
bool isMorphValid() const;
virtual void requestUpdate() = 0;
void invalidateMorphMasks();
void deleteCaches();
LLTexLayerInterface* findLayerByName(const std::string& name);
void cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable* wearable);
LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
const std::string getBodyRegionName() const;
bool hasComposite() const { return (mComposite.notNull()); }
LLAvatarAppearanceDefines::EBakedTextureIndex getBakedTexIndex() const { return mBakedTexIndex; }
void setBakedTexIndex(LLAvatarAppearanceDefines::EBakedTextureIndex index) { mBakedTexIndex = index; }
bool isVisible() const { return mIsVisible; }
static bool sHasCaches;
protected:
typedef std::vector<LLTexLayerInterface *> layer_list_t;
layer_list_t mLayerList;
layer_list_t mMaskLayerList;
LLPointer<LLTexLayerSetBuffer> mComposite;
LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer.
bool mIsVisible;
LLAvatarAppearanceDefines::EBakedTextureIndex mBakedTexIndex;
const LLTexLayerSetInfo* mInfo;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerSetInfo
//
// Contains shared layer set data.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerSetInfo
{
friend class LLTexLayerSet;
public:
LLTexLayerSetInfo();
~LLTexLayerSetInfo();
bool parseXml(LLXmlTreeNode* node);
void createVisualParams(LLAvatarAppearance *appearance);
S32 getWidth() const { return mWidth; }
S32 getHeight() const { return mHeight; }
protected:
std::string mBodyRegion;
S32 mWidth;
S32 mHeight;
std::string mStaticAlphaFileName;
bool mClearAlpha; // Set alpha to 1 for this layerset (if there is no mStaticAlphaFileName)
typedef std::vector<LLTexLayerInfo*> layer_info_list_t;
layer_info_list_t mLayerInfoList;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerSetBuffer
//
// The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerSetBuffer : public virtual LLRefCount
{
LOG_CLASS(LLTexLayerSetBuffer);
public:
LLTexLayerSetBuffer(LLTexLayerSet* const owner);
virtual ~LLTexLayerSetBuffer();
protected:
void pushProjection() const;
void popProjection() const;
virtual void preRenderTexLayerSet();
// <FS:Ansariel> [Legacy Bake]
//virtual void midRenderTexLayerSet(bool success) {}
virtual void midRenderTexLayerSet(bool success, LLRenderTarget* bound_target) {}
// </FS:Ansariel> [Legacy Bake]
virtual void postRenderTexLayerSet(bool success);
virtual S32 getCompositeOriginX() const = 0;
virtual S32 getCompositeOriginY() const = 0;
virtual S32 getCompositeWidth() const = 0;
virtual S32 getCompositeHeight() const = 0;
bool renderTexLayerSet(LLRenderTarget* bound_target);
LLTexLayerSet* const mTexLayerSet;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerStaticImageList
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerStaticImageList : public LLSingleton<LLTexLayerStaticImageList>
{
LLSINGLETON(LLTexLayerStaticImageList);
~LLTexLayerStaticImageList();
public:
LLGLTexture* getTexture(const std::string& file_name, bool is_mask);
LLImageTGA* getImageTGA(const std::string& file_name);
void deleteCachedImages();
void dumpByteCount() const;
protected:
bool loadImageRaw(const std::string& file_name, LLImageRaw* image_raw);
private:
LLStringTable mImageNames;
typedef std::map<const char*, LLPointer<LLGLTexture> > texture_map_t;
texture_map_t mStaticImageList;
typedef std::map<const char*, LLPointer<LLImageTGA> > image_tga_map_t;
image_tga_map_t mStaticImageListTGA;
S32 mGLBytes;
S32 mTGABytes;
};
#endif // LL_LLTEXLAYER_H
+628
View File
@@ -0,0 +1,628 @@
/**
* @file lltexlayerparams.cpp
* @brief Texture layer parameters
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "lltexlayerparams.h"
#include "llavatarappearance.h"
#include "llimagetga.h"
#include "llquantize.h"
#include "lltexlayer.h"
#include "lltexturemanagerbridge.h"
#include "../llui/llui.h"
#include "llwearable.h"
#include "llfasttimer.h"
//-----------------------------------------------------------------------------
// LLTexLayerParam
//-----------------------------------------------------------------------------
LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer)
: LLViewerVisualParam(),
mTexLayer(layer),
mAvatarAppearance(NULL)
{
if (mTexLayer != NULL)
{
mAvatarAppearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
}
else
{
LL_ERRS() << "LLTexLayerParam constructor passed with NULL reference for layer!" << LL_ENDL;
}
}
LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance)
: LLViewerVisualParam(),
mTexLayer(NULL),
mAvatarAppearance(appearance)
{
}
LLTexLayerParam::LLTexLayerParam(const LLTexLayerParam& pOther)
: LLViewerVisualParam(pOther),
mTexLayer(pOther.mTexLayer),
mAvatarAppearance(pOther.mAvatarAppearance)
{
}
bool LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, bool add_to_appearance)
{
LLViewerVisualParam::setInfo(info);
if (add_to_appearance)
{
mAvatarAppearance->addVisualParam( this);
this->setParamLocation(mAvatarAppearance->isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
}
return true;
}
//-----------------------------------------------------------------------------
// LLTexLayerParamAlpha
//-----------------------------------------------------------------------------
// static
LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances;
// static
void LLTexLayerParamAlpha::dumpCacheByteCount()
{
S32 gl_bytes = 0;
getCacheByteCount( &gl_bytes);
LL_INFOS() << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << LL_ENDL;
}
// static
void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)
{
*gl_bytes = 0;
for (LLTexLayerParamAlpha* instance : sInstances)
{
LLGLTexture* tex = instance->mCachedProcessedTexture;
if (tex)
{
S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents();
if (tex->hasGLTexture())
{
*gl_bytes += bytes;
}
}
}
}
LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer)
: LLTexLayerParam(layer),
mCachedProcessedTexture(NULL),
mStaticImageTGA(),
mStaticImageRaw(),
mNeedsCreateTexture(false),
mStaticImageInvalid(false),
mAvgDistortionVec(1.f, 1.f, 1.f),
mCachedEffectiveWeight(0.f)
{
sInstances.push_front(this);
}
LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance)
: LLTexLayerParam(appearance),
mCachedProcessedTexture(NULL),
mStaticImageTGA(),
mStaticImageRaw(),
mNeedsCreateTexture(false),
mStaticImageInvalid(false),
mAvgDistortionVec(1.f, 1.f, 1.f),
mCachedEffectiveWeight(0.f)
{
sInstances.push_front(this);
}
LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther)
: LLTexLayerParam(pOther),
mCachedProcessedTexture(pOther.mCachedProcessedTexture),
mStaticImageTGA(pOther.mStaticImageTGA),
mStaticImageRaw(pOther.mStaticImageRaw),
mNeedsCreateTexture(pOther.mNeedsCreateTexture.load()),
mStaticImageInvalid(pOther.mStaticImageInvalid),
mAvgDistortionVec(pOther.mAvgDistortionVec),
mCachedEffectiveWeight(pOther.mCachedEffectiveWeight)
{
sInstances.push_front(this);
}
LLTexLayerParamAlpha::~LLTexLayerParamAlpha()
{
deleteCaches();
sInstances.remove(this);
}
/*virtual*/ LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const
{
return new LLTexLayerParamAlpha(*this);
}
void LLTexLayerParamAlpha::deleteCaches()
{
mStaticImageTGA = NULL; // deletes image
mCachedProcessedTexture = NULL;
mStaticImageRaw = NULL;
mNeedsCreateTexture = false;
}
bool LLTexLayerParamAlpha::getMultiplyBlend() const
{
return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend;
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamAlpha::setWeight(F32 weight)
void LLTexLayerParamAlpha::setWeight(F32 weight, bool upload_bake)
// </FS:Ansariel> [Legacy Bake]
{
if (mIsAnimating || mTexLayer == NULL)
{
return;
}
F32 min_weight = getMinWeight();
F32 max_weight = getMaxWeight();
F32 new_weight = llclamp(weight, min_weight, max_weight);
U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight);
U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight);
if (cur_u8 != new_u8)
{
mCurWeight = new_weight;
if ((mAvatarAppearance->getSex() & getSex()) &&
(mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
{
// <FS:Ansariel> [Legacy Bake]
//mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
// <FS:Ansariel> [Legacy Bake]
mTexLayer->invalidateMorphMasks();
}
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value)
void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, bool upload_bake)
{
// do not animate dummy parameters
if (mIsDummy)
{
// <FS:Ansariel> [Legacy Bake]
//setWeight(target_value);
setWeight(target_value, upload_bake);
return;
}
mTargetWeight = target_value;
// <FS:Ansariel> [Legacy Bake]
//setWeight(target_value);
setWeight(target_value, upload_bake);
mIsAnimating = true;
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->setAnimationTarget(target_value);
mNext->setAnimationTarget(target_value, upload_bake);
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamAlpha::animate(F32 delta)
void LLTexLayerParamAlpha::animate(F32 delta, bool upload_bake)
{
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->animate(delta);
mNext->animate(delta, upload_bake);
}
}
bool LLTexLayerParamAlpha::getSkip() const
{
if (!mTexLayer)
{
return true;
}
const LLAvatarAppearance *appearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
if (((LLTexLayerParamAlphaInfo *)getInfo())->mSkipIfZeroWeight)
{
F32 effective_weight = (appearance->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
if (is_approx_zero(effective_weight))
{
return true;
}
}
LLWearableType::EType type = (LLWearableType::EType)getWearableType();
if ((type != LLWearableType::WT_INVALID) && !appearance->isWearingWearableType(type))
{
return true;
}
return false;
}
bool LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
{
LL_PROFILE_ZONE_SCOPED;
bool success = true;
if (!mTexLayer)
{
return success;
}
F32 effective_weight = (mTexLayer->getTexLayerSet()->getAvatarAppearance()->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
bool weight_changed = effective_weight != mCachedEffectiveWeight;
if (getSkip())
{
return success;
}
LLTexLayerParamAlphaInfo *info = (LLTexLayerParamAlphaInfo *)getInfo();
gGL.flush();
if (info->mMultiplyBlend)
{
gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); // Multiplication: approximates a min() function
}
else
{
gGL.setSceneBlendType(LLRender::BT_ADD); // Addition: approximates a max() function
}
if (!info->mStaticImageFileName.empty() && !mStaticImageInvalid)
{
if (mStaticImageTGA.isNull())
{
// Don't load the image file until we actually need it the first time. Like now.
mStaticImageTGA = LLTexLayerStaticImageList::getInstance()->getImageTGA(info->mStaticImageFileName);
// We now have something in one of our caches
LLTexLayerSet::sHasCaches |= mStaticImageTGA.notNull();
if (mStaticImageTGA.isNull())
{
LL_WARNS() << "Unable to load static file: " << info->mStaticImageFileName << LL_ENDL;
mStaticImageInvalid = true; // don't try again.
return false;
}
}
const S32 image_tga_width = mStaticImageTGA->getWidth();
const S32 image_tga_height = mStaticImageTGA->getHeight();
if (!mCachedProcessedTexture ||
(mCachedProcessedTexture->getWidth() != image_tga_width) ||
(mCachedProcessedTexture->getHeight() != image_tga_height) ||
(weight_changed))
{
mCachedEffectiveWeight = effective_weight;
if (!mCachedProcessedTexture)
{
llassert(gTextureManagerBridgep);
mCachedProcessedTexture = gTextureManagerBridgep->getLocalTexture(image_tga_width, image_tga_height, 1, false);
// We now have something in one of our caches
LLTexLayerSet::sHasCaches |= mCachedProcessedTexture.notNull();
mCachedProcessedTexture->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
}
// Applies domain and effective weight to data as it is decoded. Also resizes the raw image if needed.
mStaticImageRaw = NULL;
mStaticImageRaw = new LLImageRaw;
mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain, effective_weight);
mNeedsCreateTexture = true;
LL_DEBUGS() << "Built Cached Alpha: " << info->mStaticImageFileName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << "Domain: " << info->mDomain << " Weight: " << effective_weight << LL_ENDL;
}
if (mCachedProcessedTexture)
{
{
// Create the GL texture, and then hang onto it for future use.
if (mNeedsCreateTexture)
{
mCachedProcessedTexture->createGLTexture(0, mStaticImageRaw);
mNeedsCreateTexture = false;
gGL.getTexUnit(0)->bind(mCachedProcessedTexture);
mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
}
gGL.getTexUnit(0)->bind(mCachedProcessedTexture);
gl_rect_2d_simple_tex(width, height);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
stop_glerror();
}
}
// Don't keep the cache for other people's avatars
// (It's not really a "cache" in that case, but the logic is the same)
if (!mAvatarAppearance->isSelf())
{
mCachedProcessedTexture = NULL;
}
}
else
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.color4f(0.f, 0.f, 0.f, effective_weight);
gl_rect_2d_simple(width, height);
}
return success;
}
//-----------------------------------------------------------------------------
// LLTexLayerParamAlphaInfo
//-----------------------------------------------------------------------------
LLTexLayerParamAlphaInfo::LLTexLayerParamAlphaInfo() :
mMultiplyBlend(false),
mSkipIfZeroWeight(false),
mDomain(0.f)
{
}
bool LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node)
{
llassert(node->hasName("param") && node->getChildByName("param_alpha"));
if (!LLViewerVisualParamInfo::parseXml(node))
return false;
LLXmlTreeNode* param_alpha_node = node->getChildByName("param_alpha");
if (!param_alpha_node)
{
return false;
}
static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file");
if (param_alpha_node->getFastAttributeString(tga_file_string, mStaticImageFileName))
{
// Don't load the image file until it's actually needed.
}
// else
// {
// LL_WARNS() << "<param_alpha> element is missing tga_file attribute." << LL_ENDL;
// }
static LLStdStringHandle multiply_blend_string = LLXmlTree::addAttributeString("multiply_blend");
param_alpha_node->getFastAttributeBOOL(multiply_blend_string, mMultiplyBlend);
static LLStdStringHandle skip_if_zero_string = LLXmlTree::addAttributeString("skip_if_zero");
param_alpha_node->getFastAttributeBOOL(skip_if_zero_string, mSkipIfZeroWeight);
static LLStdStringHandle domain_string = LLXmlTree::addAttributeString("domain");
param_alpha_node->getFastAttributeF32(domain_string, mDomain);
return true;
}
LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer)
: LLTexLayerParam(layer),
mAvgDistortionVec(1.f, 1.f, 1.f)
{
}
LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance)
: LLTexLayerParam(appearance),
mAvgDistortionVec(1.f, 1.f, 1.f)
{
}
LLTexLayerParamColor::LLTexLayerParamColor(const LLTexLayerParamColor& pOther)
: LLTexLayerParam(pOther),
mAvgDistortionVec(pOther.mAvgDistortionVec)
{
}
LLTexLayerParamColor::~LLTexLayerParamColor()
{
}
/*virtual*/ LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const
{
return new LLTexLayerParamColor(*this);
}
LLColor4 LLTexLayerParamColor::getNetColor() const
{
const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
llassert(info->mNumColors >= 1);
F32 effective_weight = (mAvatarAppearance && (mAvatarAppearance->getSex() & getSex())) ? mCurWeight : getDefaultWeight();
S32 index_last = info->mNumColors - 1;
F32 scaled_weight = effective_weight * index_last;
S32 index_start = (S32) scaled_weight;
S32 index_end = index_start + 1;
if (index_start == index_last)
{
return info->mColors[index_last];
}
else
{
F32 weight = scaled_weight - index_start;
const LLColor4 *start = &info->mColors[ index_start ];
const LLColor4 *end = &info->mColors[ index_end ];
return LLColor4((1.f - weight) * start->mV[VRED] + weight * end->mV[VRED],
(1.f - weight) * start->mV[VGREEN] + weight * end->mV[VGREEN],
(1.f - weight) * start->mV[VBLUE] + weight * end->mV[VBLUE],
(1.f - weight) * start->mV[VALPHA] + weight * end->mV[VALPHA]);
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamColor::setWeight(F32 weight)
void LLTexLayerParamColor::setWeight(F32 weight, bool upload_bake)
{
if (mIsAnimating)
{
return;
}
F32 min_weight = getMinWeight();
F32 max_weight = getMaxWeight();
F32 new_weight = llclamp(weight, min_weight, max_weight);
U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight);
U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight);
if (cur_u8 != new_u8)
{
mCurWeight = new_weight;
const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
if (info->mNumColors <= 0)
{
// This will happen when we set the default weight the first time.
return;
}
if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
{
// <FS:Ansariel> [Legacy Bake]
//onGlobalColorChanged();
onGlobalColorChanged(upload_bake);
if (mTexLayer)
{
// <FS:Ansariel> [Legacy Bake]
//mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
}
}
// LL_INFOS() << "param " << mName << " = " << new_weight << LL_ENDL;
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamColor::setAnimationTarget(F32 target_value)
void LLTexLayerParamColor::setAnimationTarget(F32 target_value, bool upload_bake)
{
// set value first then set interpolating flag to ignore further updates
mTargetWeight = target_value;
// <FS:Ansariel> [Legacy Bake]
//setWeight(target_value);
setWeight(target_value, upload_bake);
mIsAnimating = true;
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->setAnimationTarget(target_value);
mNext->setAnimationTarget(target_value, upload_bake);
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLTexLayerParamColor::animate(F32 delta)
void LLTexLayerParamColor::animate(F32 delta, bool upload_bake)
{
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->animate(delta);
mNext->animate(delta, upload_bake);
}
}
//-----------------------------------------------------------------------------
// LLTexLayerParamColorInfo
//-----------------------------------------------------------------------------
LLTexLayerParamColorInfo::LLTexLayerParamColorInfo() :
mOperation(LLTexLayerParamColor::OP_ADD),
mNumColors(0)
{
}
bool LLTexLayerParamColorInfo::parseXml(LLXmlTreeNode *node)
{
llassert(node->hasName("param") && node->getChildByName("param_color"));
if (!LLViewerVisualParamInfo::parseXml(node))
return false;
LLXmlTreeNode* param_color_node = node->getChildByName("param_color");
if (!param_color_node)
{
return false;
}
std::string op_string;
static LLStdStringHandle operation_string = LLXmlTree::addAttributeString("operation");
if (param_color_node->getFastAttributeString(operation_string, op_string))
{
LLStringUtil::toLower(op_string);
if (op_string == "add") mOperation = LLTexLayerParamColor::OP_ADD;
else if (op_string == "multiply") mOperation = LLTexLayerParamColor::OP_MULTIPLY;
else if (op_string == "blend") mOperation = LLTexLayerParamColor::OP_BLEND;
}
mNumColors = 0;
LLColor4U color4u;
for (LLXmlTreeNode* child = param_color_node->getChildByName("value");
child;
child = param_color_node->getNextNamedChild())
{
if ((mNumColors < MAX_COLOR_VALUES))
{
static LLStdStringHandle color_string = LLXmlTree::addAttributeString("color");
if (child->getFastAttributeColor4U(color_string, color4u))
{
mColors[ mNumColors ].setVec(color4u);
mNumColors++;
}
}
}
if (!mNumColors)
{
LL_WARNS() << "<param_color> is missing <value> sub-elements" << LL_ENDL;
return false;
}
if ((mOperation == LLTexLayerParamColor::OP_BLEND) && (mNumColors != 1))
{
LL_WARNS() << "<param_color> with operation\"blend\" must have exactly one <value>" << LL_ENDL;
return false;
}
return true;
}
+224
View File
@@ -0,0 +1,224 @@
/**
* @file lltexlayerparams.h
* @brief Texture layer parameters, used by lltexlayer.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLTEXLAYERPARAMS_H
#define LL_LLTEXLAYERPARAMS_H
#include "llpointer.h"
#include "v4color.h"
#include "llviewervisualparam.h"
class LLAvatarAppearance;
class LLImageRaw;
class LLImageTGA;
class LLTexLayer;
class LLTexLayerInterface;
class LLGLTexture;
class LLWearable;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerParam
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerParam : public LLViewerVisualParam
{
public:
LLTexLayerParam(LLTexLayerInterface *layer);
LLTexLayerParam(LLAvatarAppearance *appearance);
/*virtual*/ bool setInfo(LLViewerVisualParamInfo *info, bool add_to_appearance);
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0;
protected:
LLTexLayerParam(const LLTexLayerParam& pOther);
LLTexLayerInterface* mTexLayer;
LLAvatarAppearance* mAvatarAppearance;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerParamAlpha
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LL_ALIGN_PREFIX(16)
class alignas(16) LLTexLayerParamAlpha : public LLTexLayerParam
{
LL_ALIGN_NEW
public:
LLTexLayerParamAlpha( LLTexLayerInterface* layer );
LLTexLayerParamAlpha( LLAvatarAppearance* appearance );
/*virtual*/ ~LLTexLayerParamAlpha();
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
// LLVisualParam Virtual functions
///*virtual*/ bool parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex avatar_sex ) {}
// <FS:Ansariel> [Legacy Bake]
///*virtual*/ void setWeight(F32 weight);
///*virtual*/ void setAnimationTarget(F32 target_value);
///*virtual*/ void animate(F32 delta);
/*virtual*/ void setWeight(F32 weight, bool upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, bool upload_bake);
/*virtual*/ void animate(F32 delta, bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
/*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; }
/*virtual*/ F32 getMaxDistortion() { return 3.f; }
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f);}
// <FS:ND> This functions probably do not want to clear the argument, but the arguments content.
// /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
// /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;};
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { if( index ){ *index = 0;} if( poly_mesh ){ *poly_mesh = NULL; } return &mAvgDistortionVec; };
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { if( index ){ *index = 0;} if( poly_mesh ){ *poly_mesh = NULL; } return NULL; };
// </FS:ND>
// New functions
bool render( S32 x, S32 y, S32 width, S32 height );
bool getSkip() const;
void deleteCaches();
bool getMultiplyBlend() const;
private:
LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther);
LLPointer<LLGLTexture> mCachedProcessedTexture;
LLPointer<LLImageTGA> mStaticImageTGA;
LLPointer<LLImageRaw> mStaticImageRaw;
std::atomic<bool> mNeedsCreateTexture;
bool mStaticImageInvalid;
LL_ALIGN_16(LLVector4a mAvgDistortionVec);
F32 mCachedEffectiveWeight;
public:
// Global list of instances for gathering statistics
static void dumpCacheByteCount();
static void getCacheByteCount( S32* gl_bytes );
typedef std::list< LLTexLayerParamAlpha* > param_alpha_ptr_list_t;
static param_alpha_ptr_list_t sInstances;
} LL_ALIGN_POSTFIX(16);
class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo
{
friend class LLTexLayerParamAlpha;
public:
LLTexLayerParamAlphaInfo();
/*virtual*/ ~LLTexLayerParamAlphaInfo() {};
/*virtual*/ bool parseXml(LLXmlTreeNode* node);
private:
std::string mStaticImageFileName;
bool mMultiplyBlend;
bool mSkipIfZeroWeight;
F32 mDomain;
};
//
// LLTexLayerParamAlpha
//-----------------------------------------------------------------------------
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerParamColor
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class alignas(16) LLTexLayerParamColor : public LLTexLayerParam
{
LL_ALIGN_NEW
public:
enum EColorOperation
{
OP_ADD = 0,
OP_MULTIPLY = 1,
OP_BLEND = 2,
OP_COUNT = 3 // Number of operations
};
LLTexLayerParamColor( LLTexLayerInterface* layer );
LLTexLayerParamColor( LLAvatarAppearance* appearance );
/* virtual */ ~LLTexLayerParamColor();
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
// LLVisualParam Virtual functions
///*virtual*/ bool parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex avatar_sex ) {}
// <FS:Ansariel> [Legacy Bake]
///*virtual*/ void setWeight(F32 weight);
///*virtual*/ void setAnimationTarget(F32 target_value);
///*virtual*/ void animate(F32 delta);
/*virtual*/ void setWeight(F32 weight, bool upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, bool upload_bake);
/*virtual*/ void animate(F32 delta, bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
/*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; }
/*virtual*/ F32 getMaxDistortion() { return 3.f; }
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f); }
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;};
// New functions
LLColor4 getNetColor() const;
protected:
LLTexLayerParamColor(const LLTexLayerParamColor& pOther);
// <FS:Ansariel> [Legacy Bake]
//virtual void onGlobalColorChanged() {}
virtual void onGlobalColorChanged(bool upload_bake) {}
private:
LLVector4a mAvgDistortionVec;
};
class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo
{
friend class LLTexLayerParamColor;
public:
LLTexLayerParamColorInfo();
virtual ~LLTexLayerParamColorInfo() {};
bool parseXml( LLXmlTreeNode* node );
LLTexLayerParamColor::EColorOperation getOperation() const { return mOperation; }
private:
enum { MAX_COLOR_VALUES = 20 };
LLTexLayerParamColor::EColorOperation mOperation;
LLColor4 mColors[MAX_COLOR_VALUES];
S32 mNumColors;
};
typedef std::vector<LLTexLayerParamColor *> param_color_list_t;
typedef std::vector<LLTexLayerParamAlpha *> param_alpha_list_t;
typedef std::vector<LLTexLayerParamColorInfo *> param_color_info_list_t;
typedef std::vector<LLTexLayerParamAlphaInfo *> param_alpha_info_list_t;
#endif
+181
View File
@@ -0,0 +1,181 @@
/**
* @file llviewervisualparam.cpp
* @brief Implementation of LLViewerVisualParam class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "linden_common.h"
#include "llviewervisualparam.h"
#include "llxmltree.h"
#include "llwearable.h"
//-----------------------------------------------------------------------------
// LLViewerVisualParamInfo()
//-----------------------------------------------------------------------------
LLViewerVisualParamInfo::LLViewerVisualParamInfo()
:
mWearableType( LLWearableType::WT_INVALID ),
mCrossWearable(false),
mCamDist( 0.5f ),
mCamAngle( 0.f ),
mCamElevation( 0.f ),
mEditGroupDisplayOrder( 0 ),
mShowSimple(false),
mSimpleMin(0.f),
mSimpleMax(100.f)
{
}
LLViewerVisualParamInfo::~LLViewerVisualParamInfo()
{
}
//-----------------------------------------------------------------------------
// parseXml()
//-----------------------------------------------------------------------------
bool LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)
{
llassert( node->hasName( "param" ) );
if (!LLVisualParamInfo::parseXml(node))
return false;
// VIEWER SPECIFIC PARAMS
std::string wearable;
static LLStdStringHandle wearable_string = LLXmlTree::addAttributeString("wearable");
if( node->getFastAttributeString( wearable_string, wearable) )
{
mWearableType = LLWearableType::getInstance()->typeNameToType( wearable );
}
static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group");
if (!node->getFastAttributeString( edit_group_string, mEditGroup))
{
mEditGroup = "";
}
static LLStdStringHandle cross_wearable_string = LLXmlTree::addAttributeString("cross_wearable");
if (!node->getFastAttributeBOOL(cross_wearable_string, mCrossWearable))
{
mCrossWearable = false;
}
// Optional camera offsets from the current joint center. Used for generating "hints" (thumbnails).
static LLStdStringHandle camera_distance_string = LLXmlTree::addAttributeString("camera_distance");
node->getFastAttributeF32( camera_distance_string, mCamDist );
static LLStdStringHandle camera_angle_string = LLXmlTree::addAttributeString("camera_angle");
node->getFastAttributeF32( camera_angle_string, mCamAngle ); // in degrees
static LLStdStringHandle camera_elevation_string = LLXmlTree::addAttributeString("camera_elevation");
node->getFastAttributeF32( camera_elevation_string, mCamElevation );
mCamAngle += 180;
static S32 params_loaded = 0;
// By default, parameters are displayed in the order in which they appear in the xml file.
// "edit_group_order" overriddes.
static LLStdStringHandle edit_group_order_string = LLXmlTree::addAttributeString("edit_group_order");
if( !node->getFastAttributeF32( edit_group_order_string, mEditGroupDisplayOrder ) )
{
mEditGroupDisplayOrder = (F32)params_loaded;
}
params_loaded++;
return true;
}
/*virtual*/ void LLViewerVisualParamInfo::toStream(std::ostream &out)
{
LLVisualParamInfo::toStream(out);
out << mWearableType << "\t";
out << mEditGroup << "\t";
out << mEditGroupDisplayOrder << "\t";
}
//-----------------------------------------------------------------------------
// LLViewerVisualParam()
//-----------------------------------------------------------------------------
LLViewerVisualParam::LLViewerVisualParam()
: LLVisualParam()
{
}
//-----------------------------------------------------------------------------
// LLViewerVisualParam()
//-----------------------------------------------------------------------------
LLViewerVisualParam::LLViewerVisualParam(const LLViewerVisualParam& pOther)
: LLVisualParam(pOther)
{
}
//-----------------------------------------------------------------------------
// ~LLViewerVisualParam()
//-----------------------------------------------------------------------------
LLViewerVisualParam::~LLViewerVisualParam()
{
}
//-----------------------------------------------------------------------------
// setInfo()
//-----------------------------------------------------------------------------
bool LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
{
llassert(mInfo == NULL);
if (info->mID < 0)
return false;
mInfo = info;
mID = info->mID;
// <FS:Ansariel> [Legacy Bake]
//setWeight(getDefaultWeight());
setWeight(getDefaultWeight(), false);
return true;
}
/*
//=============================================================================
// These virtual functions should always be overridden,
// but are included here for use as templates
//=============================================================================
//-----------------------------------------------------------------------------
// parseData()
//-----------------------------------------------------------------------------
bool LLViewerVisualParam::parseData(LLXmlTreeNode *node)
{
LLViewerVisualParamInfo* info = new LLViewerVisualParamInfo;
info->parseXml(node);
if (!setInfo(info))
return false;
return true;
}
*/
+112
View File
@@ -0,0 +1,112 @@
/**
* @file llviewervisualparam.h
* @brief viewer side visual params (with data file parsing)
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLViewerVisualParam_H
#define LL_LLViewerVisualParam_H
#include "v3math.h"
#include "llstring.h"
#include "llvisualparam.h"
class LLWearable;
//-----------------------------------------------------------------------------
// LLViewerVisualParamInfo
//-----------------------------------------------------------------------------
class LLViewerVisualParamInfo : public LLVisualParamInfo
{
friend class LLViewerVisualParam;
public:
LLViewerVisualParamInfo();
/*virtual*/ ~LLViewerVisualParamInfo();
/*virtual*/ bool parseXml(LLXmlTreeNode* node);
/*virtual*/ void toStream(std::ostream &out);
protected:
S32 mWearableType;
bool mCrossWearable;
std::string mEditGroup;
F32 mCamDist;
F32 mCamAngle; // degrees
F32 mCamElevation;
F32 mEditGroupDisplayOrder;
bool mShowSimple; // show edit controls when in "simple ui" mode?
F32 mSimpleMin; // when in simple UI, apply this minimum, range 0.f to 100.f
F32 mSimpleMax; // when in simple UI, apply this maximum, range 0.f to 100.f
};
//-----------------------------------------------------------------------------
// LLViewerVisualParam
// VIRTUAL CLASS
// a viewer side interface class for a generalized parametric modification of the avatar mesh
//-----------------------------------------------------------------------------
LL_ALIGN_PREFIX(16)
class LLViewerVisualParam : public LLVisualParam
{
public:
LLViewerVisualParam();
virtual ~LLViewerVisualParam();
// Special: These functions are overridden by child classes
LLViewerVisualParamInfo *getInfo() const { return (LLViewerVisualParamInfo*)mInfo; };
// This sets mInfo and calls initialization functions
bool setInfo(LLViewerVisualParamInfo *info);
virtual LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0;
// LLVisualParam Virtual functions
///*virtual*/ bool parseData(LLXmlTreeNode* node);
// New Virtual functions
virtual F32 getTotalDistortion() = 0;
virtual const LLVector4a& getAvgDistortion() = 0;
virtual F32 getMaxDistortion() = 0;
virtual LLVector4a getVertexDistortion(S32 index, LLPolyMesh *mesh) = 0;
virtual const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **mesh) = 0;
virtual const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0;
// interface methods
F32 getDisplayOrder() const { return getInfo()->mEditGroupDisplayOrder; }
S32 getWearableType() const { return getInfo()->mWearableType; }
const std::string& getEditGroup() const { return getInfo()->mEditGroup; }
F32 getCameraDistance() const { return getInfo()->mCamDist; }
F32 getCameraAngle() const { return getInfo()->mCamAngle; } // degrees
F32 getCameraElevation() const { return getInfo()->mCamElevation; }
bool getShowSimple() const { return getInfo()->mShowSimple; }
F32 getSimpleMin() const { return getInfo()->mSimpleMin; }
F32 getSimpleMax() const { return getInfo()->mSimpleMax; }
bool getCrossWearable() const { return getInfo()->mCrossWearable; }
protected:
LLViewerVisualParam(const LLViewerVisualParam& pOther);
} LL_ALIGN_POSTFIX(16);
#endif // LL_LLViewerVisualParam_H
+793
View File
@@ -0,0 +1,793 @@
/**
* @file llwearable.cpp
* @brief LLWearable class implementation
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llavatarappearance.h"
#include "lllocaltextureobject.h"
#include "lltexlayer.h"
#include "lltexturemanagerbridge.h"
#include "llvisualparam.h"
#include "llavatarappearancedefines.h"
#include "llwearable.h"
#include "boost/bind.hpp"
using namespace LLAvatarAppearanceDefines;
// static
S32 LLWearable::sCurrentDefinitionVersion = 1;
// Private local functions
static std::string terse_F32_to_string(F32 f);
LLWearable::LLWearable()
: mDefinitionVersion(-1),
mName(),
mDescription(),
mPermissions(),
mSaleInfo(),
mType(LLWearableType::WT_NONE),
mSavedVisualParamMap(),
mVisualParamIndexMap(),
mTEMap(),
mSavedTEMap()
{
}
// virtual
LLWearable::~LLWearable()
{
for (std::set< LLWearableObserver* >::iterator itr = mObservers.begin(); itr != mObservers.end(); ++itr )
(*itr)->onDestroyed( this );
for (visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
{
LLVisualParam* vp = vp_pair.second;
vp->clearNextParam();
delete vp;
vp_pair.second = NULL;
}
destroyTextures();
}
const std::string& LLWearable::getTypeLabel() const
{
return LLWearableType::getInstance()->getTypeLabel(mType);
}
const std::string& LLWearable::getTypeName() const
{
return LLWearableType::getInstance()->getTypeName(mType);
}
LLAssetType::EType LLWearable::getAssetType() const
{
return LLWearableType::getInstance()->getAssetType(mType);
}
bool LLWearable::exportFile(const std::string& filename) const
{
llofstream ofs(filename.c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
return ofs.is_open() && exportStream(ofs);
}
// virtual
bool LLWearable::exportStream( std::ostream& output_stream ) const
{
if (!output_stream.good()) return false;
// header and version
output_stream << "LLWearable version " << mDefinitionVersion << "\n";
// name
output_stream << mName << "\n";
// description
output_stream << mDescription << "\n";
// permissions
if( !mPermissions.exportLegacyStream( output_stream ) )
{
return false;
}
// sale info
if( !mSaleInfo.exportLegacyStream( output_stream ) )
{
return false;
}
// wearable type
output_stream << "type " << (S32) getType() << "\n";
// parameters
output_stream << "parameters " << mVisualParamIndexMap.size() << "\n";
for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
{
S32 param_id = vp_pair.first;
const LLVisualParam* param = vp_pair.second;
F32 param_weight = param->getWeight();
output_stream << param_id << " " << terse_F32_to_string( param_weight ) << "\n";
}
// texture entries
output_stream << "textures " << mTEMap.size() << "\n";
for (const te_map_t::value_type& te_pair : mTEMap)
{
S32 te = te_pair.first;
const LLUUID& image_id = te_pair.second->getID();
output_stream << te << " " << image_id << "\n";
}
return true;
}
void LLWearable::createVisualParams(LLAvatarAppearance *avatarp)
{
for (LLViewerVisualParam* param = (LLViewerVisualParam*) avatarp->getFirstVisualParam();
param;
param = (LLViewerVisualParam*) avatarp->getNextVisualParam())
{
if (param->getWearableType() == mType)
{
LLVisualParam *clone_param = param->cloneParam(this);
clone_param->setParamLocation(LOC_UNKNOWN);
clone_param->setParamLocation(LOC_WEARABLE);
addVisualParam(clone_param);
}
}
// resync driver parameters to point to the newly cloned driven parameters
for (visual_param_index_map_t::value_type& param_pair : mVisualParamIndexMap)
{
LLVisualParam* param = param_pair.second;
LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam;
// need this line to disambiguate between versions of LLCharacter::getVisualParam()
LLVisualParam*(LLAvatarAppearance::*param_function)(S32)const = &LLAvatarAppearance::getVisualParam;
param->resetDrivenParams();
if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false))
{
if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true))
{
LL_DEBUGS("Avatar") << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL;
continue;
}
}
}
}
void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp)
{
LLTexLayerSet *layer_set = NULL;
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearance::getDictionary()->getTexture((ETextureIndex)te);
if (texture_dict && texture_dict->mIsUsedByBakedTexture)
{
const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
layer_set = avatarp->getAvatarLayerSet(baked_index);
}
if (layer_set)
{
layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this);
}
else
{
LL_WARNS() << "could not find layerset for LTO in wearable!" << LL_ENDL;
}
}
LLWearable::EImportResult LLWearable::importFile(const std::string& filename,
LLAvatarAppearance* avatarp )
{
llifstream ifs(filename.c_str(), std::ios_base::in | std::ios_base::binary);
return (! ifs.is_open())? FAILURE : importStream(ifs, avatarp);
}
// virtual
LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, LLAvatarAppearance* avatarp )
{
// *NOTE: changing the type or size of this buffer will require
// changes in the fscanf() code below.
// We are using a local max buffer size here to avoid issues
// if MAX_STRING size changes.
const U32 PARSE_BUFFER_SIZE = 2048;
char buffer[PARSE_BUFFER_SIZE]; /* Flawfinder: ignore */
char uuid_buffer[37]; /* Flawfinder: ignore */
// This data is being generated on the viewer.
// Impose some sane limits on parameter and texture counts.
const S32 MAX_WEARABLE_ASSET_TEXTURES = 100;
const S32 MAX_WEARABLE_ASSET_PARAMETERS = 1000;
if(!avatarp)
{
return LLWearable::FAILURE;
}
// read header and version
if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
{
LL_WARNS() << "Failed to read wearable asset input stream." << LL_ENDL;
return LLWearable::FAILURE;
}
if ( 1 != sscanf( /* Flawfinder: ignore */
buffer,
"LLWearable version %d\n",
&mDefinitionVersion ) )
{
return LLWearable::BAD_HEADER;
}
// Hack to allow wearables with definition version 24 to still load.
// This should only affect lindens and NDA'd testers who have saved wearables in 2.0
// the extra check for version == 24 can be removed before release, once internal testers
// have loaded these wearables again. See hack pt 2 at bottom of function to ensure that
// these wearables get re-saved with version definition 22.
if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 )
{
LL_WARNS() << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << LL_ENDL;
return LLWearable::FAILURE;
}
// name may be empty
if (!input_stream.good())
{
LL_WARNS() << "Bad Wearable asset: early end of input stream "
<< "while reading name" << LL_ENDL;
return LLWearable::FAILURE;
}
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
mName = buffer;
// description may be empty
if (!input_stream.good())
{
LL_WARNS() << "Bad Wearable asset: early end of input stream "
<< "while reading description" << LL_ENDL;
return LLWearable::FAILURE;
}
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
mDescription = buffer;
// permissions may have extra empty lines before the correct line
if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
{
LL_WARNS() << "Bad Wearable asset: early end of input stream "
<< "while reading permissions" << LL_ENDL;
return LLWearable::FAILURE;
}
S32 perm_version = -1;
if ( 1 != sscanf( buffer, " permissions %d\n", &perm_version ) ||
perm_version != 0 )
{
LL_WARNS() << "Bad Wearable asset: missing valid permissions" << LL_ENDL;
return LLWearable::FAILURE;
}
if( !mPermissions.importLegacyStream( input_stream ) )
{
return LLWearable::FAILURE;
}
// sale info
if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
{
LL_WARNS() << "Bad Wearable asset: early end of input stream "
<< "while reading sale info" << LL_ENDL;
return LLWearable::FAILURE;
}
S32 sale_info_version = -1;
if ( 1 != sscanf( buffer, " sale_info %d\n", &sale_info_version ) ||
sale_info_version != 0 )
{
LL_WARNS() << "Bad Wearable asset: missing valid sale_info" << LL_ENDL;
return LLWearable::FAILURE;
}
// Sale info used to contain next owner perm. It is now in the
// permissions. Thus, we read that out, and fix legacy
// objects. It's possible this op would fail, but it should pick
// up the vast majority of the tasks.
bool has_perm_mask = false;
U32 perm_mask = 0;
if( !mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask) )
{
return LLWearable::FAILURE;
}
if(has_perm_mask)
{
// fair use fix.
if(!(perm_mask & PERM_COPY))
{
perm_mask |= PERM_TRANSFER;
}
mPermissions.setMaskNext(perm_mask);
}
// wearable type
if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
{
LL_WARNS() << "Bad Wearable asset: early end of input stream "
<< "while reading type" << LL_ENDL;
return LLWearable::FAILURE;
}
S32 type = -1;
if ( 1 != sscanf( buffer, "type %d\n", &type ) )
{
LL_WARNS() << "Bad Wearable asset: bad type" << LL_ENDL;
return LLWearable::FAILURE;
}
if( 0 <= type && type < LLWearableType::WT_COUNT )
{
setType((LLWearableType::EType)type, avatarp);
}
else
{
mType = LLWearableType::WT_COUNT;
LL_WARNS() << "Bad Wearable asset: bad type #" << type << LL_ENDL;
return LLWearable::FAILURE;
}
// parameters header
if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
{
LL_WARNS() << "Bad Wearable asset: early end of input stream "
<< "while reading parameters header" << LL_ENDL;
return LLWearable::FAILURE;
}
S32 num_parameters = -1;
if ( 1 != sscanf( buffer, "parameters %d\n", &num_parameters ) )
{
LL_WARNS() << "Bad Wearable asset: missing parameters block" << LL_ENDL;
return LLWearable::FAILURE;
}
if ( num_parameters > MAX_WEARABLE_ASSET_PARAMETERS )
{
LL_WARNS() << "Bad Wearable asset: too many parameters, "
<< num_parameters << LL_ENDL;
return LLWearable::FAILURE;
}
if( num_parameters != mVisualParamIndexMap.size() )
{
LL_WARNS() << "Wearable parameter mismatch. Reading in "
<< num_parameters << " from file, but created "
<< mVisualParamIndexMap.size()
<< " from avatar parameters. type: "
<< getType() << LL_ENDL;
}
// parameters
S32 i;
for( i = 0; i < num_parameters; i++ )
{
if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
{
LL_WARNS() << "Bad Wearable asset: early end of input stream "
<< "while reading parameter #" << i << LL_ENDL;
return LLWearable::FAILURE;
}
S32 param_id = 0;
F32 param_weight = 0.f;
if ( 2 != sscanf( buffer, "%d %f\n", &param_id, &param_weight ) )
{
LL_WARNS() << "Bad Wearable asset: bad parameter, #" << i << LL_ENDL;
return LLWearable::FAILURE;
}
mSavedVisualParamMap[param_id] = param_weight;
}
// textures header
if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
{
LL_WARNS() << "Bad Wearable asset: early end of input stream "
<< "while reading textures header" << i << LL_ENDL;
return LLWearable::FAILURE;
}
S32 num_textures = -1;
if ( 1 != sscanf( buffer, "textures %d\n", &num_textures) )
{
LL_WARNS() << "Bad Wearable asset: missing textures block" << LL_ENDL;
return LLWearable::FAILURE;
}
if ( num_textures > MAX_WEARABLE_ASSET_TEXTURES )
{
LL_WARNS() << "Bad Wearable asset: too many textures, "
<< num_textures << LL_ENDL;
return LLWearable::FAILURE;
}
// textures
for( i = 0; i < num_textures; i++ )
{
if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE))
{
LL_WARNS() << "Bad Wearable asset: early end of input stream "
<< "while reading textures #" << i << LL_ENDL;
return LLWearable::FAILURE;
}
S32 te = 0;
if ( 2 != sscanf( /* Flawfinder: ignore */
buffer,
"%d %36s\n",
&te, uuid_buffer) )
{
LL_WARNS() << "Bad Wearable asset: bad texture, #" << i << LL_ENDL;
return LLWearable::FAILURE;
}
if (te >= ETextureIndex::TEX_NUM_INDICES) //createLayers() converts to ETextureIndex
{
LL_WARNS() << "Bad Wearable asset: bad texture index: " << te << LL_ENDL;
return LLWearable::FAILURE;
}
if( !LLUUID::validate( uuid_buffer ) )
{
LL_WARNS() << "Bad Wearable asset: bad texture uuid: "
<< uuid_buffer << LL_ENDL;
return LLWearable::FAILURE;
}
LLUUID id = LLUUID(uuid_buffer);
LLGLTexture* image = gTextureManagerBridgep->getFetchedTexture( id );
if( mTEMap.find(te) != mTEMap.end() )
{
delete mTEMap[te];
}
if( mSavedTEMap.find(te) != mSavedTEMap.end() )
{
delete mSavedTEMap[te];
}
LLUUID textureid(uuid_buffer);
mTEMap[te] = new LLLocalTextureObject(image, textureid);
mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
createLayers(te, avatarp);
}
// copy all saved param values to working params
revertValues();
return LLWearable::SUCCESS;
}
bool LLWearable::getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size)
{
if (!input_stream.good())
{
return false;
}
do
{
input_stream.getline(buffer, buffer_size);
}
while (input_stream.good() && buffer[0]=='\0');
return (buffer[0] != '\0');
}
void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp)
{
mType = type;
createVisualParams(avatarp);
}
LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index)
{
te_map_t::iterator iter = mTEMap.find(index);
if( iter != mTEMap.end() )
{
LLLocalTextureObject* lto = iter->second;
return lto;
}
return NULL;
}
const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const
{
te_map_t::const_iterator iter = mTEMap.find(index);
if( iter != mTEMap.end() )
{
const LLLocalTextureObject* lto = iter->second;
return lto;
}
return NULL;
}
std::vector<LLLocalTextureObject*> LLWearable::getLocalTextureListSeq()
{
std::vector<LLLocalTextureObject*> result;
for(te_map_t::value_type& te_pair : mTEMap)
{
LLLocalTextureObject* lto = te_pair.second;
result.push_back(lto);
}
return result;
}
void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject &lto)
{
if( mTEMap.find(index) != mTEMap.end() )
{
mTEMap.erase(index);
}
mTEMap[index] = new LLLocalTextureObject(lto);
}
void LLWearable::revertValues()
{
// FIXME DRANO - this triggers changes to driven params on avatar, potentially clobbering baked appearance.
//update saved settings so wearable is no longer dirty
// One loop should be necessary here
for (param_map_t::value_type& vp_pair : mSavedVisualParamMap)
{
S32 id = vp_pair.first;
LLVisualParam *param = getVisualParam(id);
if(param)
{
F32 value = vp_pair.second;
// <FS:Ansariel> [Legacy Bake]
//setVisualParamWeight(id, value);
setVisualParamWeight(id, value, true);
mSavedVisualParamMap[id] = param->getWeight();
}
}
syncImages(mSavedTEMap, mTEMap);
}
void LLWearable::saveValues()
{
//update saved settings so wearable is no longer dirty
mSavedVisualParamMap.clear();
for (const visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
{
S32 id = vp_pair.first;
LLVisualParam *wearable_param = vp_pair.second;
F32 value = wearable_param->getWeight();
mSavedVisualParamMap[id] = value;
}
// Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed)
syncImages(mTEMap, mSavedTEMap);
}
void LLWearable::syncImages(te_map_t &src, te_map_t &dst)
{
// Deep copy of src (copies only those tes that are current, filling in defaults where needed)
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
{
if (LLAvatarAppearance::getDictionary()->getTEWearableType((ETextureIndex) te) == mType)
{
te_map_t::const_iterator iter = src.find(te);
LLUUID image_id;
LLGLTexture *image = NULL;
LLLocalTextureObject *lto = NULL;
if(iter != src.end())
{
// there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map.
lto = iter->second;
image = lto->getImage();
image_id = lto->getID();
}
else
{
// there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map.
image_id = getDefaultTextureImageID((ETextureIndex) te);
image = gTextureManagerBridgep->getFetchedTexture( image_id );
}
if( dst.find(te) != dst.end() )
{
// there's already an entry in the destination map for the texture. Just update its values.
dst[te]->setImage(image);
dst[te]->setID(image_id);
}
else
{
// no entry found in the destination map, we need to create a new Local Texture Object
dst[te] = new LLLocalTextureObject(image, image_id);
}
if( lto )
{
// If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map.
dst[te]->setBakedReady(lto->getBakedReady());
dst[te]->setDiscard(lto->getDiscard());
}
}
}
}
void LLWearable::destroyTextures()
{
std::for_each(mTEMap.begin(), mTEMap.end(), DeletePairedPointer());
mTEMap.clear();
std::for_each(mSavedTEMap.begin(), mSavedTEMap.end(), DeletePairedPointer());
mSavedTEMap.clear();
}
void LLWearable::addVisualParam(LLVisualParam *param)
{
if( mVisualParamIndexMap[param->getID()] )
{
delete mVisualParamIndexMap[param->getID()];
}
param->setIsDummy(false);
param->setParamLocation(LOC_WEARABLE);
mVisualParamIndexMap[param->getID()] = param;
mSavedVisualParamMap[param->getID()] = param->getDefaultWeight();
}
// <FS:Ansariel> [Legacy Bake]
//void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
void LLWearable::setVisualParamWeight(S32 param_index, F32 value, bool upload_bake)
{
visual_param_index_map_t::iterator found = mVisualParamIndexMap.find(param_index);
if(found != mVisualParamIndexMap.end())
{
LLVisualParam *wearable_param = found->second;
// <FS:Ansariel> [Legacy Bake]
//wearable_param->setWeight(value);
wearable_param->setWeight(value, upload_bake);
}
else
{
LL_WARNS() << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
}
}
F32 LLWearable::getVisualParamWeight(S32 param_index) const
{
visual_param_index_map_t::const_iterator found = mVisualParamIndexMap.find(param_index);
if(found != mVisualParamIndexMap.end())
{
return found->second->getWeight();
}
else
{
LL_WARNS() << "LLWearable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL;
}
return (F32)-1.0;
}
LLVisualParam* LLWearable::getVisualParam(S32 index) const
{
visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(index);
return (iter == mVisualParamIndexMap.end()) ? NULL : iter->second;
}
void LLWearable::getVisualParams(visual_param_vec_t &list)
{
// add all visual params to the passed-in vector
for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
{
list.push_back(vp_pair.second);
}
}
// <FS:Ansariel> [Legacy Bake]
//void LLWearable::animateParams(F32 delta)
void LLWearable::animateParams(F32 delta, bool upload_bake)
{
for(visual_param_index_map_t::value_type& vp_pair : mVisualParamIndexMap)
{
LLVisualParam *param = (LLVisualParam*)vp_pair.second;
// <FS:Ansariel> [Legacy Bake]
//param->animate(delta);
param->animate(delta, upload_bake);
}
}
LLColor4 LLWearable::getClothesColor(S32 te) const
{
LLColor4 color;
U32 param_name[3];
if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
{
for( U8 index = 0; index < 3; index++ )
{
color.mV[index] = getVisualParamWeight(param_name[index]);
}
}
return color;
}
// <FS:Ansariel> [Legacy Bake]
//void LLWearable::setClothesColor( S32 te, const LLColor4& new_color)
void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, bool upload_bake)
{
U32 param_name[3];
if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
{
for( U8 index = 0; index < 3; index++ )
{
// <FS:Ansariel> [Legacy Bake]
//setVisualParamWeight(param_name[index], new_color.mV[index]);
setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake);
}
}
}
void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
{
if (!avatarp) return;
// Pull params
for( const LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() )
{
// cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the
// avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way.
if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) )
{
S32 param_id = param->getID();
F32 weight = getVisualParamWeight(param_id);
// <FS:Ansariel> [Legacy Bake]
//avatarp->setVisualParamWeight( param_id, weight);
avatarp->setVisualParamWeight( param_id, weight, false);
}
}
}
std::string terse_F32_to_string(F32 f)
{
std::string r = llformat("%.2f", f);
auto len = r.length();
// "1.20" -> "1.2"
// "24.00" -> "24."
while (len > 0 && ('0' == r[len - 1]))
{
r.erase(len-1, 1);
len--;
}
if ('.' == r[len - 1])
{
// "24." -> "24"
r.erase(len-1, 1);
}
else if (('-' == r[0]) && ('0' == r[1]))
{
// "-0.59" -> "-.59"
r.erase(1, 1);
}
else if ('0' == r[0])
{
// "0.59" -> ".59"
r.erase(0, 1);
}
return r;
}
+164
View File
@@ -0,0 +1,164 @@
/**
* @file llwearable.h
* @brief LLWearable class header file
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLWEARABLE_H
#define LL_LLWEARABLE_H
#include "llavatarappearancedefines.h"
#include "llpermissions.h"
#include "llsaleinfo.h"
#include "llwearabletype.h"
class LLMD5; // <FS:Ansariel> [Legacy Bake]
class LLVisualParam;
class LLTexGlobalColorInfo;
class LLTexGlobalColor;
class LLLocalTextureObject;
class LLAvatarAppearance;
// Abstract class.
class LLWearable
{
// <FS:ND> Try to see if this fixes the crash in LLPanelEditWearable::isDirty, that is the wearable dets destroyed before the panel
public:
class LLWearableObserver
{
public:
virtual void onDestroyed(LLWearable const * ) = 0;
};
public:
void registerObserver(LLWearableObserver *aObserver){ mObservers.insert(aObserver); }
void unregisterObserver(LLWearableObserver *aObserver){ mObservers.erase(aObserver); }
private:
std::set< LLWearableObserver* > mObservers;
// </FS:ND>
//--------------------------------------------------------------------
// Constructors and destructors
//--------------------------------------------------------------------
public:
LLWearable();
virtual ~LLWearable();
//--------------------------------------------------------------------
// Accessors
//--------------------------------------------------------------------
public:
LLWearableType::EType getType() const { return mType; }
void setType(LLWearableType::EType type, LLAvatarAppearance *avatarp);
const std::string& getName() const { return mName; }
void setName(const std::string& name) { mName = name; }
const std::string& getDescription() const { return mDescription; }
void setDescription(const std::string& desc) { mDescription = desc; }
const LLPermissions& getPermissions() const { return mPermissions; }
void setPermissions(const LLPermissions& p) { mPermissions = p; }
const LLSaleInfo& getSaleInfo() const { return mSaleInfo; }
void setSaleInfo(const LLSaleInfo& info) { mSaleInfo = info; }
const std::string& getTypeLabel() const;
const std::string& getTypeName() const;
LLAssetType::EType getAssetType() const;
S32 getDefinitionVersion() const { return mDefinitionVersion; }
void setDefinitionVersion( S32 new_version ) { mDefinitionVersion = new_version; }
static S32 getCurrentDefinitionVersion() { return LLWearable::sCurrentDefinitionVersion; }
public:
typedef std::vector<LLVisualParam*> visual_param_vec_t;
virtual void writeToAvatar(LLAvatarAppearance* avatarp);
enum EImportResult
{
FAILURE = 0,
SUCCESS,
BAD_HEADER
};
bool exportFile(const std::string& filename) const;
EImportResult importFile(const std::string& filename, LLAvatarAppearance* avatarp );
virtual bool exportStream( std::ostream& output_stream ) const;
virtual EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );
static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; }
virtual LLUUID getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const = 0;
LLLocalTextureObject* getLocalTextureObject(S32 index);
const LLLocalTextureObject* getLocalTextureObject(S32 index) const;
std::vector<LLLocalTextureObject*> getLocalTextureListSeq();
void setLocalTextureObject(S32 index, LLLocalTextureObject &lto);
void addVisualParam(LLVisualParam *param);
// <FS:Ansariel> [Legacy Bake]
//void setVisualParamWeight(S32 index, F32 value);
void setVisualParamWeight(S32 index, F32 value, bool upload_bake);
F32 getVisualParamWeight(S32 index) const;
LLVisualParam* getVisualParam(S32 index) const;
void getVisualParams(visual_param_vec_t &list);
// <FS:Ansariel> [Legacy Bake]
//void animateParams(F32 delta);
void animateParams(F32 delta, bool upload_bake);
LLColor4 getClothesColor(S32 te) const;
// <FS:Ansariel> [Legacy Bake]
//void setClothesColor( S32 te, const LLColor4& new_color);
void setClothesColor( S32 te, const LLColor4& new_color, bool upload_bake);
virtual void revertValues();
virtual void saveValues();
// Something happened that requires the wearable to be updated (e.g. worn/unworn).
virtual void setUpdated() const = 0;
// <FS:Ansariel> [Legacy Bake]
// Update the baked texture hash.
virtual void addToBakedTextureHash(LLMD5& hash) const = 0;
typedef std::map<S32, LLVisualParam *> visual_param_index_map_t;
visual_param_index_map_t mVisualParamIndexMap;
protected:
typedef std::map<S32, LLLocalTextureObject*> te_map_t;
void syncImages(te_map_t &src, te_map_t &dst);
void destroyTextures();
void createVisualParams(LLAvatarAppearance *avatarp);
void createLayers(S32 te, LLAvatarAppearance *avatarp);
bool getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size);
static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml.
S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created.
std::string mName;
std::string mDescription;
LLPermissions mPermissions;
LLSaleInfo mSaleInfo;
LLWearableType::EType mType;
typedef std::map<S32, F32> param_map_t;
param_map_t mSavedVisualParamMap; // last saved version of visual params
te_map_t mTEMap; // maps TE to LocalTextureObject
te_map_t mSavedTEMap; // last saved version of TEMap
};
#endif // LL_LLWEARABLE_H
+397
View File
@@ -0,0 +1,397 @@
/**
* @file llwearabledata.cpp
* @brief LLWearableData class implementation
*
* $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$
*/
#include "linden_common.h"
#include "llwearabledata.h"
#include "llavatarappearance.h"
#include "llavatarappearancedefines.h"
#include "lldriverparam.h"
#include "llmd5.h" // <FS:Ansariel> [Legacy Bake]
LLWearableData::LLWearableData() :
mAvatarAppearance(NULL)
{
}
// virtual
LLWearableData::~LLWearableData()
{
}
using namespace LLAvatarAppearanceDefines;
LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index)
{
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
{
return NULL;
}
wearableentry_vec_t& wearable_vec = wearable_iter->second;
if (index>=wearable_vec.size())
{
return NULL;
}
else
{
return wearable_vec[index];
}
}
void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable)
{
LLWearable *old_wearable = getWearable(type,index);
if (!old_wearable)
{
pushWearable(type,wearable);
return;
}
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
{
LL_WARNS() << "invalid type, type " << type << " index " << index << LL_ENDL;
return;
}
wearableentry_vec_t& wearable_vec = wearable_iter->second;
if (index>=wearable_vec.size())
{
LL_WARNS() << "invalid index, type " << type << " index " << index << LL_ENDL;
}
else
{
wearable_vec[index] = wearable;
old_wearable->setUpdated();
const bool removed = false;
wearableUpdated(wearable, removed);
}
}
void LLWearableData::pushWearable(const LLWearableType::EType type,
LLWearable *wearable,
bool trigger_updated /* = true */)
{
if (wearable == NULL)
{
// no null wearables please!
LL_WARNS() << "Null wearable sent for type " << type << LL_ENDL;
// <FS:Ansariel> Prevent adding null wearables
return;
}
if (canAddWearable(type))
{
// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0)
// Don't add the same wearable twice
U32 idxWearable = 0;
if (!getWearableIndex(wearable, idxWearable))
mWearableDatas[type].push_back(wearable);
else
llassert(false); // pushWearable() on an already added wearable is a bug *somewhere*
// [/RLVa:KB]
// mWearableDatas[type].push_back(wearable); mWearableDatas[type].push_back(wearable);
if (trigger_updated)
{
const bool removed = false;
wearableUpdated(wearable, removed);
}
}
}
// virtual
void LLWearableData::wearableUpdated(LLWearable *wearable, bool removed)
{
wearable->setUpdated();
if (!removed)
{
pullCrossWearableValues(wearable->getType());
}
}
void LLWearableData::eraseWearable(LLWearable *wearable)
{
if (wearable == NULL)
{
// nothing to do here. move along.
return;
}
const LLWearableType::EType type = wearable->getType();
U32 index;
if (getWearableIndex(wearable,index))
{
eraseWearable(type, index);
}
}
void LLWearableData::eraseWearable(const LLWearableType::EType type, U32 index)
{
LLWearable *wearable = getWearable(type, index);
if (wearable)
{
mWearableDatas[type].erase(mWearableDatas[type].begin() + index);
const bool removed = true;
wearableUpdated(wearable, removed);
}
}
//void LLWearableData::clearWearableType(const LLWearableType::EType type)
//{
// wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
// if (wearable_iter == mWearableDatas.end())
// {
// return;
// }
// wearableentry_vec_t& wearable_vec = wearable_iter->second;
// wearable_vec.clear();
//}
bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b)
{
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
{
return false;
}
wearableentry_vec_t& wearable_vec = wearable_iter->second;
// removed 0 > index_a and index_b comparisions - can never be true
if (index_a >= wearable_vec.size()) return false;
if (index_b >= wearable_vec.size()) return false;
LLWearable* wearable = wearable_vec[index_a];
wearable_vec[index_a] = wearable_vec[index_b];
wearable_vec[index_b] = wearable;
return true;
}
void LLWearableData::pullCrossWearableValues(const LLWearableType::EType type)
{
llassert(mAvatarAppearance);
// scan through all of the avatar's visual parameters
for (LLViewerVisualParam* param = (LLViewerVisualParam*) mAvatarAppearance->getFirstVisualParam();
param;
param = (LLViewerVisualParam*) mAvatarAppearance->getNextVisualParam())
{
if( param )
{
LLDriverParam *driver_param = dynamic_cast<LLDriverParam*>(param);
if(driver_param)
{
// parameter is a driver parameter, have it update its cross-driven params
driver_param->updateCrossDrivenParams(type);
}
}
}
}
bool LLWearableData::getWearableIndex(const LLWearable *wearable, U32& index_found) const
{
if (wearable == NULL)
{
return false;
}
const LLWearableType::EType type = wearable->getType();
wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
{
LL_WARNS() << "tried to get wearable index with an invalid type!" << LL_ENDL;
return false;
}
const wearableentry_vec_t& wearable_vec = wearable_iter->second;
for(U32 index = 0; index < wearable_vec.size(); index++)
{
if (wearable_vec[index] == wearable)
{
index_found = index;
return true;
}
}
return false;
}
U32 LLWearableData::getClothingLayerCount() const
{
U32 count = 0;
LLWearableType *wr_inst = LLWearableType::getInstance();
for (S32 i = 0; i < LLWearableType::WT_COUNT; i++)
{
LLWearableType::EType type = (LLWearableType::EType)i;
if (wr_inst->getAssetType(type)==LLAssetType::AT_CLOTHING)
{
count += getWearableCount(type);
}
}
return count;
}
bool LLWearableData::canAddWearable(const LLWearableType::EType type) const
{
LLAssetType::EType a_type = LLWearableType::getInstance()->getAssetType(type);
if (a_type==LLAssetType::AT_CLOTHING)
{
if (type == LLWearableType::WT_PHYSICS) return (getWearableCount(type) < 1); // <FS:Ansariel> Don't add physics layer
return (getClothingLayerCount() < MAX_CLOTHING_LAYERS);
}
else if (a_type==LLAssetType::AT_BODYPART)
{
return (getWearableCount(type) < 1);
}
else
{
return false;
}
}
bool LLWearableData::isOnTop(LLWearable* wearable) const
{
if (!wearable) return false;
const LLWearableType::EType type = wearable->getType();
return ( getTopWearable(type) == wearable );
}
const LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index) const
{
wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
{
return NULL;
}
const wearableentry_vec_t& wearable_vec = wearable_iter->second;
if (index>=wearable_vec.size())
{
return NULL;
}
else
{
return wearable_vec[index];
}
}
LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type)
{
U32 count = getWearableCount(type);
if ( count == 0)
{
return NULL;
}
return getWearable(type, count-1);
}
const LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type) const
{
U32 count = getWearableCount(type);
if ( count == 0)
{
return NULL;
}
return getWearable(type, count-1);
}
LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type)
{
if (getWearableCount(type) == 0)
{
return NULL;
}
return getWearable(type, 0);
}
const LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type) const
{
if (getWearableCount(type) == 0)
{
return NULL;
}
return getWearable(type, 0);
}
U32 LLWearableData::getWearableCount(const LLWearableType::EType type) const
{
wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
{
return 0;
}
const wearableentry_vec_t& wearable_vec = wearable_iter->second;
return static_cast<U32>(wearable_vec.size());
}
U32 LLWearableData::getWearableCount(const U32 tex_index) const
{
const LLWearableType::EType wearable_type = LLAvatarAppearance::getDictionary()->getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index);
return getWearableCount(wearable_type);
}
// <FS:Ansariel> [Legacy Bake]
LLUUID LLWearableData::computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
bool generate_valid_hash) // Set to false if you want to upload the baked texture w/o putting it in the cache
{
LLUUID hash_id;
bool hash_computed = false;
LLMD5 hash;
const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearance::getDictionary()->getBakedTexture(baked_index);
for (U8 i=0; i < baked_dict->mWearables.size(); i++)
{
const LLWearableType::EType baked_type = baked_dict->mWearables[i];
const U32 num_wearables = getWearableCount(baked_type);
for (U32 index = 0; index < num_wearables; ++index)
{
const LLWearable* wearable = getWearable(baked_type,index);
if (wearable)
{
wearable->addToBakedTextureHash(hash);
hash_computed = true;
}
}
}
if (hash_computed)
{
hash.update((const unsigned char*)baked_dict->mWearablesHashID.mData, UUID_BYTES);
if (!generate_valid_hash)
{
invalidateBakedTextureHash(hash);
}
hash.finalize();
hash.raw_digest(hash_id.mData);
}
return hash_id;
}
// </FS:Ansariel> [Legacy Bake]

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