diff options
150 files changed, 11189 insertions, 6516 deletions
@@ -63,6 +63,7 @@ pre_build()      -DVIEWER_CHANNEL:STRING="$viewer_channel" \      -DVIEWER_LOGIN_CHANNEL:STRING="$login_channel" \      -DINSTALL_PROPRIETARY:BOOL=ON \ +    -DRELEASE_CRASH_REPORTING:BOOL=ON \      -DLOCALIZESETUP:BOOL=ON \      -DPACKAGE:BOOL=ON      -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE diff --git a/doc/contributions.txt b/doc/contributions.txt index e38a33b54d..32ae801d19 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -61,19 +61,27 @@ Aimee Trescothick  Alejandro Rosenthal  	VWR-1184  Aleric Inglewood +	SNOW-240  	SNOW-522  	SNOW-626  	SNOW-756  	SNOW-764  	VWR-10001 +	VWR-10579  	VWR-10759  	VWR-10837  	VWR-12691  	VWR-12984  	VWR-13996  	VWR-14426 +	VWR-24247 +	VWR-24251 +	VWR-24252 +	VWR-24254 +	VWR-24261  	SNOW-84  	SNOW-477 +	SNOW-744  	SNOW-766  	STORM-163  Ales Beaumont @@ -213,6 +221,8 @@ Catherine Pfeffer  Celierra Darling  	VWR-1274  	VWR-6975 +Cron Stardust +	VWR-10579  Cypren Christenson  	STORM-417  Dale Glass @@ -357,10 +367,12 @@ Joghert LeSabre  	VWR-64  Jonathan Yap  	VWR-17801 +	STORM-523  	STORM-616  	STORM-679  	STORM-596  	STORM-726 +	STORM-785  Kage Pixel  	VWR-11  Ken March @@ -589,6 +601,7 @@ Robin Cornelius  	STORM-422  	VWR-2488  	VWR-9557 +	VWR-10579  	VWR-11128  	VWR-12533  	VWR-12587 diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index d01e1869b6..6d17a6f402 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -43,6 +43,7 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)  add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)  add_subdirectory(${LIBS_OPEN_PREFIX}llcommon)  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) @@ -53,10 +54,6 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llvfs)  add_subdirectory(${LIBS_OPEN_PREFIX}llwindow)  add_subdirectory(${LIBS_OPEN_PREFIX}llxml) -if (EXISTS ${LIBS_CLOSED_DIR}llkdu) -  add_subdirectory(${LIBS_CLOSED_PREFIX}llkdu) -endif (EXISTS ${LIBS_CLOSED_DIR}llkdu) -  add_subdirectory(${LIBS_OPEN_PREFIX}lscript)  if (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 40a04e72f7..87f1dcf07d 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -4,27 +4,28 @@  include(Variables) -  # Portable compilation flags. - -if (EXISTS ${CMAKE_SOURCE_DIR}/llphysics) -  # The release build should only offer to send crash reports if we're -  # building from a Linden internal source tree. -  set(release_crash_reports 1) -else (EXISTS ${CMAKE_SOURCE_DIR}/llphysics) -  set(release_crash_reports 0)  -endif (EXISTS ${CMAKE_SOURCE_DIR}/llphysics) -  set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG -DLL_DEBUG=1")  set(CMAKE_CXX_FLAGS_RELEASE -    "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=${release_crash_reports} -DNDEBUG")  +    "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DNDEBUG")   set(CMAKE_CXX_FLAGS_RELWITHDEBINFO  -    "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") +    "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") +# Configure crash reporting +set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds") +set(NON_RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in developer builds") -# Don't bother with a MinSizeRel build. +if(RELEASE_CRASH_REPORTING) +  set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DLL_SEND_CRASH_REPORTS=1") +endif() + +if(NON_RELEASE_CRASH_REPORTING) +  set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLL_SEND_CRASH_REPORTS=1") +  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1") +endif()   +# Don't bother with a MinSizeRel build.  set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING      "Supported build types." FORCE) diff --git a/indra/cmake/BerkeleyDB.cmake b/indra/cmake/BerkeleyDB.cmake index d98e79179d..e3ca0fd77d 100644 --- a/indra/cmake/BerkeleyDB.cmake +++ b/indra/cmake/BerkeleyDB.cmake @@ -6,6 +6,11 @@ set(DB_FIND_REQUIRED ON)  if (STANDALONE)    include(FindBerkeleyDB)  else (STANDALONE) -  set(DB_LIBRARIES db-4.2) +  if (LINUX) +    # Need to add dependency pthread explicitely to support ld.gold. +    set(DB_LIBRARIES db-4.2 pthread) +  else (LINUX) +    set(DB_LIBRARIES db-4.2) +  endif (LINUX)    set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)  endif (STANDALONE) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index ff54b45e8b..e970116c7e 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -33,6 +33,7 @@ set(cmake_SOURCE_FILES      FindMySQL.cmake      FindOpenJPEG.cmake      FindXmlRpcEpi.cmake +    FindZLIB.cmake      FMOD.cmake      FreeType.cmake      GLOD.cmake diff --git a/indra/cmake/CURL.cmake b/indra/cmake/CURL.cmake index 6e5fed4d52..9aba08e573 100644 --- a/indra/cmake/CURL.cmake +++ b/indra/cmake/CURL.cmake @@ -10,10 +10,10 @@ else (STANDALONE)    use_prebuilt_binary(curl)    if (WINDOWS)      set(CURL_LIBRARIES  -    debug libcurld -    optimized libcurl) +    debug libcurld.lib +    optimized libcurl.lib)    else (WINDOWS) -    set(CURL_LIBRARIES curl) +    set(CURL_LIBRARIES libcurl.a)    endif (WINDOWS)    set(CURL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)  endif (STANDALONE) diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 85bb281354..bb108d7dd9 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -64,22 +64,6 @@ if(WINDOWS)        set(release_files ${release_files} fmod.dll)      endif (FMOD) -    #******************************* -    # LLKDU -    set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu") -    if(NOT EXISTS ${internal_llkdu_path}) -        if (EXISTS "${debug_src_dir}/llkdu.dll") -            set(debug_llkdu_src "${debug_src_dir}/llkdu.dll") -            set(debug_llkdu_dst "${SHARED_LIB_STAGING_DIR_DEBUG}/llkdu.dll") -        endif (EXISTS "${debug_src_dir}/llkdu.dll") - -        if (EXISTS "${release_src_dir}/llkdu.dll") -            set(release_llkdu_src "${release_src_dir}/llkdu.dll") -            set(release_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELEASE}/llkdu.dll") -            set(relwithdebinfo_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}/llkdu.dll") -        endif (EXISTS "${release_src_dir}/llkdu.dll") -    endif (NOT EXISTS ${internal_llkdu_path}) -  #*******************************  # Copy MS C runtime dlls, required for packaging.  # *TODO - Adapt this to support VC9 @@ -180,21 +164,6 @@ elseif(DARWIN)      # fmod is statically linked on darwin      set(fmod_files "") -    #******************************* -    # LLKDU -    set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu") -    if(NOT EXISTS ${internal_llkdu_path}) -        if (EXISTS "${debug_src_dir}/libllkdu.dylib") -            set(debug_llkdu_src "${debug_src_dir}/libllkdu.dylib") -            set(debug_llkdu_dst "${SHARED_LIB_STAGING_DIR_DEBUG}/libllkdu.dylib") -        endif (EXISTS "${debug_src_dir}/libllkdu.dylib") - -        if (EXISTS "${release_src_dir}/libllkdu.dylib") -            set(release_llkdu_src "${release_src_dir}/libllkdu.dylib") -            set(release_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELEASE}/libllkdu.dylib") -            set(relwithdebinfo_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}/libllkdu.dylib") -        endif (EXISTS "${release_src_dir}/libllkdu.dylib") -    endif (NOT EXISTS ${internal_llkdu_path})  elseif(LINUX)      # linux is weird, multiple side by side configurations aren't supported      # and we don't seem to have any debug shared libs built yet anyways... @@ -249,21 +218,6 @@ elseif(LINUX)        set(release_files ${release_files} "libfmod-3.75.so")      endif (FMOD) -    #******************************* -    # LLKDU -    set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu") -    if(NOT EXISTS ${internal_llkdu_path}) -        if (EXISTS "${debug_src_dir}/libllkdu.so") -            set(debug_llkdu_src "${debug_src_dir}/libllkdu.so") -            set(debug_llkdu_dst "${SHARED_LIB_STAGING_DIR_DEBUG}/libllkdu.so") -        endif (EXISTS "${debug_src_dir}/libllkdu.so") - -        if (EXISTS "${release_src_dir}/libllkdu.so") -            set(release_llkdu_src "${release_src_dir}/libllkdu.so") -            set(release_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELEASE}/libllkdu.so") -            set(relwithdebinfo_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}/libllkdu.so") -        endif (EXISTS "${release_src_dir}/libllkdu.so") -    endif(NOT EXISTS ${internal_llkdu_path})  else(WINDOWS)      message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...")      set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux") @@ -341,40 +295,29 @@ copy_if_different(      )  set(third_party_targets ${third_party_targets} ${out_targets}) -#******************************* -# LLKDU -set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu") -if(NOT EXISTS ${internal_llkdu_path}) -    if (EXISTS "${debug_llkdu_src}") -        ADD_CUSTOM_COMMAND( -            OUTPUT  ${debug_llkdu_dst} -            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${debug_llkdu_src} ${debug_llkdu_dst} -            DEPENDS ${debug_llkdu_src} -            COMMENT "Copying llkdu.dll ${SHARED_LIB_STAGING_DIR_DEBUG}" -            ) -        set(third_party_targets ${third_party_targets} $} ${debug_llkdu_dst}) -    endif (EXISTS "${debug_llkdu_src}") - -    if (EXISTS "${release_llkdu_src}") -        ADD_CUSTOM_COMMAND( -            OUTPUT  ${release_llkdu_dst} -            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${release_llkdu_src} ${release_llkdu_dst} -            DEPENDS ${release_llkdu_src} -            COMMENT "Copying llkdu.dll ${SHARED_LIB_STAGING_DIR_RELEASE}" -            ) -        set(third_party_targets ${third_party_targets} ${release_llkdu_dst}) - -        ADD_CUSTOM_COMMAND( -            OUTPUT  ${relwithdebinfo_llkdu_dst} -            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${release_llkdu_src} ${relwithdebinfo_llkdu_dst} -            DEPENDS ${release_llkdu_src} -            COMMENT "Copying llkdu.dll ${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}" -            ) -        set(third_party_targets ${third_party_targets} ${relwithdebinfo_llkdu_dst}) -    endif (EXISTS "${release_llkdu_src}") - -endif (NOT EXISTS ${internal_llkdu_path}) - +if (FMOD_SDK_DIR) +    copy_if_different( +        ${FMOD_SDK_DIR}  +        "${CMAKE_CURRENT_BINARY_DIR}/Debug" +        out_targets  +        ${fmod_files} +        ) +    set(all_targets ${all_targets} ${out_targets}) +    copy_if_different( +        ${FMOD_SDK_DIR}  +        "${CMAKE_CURRENT_BINARY_DIR}/Release" +        out_targets  +        ${fmod_files} +        ) +    set(all_targets ${all_targets} ${out_targets}) +    copy_if_different( +        ${FMOD_SDK_DIR}  +        "${CMAKE_CURRENT_BINARY_DIR}/RelWithDbgInfo" +        out_targets  +        ${fmod_files} +        ) +    set(all_targets ${all_targets} ${out_targets}) +endif (FMOD_SDK_DIR)  if(NOT STANDALONE)    add_custom_target( diff --git a/indra/cmake/FindJsonCpp.cmake b/indra/cmake/FindJsonCpp.cmake index 9d16f2aaab..cf84b309c1 100644 --- a/indra/cmake/FindJsonCpp.cmake +++ b/indra/cmake/FindJsonCpp.cmake @@ -21,7 +21,12 @@ EXEC_PROGRAM(${CMAKE_CXX_COMPILER}              OUTPUT_STRIP_TRAILING_WHITESPACE              ) +# Try to find a library that was compiled with the same compiler version as we currently use.  SET(JSONCPP_NAMES ${JSONCPP_NAMES} libjson_linux-gcc-${_gcc_COMPILER_VERSION}_libmt.so) +IF (STANDALONE) +	# On standalone, assume that the system installed library was compiled with the used compiler. +	SET(JSONCPP_NAMES ${JSONCPP_NAMES} libjson.so) +ENDIF (STANDALONE)  FIND_LIBRARY(JSONCPP_LIBRARY    NAMES ${JSONCPP_NAMES}    PATHS /usr/lib /usr/local/lib diff --git a/indra/cmake/FindLLQtWebkit.cmake b/indra/cmake/FindLLQtWebkit.cmake new file mode 100644 index 0000000000..c747ec32a2 --- /dev/null +++ b/indra/cmake/FindLLQtWebkit.cmake @@ -0,0 +1,62 @@ +# -*- cmake -*- + +# - Find llqtwebkit +# Find the llqtwebkit includes and library +# This module defines +#  LLQTWEBKIT_INCLUDE_DIR, where to find llqtwebkit.h, etc. +#  LLQTWEBKIT_LIBRARY, the llqtwebkit library with full path. +#  LLQTWEBKIT_FOUND, If false, do not try to use llqtwebkit. +# also defined, but not for general use are +#  LLQTWEBKIT_LIBRARIES, the libraries needed to use llqtwebkit. +#  LLQTWEBKIT_LIBRARY_DIRS, where to find the llqtwebkit library. +#  LLQTWEBKIT_DEFINITIONS - You should add_definitions(${LLQTWEBKIT_DEFINITIONS}) +#      before compiling code that includes llqtwebkit library files. + +# Try to use pkg-config first. +# This allows to have two different libllqtwebkit packages installed: +# one for viewer 2.x and one for viewer 1.x. +include(FindPkgConfig) +if (PKG_CONFIG_FOUND) +    if (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION) +        set(_PACKAGE_ARGS libllqtwebkit>=${LLQtWebkit_FIND_VERSION} REQUIRED) +    else (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION) +        set(_PACKAGE_ARGS libllqtwebkit) +    endif (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION) +    if (NOT "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_LESS "2.8") +      # As virtually nobody will have a pkg-config file for this, do this check always quiet. +      # Unfortunately cmake 2.8 or higher is required for pkg_check_modules to have a 'QUIET'. +      set(_PACKAGE_ARGS ${_PACKAGE_ARGS} QUIET) +    endif () +    pkg_check_modules(LLQTWEBKIT ${_PACKAGE_ARGS}) +endif (PKG_CONFIG_FOUND) +set(LLQTWEBKIT_DEFINITIONS ${LLQTWEBKIT_CFLAGS_OTHER}) + +find_path(LLQTWEBKIT_INCLUDE_DIR llqtwebkit.h NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_INCLUDE_DIRS}) + +find_library(LLQTWEBKIT_LIBRARY NAMES llqtwebkit NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_LIBRARY_DIRS}) + +if (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND)	# If pkg-config couldn't find it, pretend we don't have pkg-config. +   set(LLQTWEBKIT_LIBRARIES llqtwebkit) +   get_filename_component(LLQTWEBKIT_LIBRARY_DIRS ${LLQTWEBKIT_LIBRARY} PATH) +endif (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND) + +# Handle the QUIETLY and REQUIRED arguments and set LLQTWEBKIT_FOUND +# to TRUE if all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( +  LLQTWEBKIT +  DEFAULT_MSG +  LLQTWEBKIT_LIBRARY +  LLQTWEBKIT_INCLUDE_DIR +  LLQTWEBKIT_LIBRARIES +  LLQTWEBKIT_LIBRARY_DIRS +  ) + +mark_as_advanced( +  LLQTWEBKIT_LIBRARY +  LLQTWEBKIT_INCLUDE_DIR +  LLQTWEBKIT_LIBRARIES +  LLQTWEBKIT_LIBRARY_DIRS +  LLQTWEBKIT_DEFINITIONS +  ) + diff --git a/indra/cmake/FindNDOF.cmake b/indra/cmake/FindNDOF.cmake new file mode 100644 index 0000000000..6dcf590a53 --- /dev/null +++ b/indra/cmake/FindNDOF.cmake @@ -0,0 +1,39 @@ +# -*- cmake -*- + +# - Find NDOF +# Find the NDOF includes and library +# This module defines +#  NDOF_INCLUDE_DIR, where to find ndofdev_external.h, etc. +#  NDOF_LIBRARY, the library needed to use NDOF. +#  NDOF_FOUND, If false, do not try to use NDOF. + +find_path(NDOF_INCLUDE_DIR ndofdev_external.h +  PATH_SUFFIXES ndofdev +  ) + +set(NDOF_NAMES ${NDOF_NAMES} ndofdev libndofdev) +find_library(NDOF_LIBRARY +  NAMES ${NDOF_NAMES} +  ) + +if (NDOF_LIBRARY AND NDOF_INCLUDE_DIR) +  set(NDOF_FOUND "YES") +else (NDOF_LIBRARY AND NDOF_INCLUDE_DIR) +  set(NDOF_FOUND "NO") +endif (NDOF_LIBRARY AND NDOF_INCLUDE_DIR) + + +if (NDOF_FOUND) +  if (NOT NDOF_FIND_QUIETLY) +    message(STATUS "Found NDOF: Library in '${NDOF_LIBRARY}' and header in '${NDOF_INCLUDE_DIR}' ") +  endif (NOT NDOF_FIND_QUIETLY) +else (NDOF_FOUND) +  if (NDOF_FIND_REQUIRED) +    message(FATAL_ERROR " * * *\nCould not find NDOF library!\nIf you don't need Space Navigator Joystick support you can skip this test by configuring with -DNDOF:BOOL=OFF\n * * *") +  endif (NDOF_FIND_REQUIRED) +endif (NDOF_FOUND) + +mark_as_advanced( +  NDOF_LIBRARY +  NDOF_INCLUDE_DIR +  ) diff --git a/indra/cmake/FindZLIB.cmake b/indra/cmake/FindZLIB.cmake new file mode 100644 index 0000000000..6d630f1ba9 --- /dev/null +++ b/indra/cmake/FindZLIB.cmake @@ -0,0 +1,46 @@ +# -*- cmake -*- + +# - Find zlib +# Find the ZLIB includes and library +# This module defines +#  ZLIB_INCLUDE_DIRS, where to find zlib.h, etc. +#  ZLIB_LIBRARIES, the libraries needed to use zlib. +#  ZLIB_FOUND, If false, do not try to use zlib. +# +# This FindZLIB is about 43 times as fast the one provided with cmake (2.8.x), +# because it doesn't look up the version of zlib, resulting in a dramatic +# speed up for configure (from 4 minutes 22 seconds to 6 seconds). +# +# Note: Since this file is only used for standalone, the windows +# specific parts were left out. + +FIND_PATH(ZLIB_INCLUDE_DIR zlib.h +  NO_SYSTEM_ENVIRONMENT_PATH +  ) + +FIND_LIBRARY(ZLIB_LIBRARY z) + +if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) +  SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR}) +  SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY}) +  SET(ZLIB_FOUND "YES") +else (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) +  SET(ZLIB_FOUND "NO") +endif (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) + +if (ZLIB_FOUND) +  if (NOT ZLIB_FIND_QUIETLY) +	message(STATUS "Found ZLIB: ${ZLIB_LIBRARIES}") +	SET(ZLIB_FIND_QUIETLY TRUE) +  endif (NOT ZLIB_FIND_QUIETLY) +else (ZLIB_FOUND) +  if (ZLIB_FIND_REQUIRED) +	message(FATAL_ERROR "Could not find ZLIB library") +  endif (ZLIB_FIND_REQUIRED) +endif (ZLIB_FOUND) + +mark_as_advanced( +  ZLIB_LIBRARY +  ZLIB_INCLUDE_DIR +  ) + diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 29e2492551..62b764bb30 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -205,6 +205,9 @@ FUNCTION(LL_ADD_INTEGRATION_TEST    endif(TEST_DEBUG)
    ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})
    SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
 +  if(STANDALONE)
 +    SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}")
 +  endif(STANDALONE)
    # Add link deps to the executable
    if(TEST_DEBUG)
 diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index d1ab264a41..17e211cb99 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -13,7 +13,14 @@ set(LLCOMMON_INCLUDE_DIRS      ${Boost_INCLUDE_DIRS}      ) -set(LLCOMMON_LIBRARIES llcommon) +if (LINUX) +    # In order to support using ld.gold on linux, we need to explicitely +    # specify all libraries that llcommon uses. +    # llcommon uses `clock_gettime' which is provided by librt on linux. +    set(LLCOMMON_LIBRARIES llcommon rt) +else (LINUX) +    set(LLCOMMON_LIBRARIES llcommon) +endif (LINUX)  add_definitions(${TCMALLOC_FLAG}) diff --git a/indra/cmake/LLKDU.cmake b/indra/cmake/LLKDU.cmake index 27c8ada686..f5cbad03a6 100644 --- a/indra/cmake/LLKDU.cmake +++ b/indra/cmake/LLKDU.cmake @@ -1,7 +1,20 @@  # -*- cmake -*-  include(Prebuilt) +# USE_KDU can be set when launching cmake or develop.py as an option using the argument -DUSE_KDU:BOOL=ON +# When building using proprietary binaries though (i.e. having access to LL private servers), we always build with KDU  if (INSTALL_PROPRIETARY AND NOT STANDALONE) -  use_prebuilt_binary(kdu) -  set(LLKDU_LIBRARY llkdu) +  set(USE_KDU ON)  endif (INSTALL_PROPRIETARY AND NOT STANDALONE) + +if (USE_KDU) +  use_prebuilt_binary(kdu) +  if (WINDOWS) +    set(KDU_LIBRARY kdu.lib) +  else (WINDOWS) +    set(KDU_LIBRARY libkdu.a) +  endif (WINDOWS) +  set(KDU_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/kdu) +  set(LLKDU_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llkdu) +  set(LLKDU_LIBRARIES llkdu) +endif (USE_KDU) diff --git a/indra/cmake/LLPlugin.cmake b/indra/cmake/LLPlugin.cmake index 9722f16c3c..7ee404b9bd 100644 --- a/indra/cmake/LLPlugin.cmake +++ b/indra/cmake/LLPlugin.cmake @@ -5,4 +5,10 @@ set(LLPLUGIN_INCLUDE_DIRS      ${LIBS_OPEN_DIR}/llplugin      ) -set(LLPLUGIN_LIBRARIES llplugin) +if (LINUX) +    # In order to support using ld.gold on linux, we need to explicitely +    # specify all libraries that llplugin uses. +	set(LLPLUGIN_LIBRARIES llplugin pthread) +else (LINUX) +	set(LLPLUGIN_LIBRARIES llplugin) +endif (LINUX) diff --git a/indra/cmake/NDOF.cmake b/indra/cmake/NDOF.cmake index dad74e99b1..7a463d1190 100644 --- a/indra/cmake/NDOF.cmake +++ b/indra/cmake/NDOF.cmake @@ -1,14 +1,32 @@  # -*- cmake -*-  include(Prebuilt) -use_prebuilt_binary(ndofdev) +set(NDOF ON CACHE BOOL "Use NDOF space navigator joystick library.") -if (WINDOWS OR DARWIN OR LINUX) +if (NDOF) +  if (STANDALONE) +	set(NDOF_FIND_REQUIRED ON) +	include(FindNDOF) +  else (STANDALONE) +	use_prebuilt_binary(ndofdev) + +	if (WINDOWS) +	  set(NDOF_LIBRARY libndofdev) +	elseif (DARWIN OR LINUX) +	  set(NDOF_LIBRARY ndofdev) +	endif (WINDOWS) + +	set(NDOF_INCLUDE_DIR ${ARCH_PREBUILT_DIRS}/include/ndofdev) +	set(NDOF_FOUND 1) +  endif (STANDALONE) +endif (NDOF) + +if (NDOF_FOUND)    add_definitions(-DLIB_NDOF=1) -endif (WINDOWS OR DARWIN OR LINUX) +  include_directories(${NDOF_INCLUDE_DIR}) +else (NDOF_FOUND) +  message(STATUS "Building without N-DoF joystick support") +  set(NDOF_INCLUDE_DIR "") +  set(NDOF_LIBRARY "") +endif (NDOF_FOUND) -if (WINDOWS) -  set(NDOF_LIBRARY libndofdev) -elseif (DARWIN OR LINUX) -  set(NDOF_LIBRARY ndofdev) -endif (WINDOWS) diff --git a/indra/cmake/WebKitLibPlugin.cmake b/indra/cmake/WebKitLibPlugin.cmake index 1c572ab27f..639e94330f 100644 --- a/indra/cmake/WebKitLibPlugin.cmake +++ b/indra/cmake/WebKitLibPlugin.cmake @@ -3,6 +3,29 @@ include(Linking)  include(Prebuilt)  if (STANDALONE) +  # The minimal version, 4.4.3, is rather arbitrary: it's the version in Debian/Lenny. +  find_package(Qt4 4.4.3 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED) +  include(${QT_USE_FILE}) +  set(QTDIR $ENV{QTDIR}) +  if (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin") +	message(FATAL_ERROR "\"${QT_BINARY_DIR}\" is unequal \"${QTDIR}/bin\"; " +	  "Qt is found by looking for qmake in your PATH. " +	  "Please set your PATH such that 'qmake' is found in \$QTDIR/bin, " +	  "or unset QTDIR if the found Qt is correct.") +	endif (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin") +  find_package(LLQtWebkit REQUIRED QUIET) +  # Add the plugins. +  set(QT_PLUGIN_LIBRARIES) +  foreach(qlibname qgif qjpeg) +	find_library(QT_PLUGIN_${qlibname} ${qlibname} PATHS ${QT_PLUGINS_DIR}/imageformats NO_DEFAULT_PATH) +	if (QT_PLUGIN_${qlibname}) +	  list(APPEND QT_PLUGIN_LIBRARIES ${QT_PLUGIN_${qlibname}}) +	else (QT_PLUGIN_${qtlibname}) +	  message(FATAL_ERROR "Could not find the Qt plugin ${qlibname} in \"${QT_PLUGINS_DIR}/imageformats\"!") +	endif (QT_PLUGIN_${qlibname}) +  endforeach(qlibname) +  # qjpeg depends on libjpeg +  list(APPEND QT_PLUGIN_LIBRARIES jpeg)      set(WEBKITLIBPLUGIN OFF CACHE BOOL          "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.")  else (STANDALONE) @@ -34,6 +57,7 @@ elseif (DARWIN)          debug ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib          )  elseif (LINUX) +    set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY} ${QT_LIBRARIES} ${QT_PLUGIN_LIBRARIES})      set(WEBKIT_PLUGIN_LIBRARIES          llqtwebkit diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index 452d37d3be..e0772e55ca 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -10,6 +10,7 @@ include(00-Common)  include(LLCommon)  include(LLImage)  include(LLImageJ2COJ)   # ugh, needed for images +include(LLKDU)  include(LLMath)  include(LLMessage)  include(LLRender) @@ -71,6 +72,11 @@ endif (DARWIN)  target_link_libraries(llui_libtest      llui      llmessage +    ${LLRENDER_LIBRARIES} +    ${LLIMAGE_LIBRARIES} +    ${LLKDU_LIBRARIES} +    ${KDU_LIBRARY} +    ${LLIMAGEJ2COJ_LIBRARIES}      ${OS_LIBRARIES}      ${GOOGLE_PERFTOOLS_LIBRARIES}      ) diff --git a/indra/lib/python/indra/util/test_win32_manifest.py b/indra/lib/python/indra/util/test_win32_manifest.py index 786521c068..da8ee6c545 100644 --- a/indra/lib/python/indra/util/test_win32_manifest.py +++ b/indra/lib/python/indra/util/test_win32_manifest.py @@ -52,20 +52,22 @@ def get_HKLM_registry_value(key_str, value_str):  def find_vc_dir():      supported_versions = (r'8.0', r'9.0') +    supported_products = (r'VisualStudio', r'VCExpress')      value_str = (r'ProductDir') -    for version in supported_versions: -        key_str = (r'SOFTWARE\Microsoft\VisualStudio\%s\Setup\VC' % -                   version) -        try: -            return get_HKLM_registry_value(key_str, value_str) -        except WindowsError, err: -            x64_key_str = (r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%s\Setup\VS' % -                       version) +    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(x64_key_str, value_str) -            except: -                print >> sys.stderr, "Didn't find MS VC version %s " % version +                return get_HKLM_registry_value(key_str, value_str) +            except WindowsError, err: +                x64_key_str = (r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%s\Setup\VS' % +                        version) +                try: +                    return get_HKLM_registry_value(x64_key_str, value_str) +                except: +                    print >> sys.stderr, "Didn't find MS %s version %s " % (product,version)      raise diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 66ec5bad2c..d1c44c9403 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -28,6 +28,7 @@  #include "linden_common.h"  #include "llapr.h" +#include "apr_dso.h"  apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool  LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool. @@ -279,14 +280,31 @@ bool ll_apr_warn_status(apr_status_t status)  {  	if(APR_SUCCESS == status) return false;  	char buf[MAX_STRING];	/* Flawfinder: ignore */ -	apr_strerror(status, buf, MAX_STRING); +	apr_strerror(status, buf, sizeof(buf));  	LL_WARNS("APR") << "APR: " << buf << LL_ENDL;  	return true;  } +bool ll_apr_warn_status(apr_status_t status, apr_dso_handle_t *handle) +{ +    bool result = ll_apr_warn_status(status); +    // Despite observed truncation of actual Mac dylib load errors, increasing +    // this buffer to more than MAX_STRING doesn't help: it appears that APR +    // stores the output in a fixed 255-character internal buffer. (*sigh*) +    char buf[MAX_STRING];           /* Flawfinder: ignore */ +    apr_dso_error(handle, buf, sizeof(buf)); +    LL_WARNS("APR") << "APR: " << buf << LL_ENDL; +    return result; +} +  void ll_apr_assert_status(apr_status_t status)  { -	llassert(ll_apr_warn_status(status) == false); +	llassert(! ll_apr_warn_status(status)); +} + +void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle) +{ +    llassert(! ll_apr_warn_status(status, handle));  }  //--------------------------------------------------------------------- diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 4930270af8..af33ce666f 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -53,6 +53,8 @@  extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;  extern apr_thread_mutex_t* gCallStacksLogMutexp; +struct apr_dso_handle_t; +  /**    * @brief initialize the common apr constructs -- apr itself, the   * global pool, and a mutex. @@ -259,8 +261,11 @@ public:   * @return Returns <code>true</code> if status is an error condition.   */  bool LL_COMMON_API ll_apr_warn_status(apr_status_t status); +/// There's a whole other APR error-message function if you pass a DSO handle. +bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle);  void LL_COMMON_API ll_apr_assert_status(apr_status_t status); +void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle);  extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 84a6620a77..97e2bdeb57 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -475,7 +475,7 @@ void LLEventPump::stopListening(const std::string& name)  *****************************************************************************/  bool LLEventStream::post(const LLSD& event)  { -    if (! mEnabled) +    if (! mEnabled || !mSignal)      {          return false;      } @@ -515,6 +515,8 @@ bool LLEventQueue::post(const LLSD& event)  void LLEventQueue::flush()  { +	if(!mSignal) return; +		      // Consider the case when a given listener on this LLEventQueue posts yet      // another event on the same queue. If we loop over mEventQueue directly,      // we'll end up processing all those events during the same flush() call diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index 55d0c85cbd..e1876599fc 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -29,9 +29,25 @@  #include "llerror.h" +#if LL_REF_COUNT_DEBUG +#include "llthread.h" +#include "llapr.h" +#endif +  LLRefCount::LLRefCount(const LLRefCount& other)  :	mRef(0)  { +#if LL_REF_COUNT_DEBUG +	if(gAPRPoolp) +	{ +		mMutexp = new LLMutex(gAPRPoolp) ; +	} +	else +	{ +		mMutexp = NULL ; +	} +	mCrashAtUnlock = FALSE ; +#endif  }  LLRefCount& LLRefCount::operator=(const LLRefCount&) @@ -43,6 +59,17 @@ LLRefCount& LLRefCount::operator=(const LLRefCount&)  LLRefCount::LLRefCount() :  	mRef(0)  { +#if LL_REF_COUNT_DEBUG +	if(gAPRPoolp) +	{ +		mMutexp = new LLMutex(gAPRPoolp) ; +	} +	else +	{ +		mMutexp = NULL ; +	} +	mCrashAtUnlock = FALSE ; +#endif  }  LLRefCount::~LLRefCount() @@ -51,4 +78,87 @@ LLRefCount::~LLRefCount()  	{  		llerrs << "deleting non-zero reference" << llendl;  	} + +#if LL_REF_COUNT_DEBUG +	if(gAPRPoolp) +	{ +		delete mMutexp ; +	} +#endif  } + +#if LL_REF_COUNT_DEBUG +void LLRefCount::ref() const +{  +	if(mMutexp) +	{ +		if(mMutexp->isLocked())  +		{ +			mCrashAtUnlock = TRUE ; +			llerrs << "the mutex is locked by the thread: " << mLockedThreadID  +				<< " Current thread: " << LLThread::currentID() << llendl ; +		} + +		mMutexp->lock() ; +		mLockedThreadID = LLThread::currentID() ; + +		mRef++;  + +		if(mCrashAtUnlock) +		{ +			while(1); //crash here. +		} +		mMutexp->unlock() ; +	} +	else +	{ +		mRef++;  +	} +}  + +S32 LLRefCount::unref() const +{ +	if(mMutexp) +	{ +		if(mMutexp->isLocked())  +		{ +			mCrashAtUnlock = TRUE ; +			llerrs << "the mutex is locked by the thread: " << mLockedThreadID  +				<< " Current thread: " << LLThread::currentID() << llendl ; +		} + +		mMutexp->lock() ; +		mLockedThreadID = LLThread::currentID() ; +		 +		llassert(mRef >= 1); +		if (0 == --mRef)  +		{ +			if(mCrashAtUnlock) +			{ +				while(1); //crash here. +			} +			mMutexp->unlock() ; + +			delete this;  +			return 0; +		} + +		if(mCrashAtUnlock) +		{ +			while(1); //crash here. +		} +		mMutexp->unlock() ; +		return mRef; +	} +	else +	{ +		llassert(mRef >= 1); +		if (0 == --mRef)  +		{ +			delete this;  +			return 0; +		} +		return mRef; +	} +}	 +#endif diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 19f008b15c..868789de4d 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -28,6 +28,11 @@  #include <boost/noncopyable.hpp> +#define LL_REF_COUNT_DEBUG 0 +#if LL_REF_COUNT_DEBUG +class LLMutex ; +#endif +  //----------------------------------------------------------------------------  // RefCount objects should generally only be accessed by way of LLPointer<>'s  // see llthread.h for LLThreadSafeRefCount @@ -43,12 +48,16 @@ protected:  public:  	LLRefCount(); -	void ref() const +#if LL_REF_COUNT_DEBUG +	void ref() const ; +	S32 unref() const ; +#else +	void LLRefCount::ref() const  	{   		mRef++;   	}  -	S32 unref() const +	S32 LLRefCount::unref() const  	{  		llassert(mRef >= 1);  		if (0 == --mRef)  @@ -58,6 +67,7 @@ public:  		}  		return mRef;  	}	 +#endif  	//NOTE: when passing around a const LLRefCount object, this can return different results  	// at different types, since mRef is mutable @@ -68,6 +78,12 @@ public:  private:   	mutable S32	mRef;  + +#if LL_REF_COUNT_DEBUG +	LLMutex*  mMutexp ; +	mutable U32  mLockedThreadID ; +	mutable BOOL mCrashAtUnlock ;  +#endif  };  #endif diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt index a69621a57b..6834267d4b 100644 --- a/indra/llimage/CMakeLists.txt +++ b/indra/llimage/CMakeLists.txt @@ -57,7 +57,6 @@ add_library (llimage ${llimage_SOURCE_FILES})  # Sort by high-level to low-level  target_link_libraries(llimage      llcommon -    llimagej2coj        # *HACK: In theory a noop for KDU builds?      ${JPEG_LIBRARIES}      ${PNG_LIBRARIES}      ${ZLIB_LIBRARIES} diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 5c33b675ca..b46a99e030 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -52,13 +52,11 @@ LLMutex* LLImage::sMutex = NULL;  void LLImage::initClass()  {  	sMutex = new LLMutex(NULL); -	LLImageJ2C::openDSO();  }  //static  void LLImage::cleanupClass()  { -	LLImageJ2C::closeDSO();  	delete sMutex;  	sMutex = NULL;  } diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index d005aaf29f..cb2a85fa91 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -24,9 +24,6 @@   */  #include "linden_common.h" -#include "apr_pools.h" -#include "apr_dso.h" -  #include "lldir.h"  #include "llimagej2c.h"  #include "llmemtype.h" @@ -37,18 +34,10 @@ typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)();  typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*);  typedef const char* (*EngineInfoLLImageJ2CFunction)(); -//some "private static" variables so we only attempt to load -//dynamic libaries once -CreateLLImageJ2CFunction j2cimpl_create_func; -DestroyLLImageJ2CFunction j2cimpl_destroy_func; -EngineInfoLLImageJ2CFunction j2cimpl_engineinfo_func; -apr_pool_t *j2cimpl_dso_memory_pool; -apr_dso_handle_t *j2cimpl_dso_handle; - -//Declare the prototype for theses functions here, their functionality -//will be implemented in other files which define a derived LLImageJ2CImpl -//but only ONE static library which has the implementation for this -//function should ever be included +// Declare the prototype for theses functions here. Their functionality +// will be implemented in other files which define a derived LLImageJ2CImpl +// but only ONE static library which has the implementation for these +// functions should ever be included.  LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl();  void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl);  const char* fallbackEngineInfoLLImageJ2CImpl(); @@ -58,120 +47,9 @@ LLImageCompressionTester* LLImageJ2C::sTesterp = NULL ;  const std::string sTesterName("ImageCompressionTester");  //static -//Loads the required "create", "destroy" and "engineinfo" functions needed -void LLImageJ2C::openDSO() -{ -	//attempt to load a DSO and get some functions from it -	std::string dso_name; -	std::string dso_path; - -	bool all_functions_loaded = false; -	apr_status_t rv; - -#if LL_WINDOWS -	dso_name = "llkdu.dll"; -#elif LL_DARWIN -	dso_name = "libllkdu.dylib"; -#else -	dso_name = "libllkdu.so"; -#endif - -	dso_path = gDirUtilp->findFile(dso_name, -								   gDirUtilp->getAppRODataDir(), -								   gDirUtilp->getExecutableDir()); - -	j2cimpl_dso_handle      = NULL; -	j2cimpl_dso_memory_pool = NULL; - -	//attempt to load the shared library -	apr_pool_create(&j2cimpl_dso_memory_pool, NULL); -	rv = apr_dso_load(&j2cimpl_dso_handle, -					  dso_path.c_str(), -					  j2cimpl_dso_memory_pool); - -	//now, check for success -	if ( rv == APR_SUCCESS ) -	{ -		//found the dynamic library -		//now we want to load the functions we're interested in -		CreateLLImageJ2CFunction  create_func = NULL; -		DestroyLLImageJ2CFunction dest_func = NULL; -		EngineInfoLLImageJ2CFunction engineinfo_func = NULL; - -		rv = apr_dso_sym((apr_dso_handle_sym_t*)&create_func, -						 j2cimpl_dso_handle, -						 "createLLImageJ2CKDU"); -		if ( rv == APR_SUCCESS ) -		{ -			//we've loaded the create function ok -			//we need to delete via the DSO too -			//so lets check for a destruction function -			rv = apr_dso_sym((apr_dso_handle_sym_t*)&dest_func, -							 j2cimpl_dso_handle, -							 "destroyLLImageJ2CKDU"); -			if ( rv == APR_SUCCESS ) -			{ -				//we've loaded the destroy function ok -				rv = apr_dso_sym((apr_dso_handle_sym_t*)&engineinfo_func, -						 j2cimpl_dso_handle, -						 "engineInfoLLImageJ2CKDU"); -				if ( rv == APR_SUCCESS ) -				{ -					//ok, everything is loaded alright -					j2cimpl_create_func  = create_func; -					j2cimpl_destroy_func = dest_func; -					j2cimpl_engineinfo_func = engineinfo_func; -					all_functions_loaded = true; -				} -			} -		} -	} - -	if ( !all_functions_loaded ) -	{ -		//something went wrong with the DSO or function loading.. -		//fall back onto our satefy impl creation function - -#if 0 -		// precious verbose debugging, sadly we can't use our -		// 'llinfos' stream etc. this early in the initialisation seq. -		char errbuf[256]; -		fprintf(stderr, "failed to load syms from DSO %s (%s)\n", -			dso_name.c_str(), dso_path.c_str()); -		apr_strerror(rv, errbuf, sizeof(errbuf)); -		fprintf(stderr, "error: %d, %s\n", rv, errbuf); -		apr_dso_error(j2cimpl_dso_handle, errbuf, sizeof(errbuf)); -		fprintf(stderr, "dso-error: %d, %s\n", rv, errbuf); -#endif - -		if ( j2cimpl_dso_handle ) -		{ -			apr_dso_unload(j2cimpl_dso_handle); -			j2cimpl_dso_handle = NULL; -		} - -		if ( j2cimpl_dso_memory_pool ) -		{ -			apr_pool_destroy(j2cimpl_dso_memory_pool); -			j2cimpl_dso_memory_pool = NULL; -		} -	} -} - -//static -void LLImageJ2C::closeDSO() -{ -	if ( j2cimpl_dso_handle ) apr_dso_unload(j2cimpl_dso_handle); -	if (j2cimpl_dso_memory_pool) apr_pool_destroy(j2cimpl_dso_memory_pool); -} - -//static  std::string LLImageJ2C::getEngineInfo()  { -	if (!j2cimpl_engineinfo_func) -		j2cimpl_engineinfo_func = fallbackEngineInfoLLImageJ2CImpl; - -	return j2cimpl_engineinfo_func(); +    return fallbackEngineInfoLLImageJ2CImpl();  }  LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C), @@ -181,20 +59,7 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),  							mReversible(FALSE),  							mAreaUsedForDataSizeCalcs(0)  { -	//We assume here that if we wanted to create via -	//a dynamic library that the approriate open calls were made -	//before any calls to this constructor. - -	//Therefore, a NULL creation function pointer here means -	//we either did not want to create using functions from the dynamic -	//library or there were issues loading it, either way -	//use our fall back -	if ( !j2cimpl_create_func ) -	{ -		j2cimpl_create_func = fallbackCreateLLImageJ2CImpl; -	} - -	mImpl = j2cimpl_create_func(); +	mImpl = fallbackCreateLLImageJ2CImpl();  	// Clear data size table  	for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++) @@ -217,22 +82,9 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),  // virtual  LLImageJ2C::~LLImageJ2C()  { -	//We assume here that if we wanted to destroy via -	//a dynamic library that the approriate open calls were made -	//before any calls to this destructor. - -	//Therefore, a NULL creation function pointer here means -	//we either did not want to destroy using functions from the dynamic -	//library or there were issues loading it, either way -	//use our fall back -	if ( !j2cimpl_destroy_func ) -	{ -		j2cimpl_destroy_func = fallbackDestroyLLImageJ2CImpl; -	} -  	if ( mImpl )  	{ -		j2cimpl_destroy_func(mImpl); +        fallbackDestroyLLImageJ2CImpl(mImpl);  	}  } diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index cc3dabd7d8..dd5bec8b2e 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -72,8 +72,6 @@ public:  	static S32 calcHeaderSizeJ2C();  	static S32 calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate = 0.f); -	static void openDSO(); -	static void closeDSO();  	static std::string getEngineInfo();  protected: diff --git a/indra/llinventory/llnotecard.cpp b/indra/llinventory/llnotecard.cpp index 62829c284f..69152cefe0 100644 --- a/indra/llinventory/llnotecard.cpp +++ b/indra/llinventory/llnotecard.cpp @@ -199,7 +199,7 @@ bool LLNotecard::importStream(std::istream& str)  		return FALSE;  	} -	if(text_len > mMaxText) +	if(text_len > mMaxText || text_len < 0)  	{  		llwarns << "Invalid Linden text length: " << text_len << llendl;  		return FALSE; diff --git a/indra/llkdu/CMakeLists.txt b/indra/llkdu/CMakeLists.txt new file mode 100644 index 0000000000..b8b44b44fc --- /dev/null +++ b/indra/llkdu/CMakeLists.txt @@ -0,0 +1,45 @@ +# -*- cmake -*- + +project(llkdu) + +# Visual Studio 2005 has a dumb bug that causes it to fail compilation +# of KDU if building with both optimisation and /WS (treat warnings as +# errors), even when the specific warnings that make it croak are +# disabled. + +#set(VS_DISABLE_FATAL_WARNINGS ON) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLKDU) +include(LLMath) + +include_directories( +    ${LLCOMMON_INCLUDE_DIRS} +    ${LLIMAGE_INCLUDE_DIRS} +    ${KDU_INCLUDE_DIR} +    ${LLMATH_INCLUDE_DIRS} +    ) + +set(llkdu_SOURCE_FILES +    llimagej2ckdu.cpp +    llkdumem.cpp +    ) + +set(llkdu_HEADER_FILES +    CMakeLists.txt +	 +    llimagej2ckdu.h +    llkdumem.h +    ) + +set_source_files_properties(${llkdu_HEADER_FILES} +                            PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llkdu_SOURCE_FILES ${llkdu_HEADER_FILES}) + +if (USE_KDU) +  add_library (${LLKDU_LIBRARIES} ${llkdu_SOURCE_FILES}) +   +endif (USE_KDU) diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp new file mode 100644 index 0000000000..1a286d1406 --- /dev/null +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -0,0 +1,1084 @@ + /**  + * @file llimagej2ckdu.cpp + * @brief This is an implementation of JPEG2000 encode/decode using Kakadu + * + * $LicenseInfo:firstyear=2010&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 "llimagej2ckdu.h" + +#include "lltimer.h" +#include "llpointer.h" +#include "llkdumem.h" + + +class kdc_flow_control { +	 +public: // Member functions +    kdc_flow_control(kdu_image_in_base *img_in, kdu_codestream codestream); +    ~kdc_flow_control(); +    bool advance_components(); +    void process_components(); +	 +private: // Data +     +    struct kdc_component_flow_control { +    public: // Data +        kdu_image_in_base *reader; +        int vert_subsampling; +        int ratio_counter;  /*  Initialized to 0, decremented by `count_delta'; +                                when < 0, a new line must be processed, after +                                which it is incremented by `vert_subsampling'.  */ +        int initial_lines; +        int remaining_lines; +        kdu_line_buf *line; +    }; +     +    kdu_codestream codestream; +    kdu_dims valid_tile_indices; +    kdu_coords tile_idx; +    kdu_tile tile; +    int num_components; +    kdc_component_flow_control *components; +    int count_delta; // Holds the minimum of the `vert_subsampling' fields +    kdu_multi_analysis engine; +    kdu_long max_buffer_memory; +}; + +// +// Kakadu specific implementation +// +void set_default_colour_weights(kdu_params *siz); + +const char* engineInfoLLImageJ2CKDU() +{ +	return "KDU v6.4.1"; +} + +LLImageJ2CKDU* createLLImageJ2CKDU() +{ +	return new LLImageJ2CKDU(); +} + +void destroyLLImageJ2CKDU(LLImageJ2CKDU* kdu) +{ +	delete kdu; +	kdu = NULL; +} + +LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl() +{ +	return new LLImageJ2CKDU(); +} + +void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl) +{ +	delete impl; +	impl = NULL; +} + +const char* fallbackEngineInfoLLImageJ2CImpl() +{ +	return engineInfoLLImageJ2CKDU(); +} + +class LLKDUDecodeState +{ +public: + +	S32 mNumComponents; +	BOOL mUseYCC; +	kdu_dims mDims; +	kdu_sample_allocator mAllocator; +	kdu_tile_comp mComps[4]; +	kdu_line_buf mLines[4]; +	kdu_pull_ifc mEngines[4]; +	bool mReversible[4]; // Some components may be reversible and others not. +	int mBitDepths[4]; // Original bit-depth may be quite different from 8. + +	kdu_tile mTile; +	kdu_byte *mBuf; +	S32 mRowGap; + +	LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap); +	~LLKDUDecodeState(); +	BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE); + +public: +	int *AssignLayerBytes(siz_params *siz, int &num_specs); + +	void setupCodeStream(BOOL keep_codestream, LLImageJ2CKDU::ECodeStreamMode mode); +	BOOL initDecode(LLImageRaw &raw_image, F32 decode_time, LLImageJ2CKDU::ECodeStreamMode mode, S32 first_channel, S32 max_channel_count ); +}; + +void ll_kdu_error( void ) +{ +	// *FIX: This exception is bad, bad, bad. It gets thrown from a +	// destructor which can lead to immediate program termination! +	throw "ll_kdu_error() throwing an exception"; +} + +// Stuff for new kdu error handling +class LLKDUMessageWarning : public kdu_message +{ +public: +	/*virtual*/ void put_text(const char *s); +	/*virtual*/ void put_text(const kdu_uint16 *s); + +	static LLKDUMessageWarning sDefaultMessage; +}; + +class LLKDUMessageError : public kdu_message +{ +public: +	/*virtual*/ void put_text(const char *s); +	/*virtual*/ void put_text(const kdu_uint16 *s); +	/*virtual*/ void flush(bool end_of_message=false); +	static LLKDUMessageError sDefaultMessage; +}; + +void LLKDUMessageWarning::put_text(const char *s) +{ +	llinfos << "KDU Warning: " << s << llendl; +} + +void LLKDUMessageWarning::put_text(const kdu_uint16 *s) +{ +	llinfos << "KDU Warning: " << s << llendl; +} + +void LLKDUMessageError::put_text(const char *s) +{ +	llinfos << "KDU Error: " << s << llendl; +} + +void LLKDUMessageError::put_text(const kdu_uint16 *s) +{ +	llinfos << "KDU Error: " << s << llendl; +} + +void LLKDUMessageError::flush(bool end_of_message) +{ +	if( end_of_message )  +	{ +		throw "KDU throwing an exception"; +	} +} + +LLKDUMessageWarning LLKDUMessageWarning::sDefaultMessage; +LLKDUMessageError	LLKDUMessageError::sDefaultMessage; +static bool kdu_message_initialized = false; + +LLImageJ2CKDU::LLImageJ2CKDU() : LLImageJ2CImpl(), +mInputp(NULL), +mCodeStreamp(NULL), +mTPosp(NULL), +mTileIndicesp(NULL), +mRawImagep(NULL), +mDecodeState(NULL) +{ +} + +LLImageJ2CKDU::~LLImageJ2CKDU() +{ +	cleanupCodeStream(); // in case destroyed before decode completed +} + +// Stuff for new simple decode +void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision); + +void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode) +{ +	S32 data_size = base.getDataSize(); +	S32 max_bytes = base.getMaxBytes() ? base.getMaxBytes() : data_size; + +	// +	//  Initialization +	// +	if (!kdu_message_initialized) +	{ +		kdu_message_initialized = true; +		kdu_customize_errors(&LLKDUMessageError::sDefaultMessage); +		kdu_customize_warnings(&LLKDUMessageWarning::sDefaultMessage); +	} + +	if (mCodeStreamp) +	{ +		mCodeStreamp->destroy(); +		delete mCodeStreamp; +		mCodeStreamp = NULL; +	} + +	if (!mInputp) +	{ +		llassert(base.getData()); +		// The compressed data has been loaded +		// Setup the source for the codestrea +		mInputp = new LLKDUMemSource(base.getData(), data_size); +	} + +	llassert(mInputp); +	mInputp->reset(); +	mCodeStreamp = new kdu_codestream; + +	mCodeStreamp->create(mInputp); + +	// Set the maximum number of bytes to use from the codestream +	mCodeStreamp->set_max_bytes(max_bytes); + +	//    If you want to flip or rotate the image for some reason, change +	// the resolution, or identify a restricted region of interest, this is +	// the place to do it.  You may use "kdu_codestream::change_appearance" +	// and "kdu_codestream::apply_input_restrictions" for this purpose. +	//    If you wish to truncate the code-stream prior to decompression, you +	// may use "kdu_codestream::set_max_bytes". +	//    If you wish to retain all compressed data so that the material +	// can be decompressed multiple times, possibly with different appearance +	// parameters, you should call "kdu_codestream::set_persistent" here. +	//    There are a variety of other features which must be enabled at +	// this point if you want to take advantage of them.  See the +	// descriptions appearing with the "kdu_codestream" interface functions +	// in "kdu_compressed.h" for an itemized account of these capabilities. + +	switch( mode ) +	{ +	case MODE_FAST: +		mCodeStreamp->set_fast(); +		break; +	case MODE_RESILIENT: +		mCodeStreamp->set_resilient(); +		break; +	case MODE_FUSSY: +		mCodeStreamp->set_fussy(); +		break; +	default: +		llassert(0); +		mCodeStreamp->set_fast(); +	} + +	kdu_dims dims; +	mCodeStreamp->get_dims(0,dims); + +	S32 components = mCodeStreamp->get_num_components(); + +	if (components >= 3) +	{ // Check that components have consistent dimensions (for PPM file) +		kdu_dims dims1; mCodeStreamp->get_dims(1,dims1); +		kdu_dims dims2; mCodeStreamp->get_dims(2,dims2); +		if ((dims1 != dims) || (dims2 != dims)) +		{ +			llerrs << "Components don't have matching dimensions!" << llendl; +		} +	} + +	base.setSize(dims.size.x, dims.size.y, components); + +	if (!keep_codestream) +	{ +		mCodeStreamp->destroy(); +		delete mCodeStreamp; +		mCodeStreamp = NULL; +		delete mInputp; +		mInputp = NULL; +	} +} + +void LLImageJ2CKDU::cleanupCodeStream() +{ +	delete mInputp; +	mInputp = NULL; + +	delete mDecodeState; +	mDecodeState = NULL; + +	if (mCodeStreamp) +	{ +		mCodeStreamp->destroy(); +		delete mCodeStreamp; +		mCodeStreamp = NULL; +	} + +	delete mTPosp; +	mTPosp = NULL; + +	delete mTileIndicesp; +	mTileIndicesp = NULL; +} + +BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count ) +{ +	base.resetLastError(); + +	// *FIX: kdu calls our callback function if there's an error, and then bombs. +	// To regain control, we throw an exception, and catch it here. +	try +	{ +		base.updateRawDiscardLevel(); +		setupCodeStream(base, TRUE, mode); + +		mRawImagep = &raw_image; +		mCodeStreamp->change_appearance(false, true, false); +		mCodeStreamp->apply_input_restrictions(first_channel,max_channel_count,base.getRawDiscardLevel(),0,NULL); + +		kdu_dims dims; mCodeStreamp->get_dims(0,dims); +		S32 channels = base.getComponents() - first_channel; +		if( channels > max_channel_count ) +		{ +			channels = max_channel_count; +		} +		raw_image.resize(dims.size.x, dims.size.y, channels); + +		//	llinfos << "Resizing to " << dims.size.x << ":" << dims.size.y << llendl; +		if (!mTileIndicesp) +		{ +			mTileIndicesp = new kdu_dims; +		} +		mCodeStreamp->get_valid_tiles(*mTileIndicesp); +		if (!mTPosp) +		{ +			mTPosp = new kdu_coords; +			mTPosp->y = 0; +			mTPosp->x = 0; +		} +	} +	catch (const char* msg) +	{ +		base.setLastError(ll_safe_string(msg)); +		return FALSE; +	} +	catch (...) +	{ +		base.setLastError("Unknown J2C error"); +		return FALSE; +	} + +	return TRUE; +} + + +// Returns TRUE to mean done, whether successful or not. +BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) +{ +	ECodeStreamMode mode = MODE_FAST; + +	LLTimer decode_timer; + +	if (!mCodeStreamp) +	{ +		if (!initDecode(base, raw_image, decode_time, mode, first_channel, max_channel_count)) +		{ +			// Initializing the J2C decode failed, bail out. +			cleanupCodeStream(); +			return TRUE; // done +		} +	} + +	// These can probably be grabbed from what's saved in the class. +	kdu_dims dims; +	mCodeStreamp->get_dims(0,dims); + +	// Now we are ready to walk through the tiles processing them one-by-one. +	kdu_byte *buffer = raw_image.getData(); + +	while (mTPosp->y < mTileIndicesp->size.y) +	{ +		while (mTPosp->x < mTileIndicesp->size.x) +		{ +			try +			{ +				if (!mDecodeState) +				{ +					kdu_tile tile = mCodeStreamp->open_tile(*(mTPosp)+mTileIndicesp->pos); + +					// Find the region of the buffer occupied by this +					// tile.  Note that we have no control over +					// sub-sampling factors which might have been used +					// during compression and so it can happen that tiles +					// (at the image component level) actually have +					// different dimensions.  For this reason, we cannot +					// figure out the buffer region occupied by a tile +					// directly from the tile indices.  Instead, we query +					// the highest resolution of the first tile-component +					// concerning its location and size on the canvas -- +					// the `dims' object already holds the location and +					// size of the entire image component on the same +					// canvas coordinate system.  Comparing the two tells +					// us where the current tile is in the buffer. +					S32 channels = base.getComponents() - first_channel; +					if( channels > max_channel_count ) +					{ +						channels = max_channel_count; +					} +					kdu_resolution res = tile.access_component(0).access_resolution(); +					kdu_dims tile_dims; res.get_dims(tile_dims); +					kdu_coords offset = tile_dims.pos - dims.pos; +					int row_gap = channels*dims.size.x; // inter-row separation +					kdu_byte *buf = buffer + offset.y*row_gap + offset.x*channels; +					mDecodeState = new LLKDUDecodeState(tile, buf, row_gap); +				} +				// Do the actual processing +				F32 remaining_time = decode_time - decode_timer.getElapsedTimeF32(); +				// This is where we do the actual decode.  If we run out of time, return false. +				if (mDecodeState->processTileDecode(remaining_time, (decode_time > 0.0f))) +				{ +					delete mDecodeState; +					mDecodeState = NULL; +				} +				else +				{ +					// Not finished decoding yet. +					//					setLastError("Ran out of time while decoding"); +					return FALSE; +				} +			} +			catch( const char* msg ) +			{ +				base.setLastError(ll_safe_string(msg)); +				base.decodeFailed(); +				cleanupCodeStream(); +				return TRUE; // done +			} +			catch( ... ) +			{ +				base.setLastError( "Unknown J2C error" ); +				base.decodeFailed(); +				cleanupCodeStream(); +				return TRUE; // done +			} + + +			mTPosp->x++; +		} +		mTPosp->y++; +		mTPosp->x = 0; +	} + +	cleanupCodeStream(); + +	return TRUE; +} + + +BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, BOOL reversible) +{ +	// Collect simple arguments. +	bool transpose, vflip, hflip; +	bool allow_rate_prediction, mem, quiet, no_weights; +	int cpu_iterations; +	std::ostream *record_stream; + +	transpose = false; +	record_stream = NULL; +	allow_rate_prediction = true; +	no_weights = false; +	cpu_iterations = -1; +	mem = false; +	quiet = false; +	vflip = true; +	hflip = false; + +	try +	{ +		// Set up input image files. +		siz_params siz; +		 +		// Should set rate someplace here. +		LLKDUMemIn mem_in(raw_image.getData(), +			raw_image.getDataSize(), +			raw_image.getWidth(), +			raw_image.getHeight(), +			raw_image.getComponents(), +			&siz); + +		base.setSize(raw_image.getWidth(), raw_image.getHeight(), raw_image.getComponents()); + +		int num_components = raw_image.getComponents(); + +		siz.set(Scomponents,0,0,num_components); +		siz.set(Sdims,0,0,base.getHeight());  // Height of first image component +		siz.set(Sdims,0,1,base.getWidth());   // Width of first image component +		siz.set(Sprecision,0,0,8);  // Image samples have original bit-depth of 8 +		siz.set(Ssigned,0,0,false); // Image samples are originally unsigned + +		kdu_params *siz_ref = &siz; siz_ref->finalize(); +		siz_params transformed_siz; // Use this one to construct code-strea +		transformed_siz.copy_from(&siz,-1,-1,-1,0,transpose,false,false); + +		// Construct the `kdu_codestream' object and parse all remaining arguments. + +		U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents(); +		if (max_output_size < 1000) +		{ +			max_output_size = 1000; +		} +		U8 *output_buffer = new U8[max_output_size]; + +		U32 output_size = max_output_size; // gets modified +		LLKDUMemTarget output(output_buffer, output_size, base.getWidth()*base.getHeight()*base.getComponents()); +		if (output_size > max_output_size) +		{ +			llerrs << llformat("LLImageJ2C::encode output_size(%d) > max_output_size(%d)", +				output_size,max_output_size) << llendl; +		} + +		kdu_codestream codestream; +		codestream.create(&transformed_siz,&output); + +		if (comment_text) +		{ +			// Set the comments for the codestream +			kdu_codestream_comment comment = codestream.add_comment(); +			comment.put_text(comment_text); +		} + +		// Set codestream options +		int num_layer_specs = 0; + +		kdu_long layer_bytes[64]; +		U32 max_bytes = 0; + +		if ((num_components >= 3) && !no_weights) +		{ +			set_default_colour_weights(codestream.access_siz()); +		} + +		if (reversible) +		{ +			// If we're doing reversible, assume we're not using quality layers. +			// Yes, I know this is incorrect! +			codestream.access_siz()->parse_string("Creversible=yes"); +			codestream.access_siz()->parse_string("Clayers=1"); +			num_layer_specs = 1; +			layer_bytes[0] = 0; +		} +		else +		{ +			// Rate is the argument passed into the LLImageJ2C which +			// specifies the target compression rate.  The default is 8:1. +			// Possibly if max_bytes < 500, we should just use the default setting? +			if (base.mRate != 0.f) +			{ +				max_bytes = (U32)(base.mRate*base.getWidth()*base.getHeight()*base.getComponents()); +			} +			else +			{ +				max_bytes = (U32)(base.getWidth()*base.getHeight()*base.getComponents()*0.125); +			} + +			const U32 min_bytes = FIRST_PACKET_SIZE; +			if (max_bytes > min_bytes) +			{ +				U32 i; +				// This code is where we specify the target number of bytes for +				// each layer.  Not sure if we should do this for small images +				// or not.  The goal is to have this roughly align with +				// different quality levels that we decode at. +				for (i = min_bytes; i < max_bytes; i*=4) +				{ +					if (i == min_bytes * 4) +					{ +						i = 2000; +					} +					layer_bytes[num_layer_specs] = i; +					num_layer_specs++; +				} +				layer_bytes[num_layer_specs] = max_bytes; +				num_layer_specs++; + +				std::string layer_string = llformat("Clayers=%d",num_layer_specs); +				codestream.access_siz()->parse_string(layer_string.c_str()); +			} +			else +			{ +				layer_bytes[0] = min_bytes; +				num_layer_specs = 1; +				std::string layer_string = llformat("Clayers=%d",num_layer_specs); +				codestream.access_siz()->parse_string(layer_string.c_str()); +			} +		} +		codestream.access_siz()->finalize_all(); +		if (cpu_iterations >= 0) +		{ +			codestream.collect_timing_stats(cpu_iterations); +		} +		codestream.change_appearance(transpose,vflip,hflip); + +		// Now we are ready for sample data processing. +        kdc_flow_control *tile = new kdc_flow_control(&mem_in,codestream); +        bool done = false; +        while (!done) +        {  +            // Process line by line +            done = true; +            if (tile->advance_components()) +            { +                done = false; +                tile->process_components(); +            } +        } + +		// Produce the compressed output +        codestream.flush(layer_bytes,num_layer_specs); + +		// Cleanup +        delete tile; + +		codestream.destroy(); +		if (record_stream != NULL) +		{ +			delete record_stream; +		} + +		// Now that we're done encoding, create the new data buffer for the compressed +		// image and stick it there. + +		base.copyData(output_buffer, output_size); +		base.updateData(); // set width, height +		delete[] output_buffer; +	} +	catch(const char* msg) +	{ +		base.setLastError(ll_safe_string(msg)); +		return FALSE; +	} +	catch( ... ) +	{ +		base.setLastError( "Unknown J2C error" ); +		return FALSE; +	} + +	return TRUE; +} + +BOOL LLImageJ2CKDU::getMetadata(LLImageJ2C &base) +{ +	// *FIX: kdu calls our callback function if there's an error, and +	// then bombs.  To regain control, we throw an exception, and +	// catch it here. +	try +	{ +		setupCodeStream(base, FALSE, MODE_FAST); +		return TRUE; +	} +	catch( const char* msg ) +	{ +		base.setLastError(ll_safe_string(msg)); +		return FALSE; +	} +	catch( ... ) +	{ +		base.setLastError( "Unknown J2C error" ); +		return FALSE; +	} +} + +void set_default_colour_weights(kdu_params *siz) +{ +	kdu_params *cod = siz->access_cluster(COD_params); +	assert(cod != NULL); + +	bool can_use_ycc = true; +	bool rev0=false; +	int depth0=0, sub_x0=1, sub_y0=1; +	for (int c=0; c < 3; c++) +	{ +		int depth=0; siz->get(Sprecision,c,0,depth); +		int sub_y=1; siz->get(Ssampling,c,0,sub_y); +		int sub_x=1; siz->get(Ssampling,c,1,sub_x); +		kdu_params *coc = cod->access_relation(-1,c); +		bool rev=false; coc->get(Creversible,0,0,rev); +		if (c == 0) +		{ rev0=rev; depth0=depth; sub_x0=sub_x; sub_y0=sub_y; } +		else if ((rev != rev0) || (depth != depth0) || +			(sub_x != sub_x0) || (sub_y != sub_y0)) +			can_use_ycc = false; +	} +	if (!can_use_ycc) +		return; + +	bool use_ycc; +	if (!cod->get(Cycc,0,0,use_ycc)) +		cod->set(Cycc,0,0,use_ycc=true); +	if (!use_ycc) +		return; +	float weight; +	if (cod->get(Clev_weights,0,0,weight) || +		cod->get(Cband_weights,0,0,weight)) +		return; // Weights already specified explicitly. + +	/* These example weights are adapted from numbers generated by Marcus Nadenau +	at EPFL, for a viewing distance of 15 cm and a display resolution of +	300 DPI. */ + +	cod->parse_string("Cband_weights:C0=" +		"{0.0901},{0.2758},{0.2758}," +		"{0.7018},{0.8378},{0.8378},{1}"); +	cod->parse_string("Cband_weights:C1=" +		"{0.0263},{0.0863},{0.0863}," +		"{0.1362},{0.2564},{0.2564}," +		"{0.3346},{0.4691},{0.4691}," +		"{0.5444},{0.6523},{0.6523}," +		"{0.7078},{0.7797},{0.7797},{1}"); +	cod->parse_string("Cband_weights:C2=" +		"{0.0773},{0.1835},{0.1835}," +		"{0.2598},{0.4130},{0.4130}," +		"{0.5040},{0.6464},{0.6464}," +		"{0.7220},{0.8254},{0.8254}," +		"{0.8769},{0.9424},{0.9424},{1}"); +} + +/******************************************************************************/ +/*                              transfer_bytes                                */ +/******************************************************************************/ + +void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision) +/* Transfers source samples from the supplied line buffer into the output +byte buffer, spacing successive output samples apart by `gap' bytes +(to allow for interleaving of colour components).  The function performs +all necessary level shifting, type conversion, rounding and truncation. */ +{ +	int width = src.get_width(); +	if (src.get_buf32() != NULL) +	{ // Decompressed samples have a 32-bit representation (integer or float) +		assert(precision >= 8); // Else would have used 16 bit representation +		kdu_sample32 *sp = src.get_buf32(); +		if (!src.is_absolute()) +		{ // Transferring normalized floating point data. +			float scale16 = (float)(1<<16); +			kdu_int32 val; + +			for (; width > 0; width--, sp++, dest+=gap) +			{ +				val = (kdu_int32)(sp->fval*scale16); +				val = (val+128)>>8; // May be faster than true rounding +				val += 128; +				if (val & ((-1)<<8)) +				{ +					val = (val<0)?0:255; +				} +				*dest = (kdu_byte) val; +			} +		} +		else +		{ // Transferring 32-bit absolute integers. +			kdu_int32 val; +			kdu_int32 downshift = precision-8; +			kdu_int32 offset = (1<<downshift)>>1; + +			for (; width > 0; width--, sp++, dest+=gap) +			{ +				val = sp->ival; +				val = (val+offset)>>downshift; +				val += 128; +				if (val & ((-1)<<8)) +				{ +					val = (val<0)?0:255; +				} +				*dest = (kdu_byte) val; +			} +		} +	} +	else +	{ // Source data is 16 bits. +		kdu_sample16 *sp = src.get_buf16(); +		if (!src.is_absolute()) +		{ // Transferring 16-bit fixed point quantities +			kdu_int16 val; + +			if (precision >= 8) +			{ // Can essentially ignore the bit-depth. +				for (; width > 0; width--, sp++, dest+=gap) +				{ +					val = sp->ival; +					val += (1<<(KDU_FIX_POINT-8))>>1; +					val >>= (KDU_FIX_POINT-8); +					val += 128; +					if (val & ((-1)<<8)) +					{ +						val = (val<0)?0:255; +					} +					*dest = (kdu_byte) val; +				} +			} +			else +			{ // Need to force zeros into one or more least significant bits. +				kdu_int16 downshift = KDU_FIX_POINT-precision; +				kdu_int16 upshift = 8-precision; +				kdu_int16 offset = 1<<(downshift-1); + +				for (; width > 0; width--, sp++, dest+=gap) +				{ +					val = sp->ival; +					val = (val+offset)>>downshift; +					val <<= upshift; +					val += 128; +					if (val & ((-1)<<8)) +					{ +						val = (val<0)?0:(256-(1<<upshift)); +					} +					*dest = (kdu_byte) val; +				} +			} +		} +		else +		{ // Transferring 16-bit absolute integers. +			kdu_int16 val; + +			if (precision >= 8) +			{ +				kdu_int16 downshift = precision-8; +				kdu_int16 offset = (1<<downshift)>>1; + +				for (; width > 0; width--, sp++, dest+=gap) +				{ +					val = sp->ival; +					val = (val+offset)>>downshift; +					val += 128; +					if (val & ((-1)<<8)) +					{ +						val = (val<0)?0:255; +					} +					*dest = (kdu_byte) val; +				} +			} +			else +			{ +				kdu_int16 upshift = 8-precision; + +				for (; width > 0; width--, sp++, dest+=gap) +				{ +					val = sp->ival; +					val <<= upshift; +					val += 128; +					if (val & ((-1)<<8)) +					{ +						val = (val<0)?0:(256-(1<<upshift)); +					} +					*dest = (kdu_byte) val; +				} +			} +		} +	} +} + +LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap) +{ +	S32 c; + +	mTile = tile; +	mBuf = buf; +	mRowGap = row_gap; + +	mNumComponents = tile.get_num_components(); + +	llassert(mNumComponents<=4); +	mUseYCC = tile.get_ycc(); + +	for (c=0; c<4; ++c) +	{ +		mReversible[c] = false; +		mBitDepths[c] = 0; +	} + +	// Open tile-components and create processing engines and resources +	for (c=0; c < mNumComponents; c++) +	{ +		mComps[c] = mTile.access_component(c); +		mReversible[c] = mComps[c].get_reversible(); +		mBitDepths[c] = mComps[c].get_bit_depth(); +		kdu_resolution res = mComps[c].access_resolution(); // Get top resolution +		kdu_dims comp_dims; res.get_dims(comp_dims); +		if (c == 0) +		{ +			mDims = comp_dims; +		} +		else +		{ +			llassert(mDims == comp_dims); // Safety check; the caller has ensured this +		} +		bool use_shorts = (mComps[c].get_bit_depth(true) <= 16); +		mLines[c].pre_create(&mAllocator,mDims.size.x,mReversible[c],use_shorts); +		if (res.which() == 0) // No DWT levels used +		{ +			mEngines[c] = kdu_decoder(res.access_subband(LL_BAND),&mAllocator,use_shorts); +		} +		else +		{ +			mEngines[c] = kdu_synthesis(res,&mAllocator,use_shorts); +		} +	} +	mAllocator.finalize(); // Actually creates buffering resources +	for (c=0; c < mNumComponents; c++) +	{ +		mLines[c].create(); // Grabs resources from the allocator. +	} +} + +LLKDUDecodeState::~LLKDUDecodeState() +{ +	S32 c; +	// Cleanup +	for (c=0; c < mNumComponents; c++) +	{ +		mEngines[c].destroy(); // engines are interfaces; no default destructors +	} + +	mTile.close(); +} + +BOOL LLKDUDecodeState::processTileDecode(F32 decode_time, BOOL limit_time) +/* Decompresses a tile, writing the data into the supplied byte buffer. +The buffer contains interleaved image components, if there are any. +Although you may think of the buffer as belonging entirely to this tile, +the `buf' pointer may actually point into a larger buffer representing +multiple tiles.  For this reason, `row_gap' is needed to identify the +separation between consecutive rows in the real buffer. */ +{ +	S32 c; +	// Now walk through the lines of the buffer, recovering them from the +	// relevant tile-component processing engines. + +	LLTimer decode_timer; +	while (mDims.size.y--) +	{ +		for (c=0; c < mNumComponents; c++) +		{ +			mEngines[c].pull(mLines[c],true); +		} +		if ((mNumComponents >= 3) && mUseYCC) +		{ +			kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]); +		} +		for (c=0; c < mNumComponents; c++) +		{ +			transfer_bytes(mBuf+c,mLines[c],mNumComponents,mBitDepths[c]); +		} +		mBuf += mRowGap; +		if (mDims.size.y % 10) +		{ +			if (limit_time && decode_timer.getElapsedTimeF32() > decode_time) +			{ +				return FALSE; +			} +		} +	} +	return TRUE; +} + +// kdc_flow_control  + +kdc_flow_control::kdc_flow_control (kdu_image_in_base *img_in, kdu_codestream codestream) +{ +    int n; +     +    this->codestream = codestream; +    codestream.get_valid_tiles(valid_tile_indices); +    tile_idx = valid_tile_indices.pos; +    tile = codestream.open_tile(tile_idx,NULL); +     +    // Set up the individual components +    num_components = codestream.get_num_components(true); +    components = new kdc_component_flow_control[num_components]; +    count_delta = 0; +    kdc_component_flow_control *comp = components; +    for (n = 0; n < num_components; n++, comp++) +    { +        comp->line = NULL; +        comp->reader = img_in; +        kdu_coords subsampling;   +        codestream.get_subsampling(n,subsampling,true); +        kdu_dims dims;   +        codestream.get_tile_dims(tile_idx,n,dims,true); +        comp->vert_subsampling = subsampling.y; +        if ((n == 0) || (comp->vert_subsampling < count_delta)) +        { +            count_delta = comp->vert_subsampling; +        } +        comp->ratio_counter = 0; +        comp->remaining_lines = comp->initial_lines = dims.size.y; +    } +    assert(num_components > 0); +     +    tile.set_components_of_interest(num_components); +    max_buffer_memory = engine.create(codestream,tile,false,NULL,false,1,NULL,NULL,false); +} + +kdc_flow_control::~kdc_flow_control() +{ +    if (components != NULL) +        delete[] components; +    if (engine.exists()) +        engine.destroy(); +} + +bool kdc_flow_control::advance_components() +{ +    bool found_line = false; +    while (!found_line) +    { +        bool all_done = true; +        kdc_component_flow_control *comp = components; +        for (int n = 0; n < num_components; n++, comp++) +        { +            assert(comp->ratio_counter >= 0); +            if (comp->remaining_lines > 0) +            { +                all_done = false; +                comp->ratio_counter -= count_delta; +                if (comp->ratio_counter < 0) +                { +                    found_line = true; +                    comp->line = engine.exchange_line(n,NULL,NULL); +                    assert(comp->line != NULL); +					if (comp->line->get_width()) +					{ +						comp->reader->get(n,*(comp->line),0); +					} +                } +            } +        } +        if (all_done) +        { +            return false; +        } +    } +    return true; +} + +void kdc_flow_control::process_components() +{ +    kdc_component_flow_control *comp = components; +    for (int n = 0; n < num_components; n++, comp++) +    { +        if (comp->ratio_counter < 0) +        { +            comp->ratio_counter += comp->vert_subsampling; +            assert(comp->ratio_counter >= 0); +            assert(comp->remaining_lines > 0); +            comp->remaining_lines--; +            assert(comp->line != NULL); +            engine.exchange_line(n,comp->line,NULL); +            comp->line = NULL; +        } +    } +} diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h new file mode 100644 index 0000000000..03f289f8b1 --- /dev/null +++ b/indra/llkdu/llimagej2ckdu.h @@ -0,0 +1,91 @@ +/**  + * @file llimagej2ckdu.h + * @brief This is an implementation of JPEG2000 encode/decode using Kakadu + * + * $LicenseInfo:firstyear=2010&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_LLIMAGEJ2CKDU_H +#define LL_LLIMAGEJ2CKDU_H + +#include "llimagej2c.h" + +// +// KDU core header files +// +#include "kdu_elementary.h" +#include "kdu_messaging.h" +#include "kdu_params.h" +#include "kdu_compressed.h" +#include "kdu_sample_processing.h" + +class LLKDUDecodeState; +class LLKDUMemSource; + +class LLImageJ2CKDU : public LLImageJ2CImpl +{	 +public: +	enum ECodeStreamMode  +	{ +		MODE_FAST = 0, +		MODE_RESILIENT = 1, +		MODE_FUSSY = 2 +	}; +	 +public: +	LLImageJ2CKDU(); +	virtual ~LLImageJ2CKDU(); + +protected: +	/*virtual*/ BOOL getMetadata(LLImageJ2C &base); +	/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count); +	/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0, +								BOOL reversible=FALSE); + +	void setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode); +	void cleanupCodeStream(); +	BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count ); + +	// Encode variable +	LLKDUMemSource *mInputp; +	kdu_codestream *mCodeStreamp; +	kdu_coords *mTPosp; // tile position +	kdu_dims *mTileIndicesp; + +	// Temporary variables for in-progress decodes... +	LLImageRaw *mRawImagep; +	LLKDUDecodeState *mDecodeState; +}; + +#if LL_WINDOWS +# define LLSYMEXPORT __declspec(dllexport) +#elif LL_LINUX +# define LLSYMEXPORT __attribute__ ((visibility("default"))) +#else +# define LLSYMEXPORT +#endif + +extern "C" LLSYMEXPORT const char* engineInfoLLImageJ2CKDU(); +extern "C" LLSYMEXPORT LLImageJ2CKDU* createLLImageJ2CKDU(); +extern "C" LLSYMEXPORT void destroyLLImageJ2CKDU(LLImageJ2CKDU* kdu); + +#endif diff --git a/indra/llkdu/llkdumem.cpp b/indra/llkdu/llkdumem.cpp new file mode 100644 index 0000000000..1f549cbbe0 --- /dev/null +++ b/indra/llkdu/llkdumem.cpp @@ -0,0 +1,196 @@ + /**  + * @file llkdumem.cpp + * @brief Helper class for kdu memory management + * + * $LicenseInfo:firstyear=2010&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 "llkdumem.h" +#include "llerror.h" + +#if defined(LL_WINDOWS) +# pragma warning(disable: 4702) // unreachable code +#endif + +LLKDUMemIn::LLKDUMemIn(const U8 *data, +					   const U32 size, +					   const U16 width, +					   const U16 height, +					   const U8 in_num_components, +					   siz_params *siz) +{ +	U8 n; + +	first_comp_idx = 0; +	rows = height; +	cols = width; +	num_components = in_num_components; +	alignment_bytes = 0; + +	for (n=0; n<3; ++n) +	{ +		precision[n] = 0; +	} + +	for (n=0; n < num_components; ++n) +	{ +		siz->set(Sdims,n,0,rows); +		siz->set(Sdims,n,1,cols); +		siz->set(Ssigned,n,0,false); +		siz->set(Sprecision,n,0,8); +	} +	incomplete_lines = NULL; +	free_lines = NULL; +	num_unread_rows = rows; + +	mData = data; +	mDataSize = size; +	mCurPos = 0; +} + +LLKDUMemIn::~LLKDUMemIn() +{ +	if ((num_unread_rows > 0) || (incomplete_lines != NULL)) +	{ +		kdu_warning w; +		w << "Not all rows of image components " +			<< first_comp_idx << " through " +			<< first_comp_idx+num_components-1 +			<< " were consumed!"; +	} +	image_line_buf *tmp; +	while ((tmp=incomplete_lines) != NULL) +    { +		incomplete_lines = tmp->next; +		delete tmp;  +	} +	while ((tmp=free_lines) != NULL) +    { +		free_lines = tmp->next; +		delete tmp; +	} +} + + +bool LLKDUMemIn::get(int comp_idx, kdu_line_buf &line, int x_tnum) +{ +	int idx = comp_idx - this->first_comp_idx; +	assert((idx >= 0) && (idx < num_components)); +	x_tnum = x_tnum*num_components+idx; +	image_line_buf *scan, *prev=NULL; +	for (scan=incomplete_lines; scan != NULL; prev=scan, scan=scan->next) +    { +		assert(scan->next_x_tnum >= x_tnum); +		if (scan->next_x_tnum == x_tnum) +		{ +			break; +		} +    } +	if (scan == NULL) +    { // Need to read a new image line. +		assert(x_tnum == 0); // Must consume in very specific order. +		if (num_unread_rows == 0) +		{ +	        return false; +		} +		if ((scan = free_lines) == NULL) +		{ +			scan = new image_line_buf(cols+3,num_components); +		} +		free_lines = scan->next; +		if (prev == NULL) +		{ +	        incomplete_lines = scan; +		} +		else +		{ +			prev->next = scan; +		} + +		// Copy from image buffer into scan. +		memcpy(scan->buf, mData+mCurPos, cols*num_components); +		mCurPos += cols*num_components; + +		num_unread_rows--; +		scan->accessed_samples = 0; +		scan->next_x_tnum = 0; +    } + +	assert((cols-scan->accessed_samples) >= line.get_width()); + +	int comp_offset = idx; +	kdu_byte *sp = scan->buf+num_components*scan->accessed_samples + comp_offset; +	int n=line.get_width(); + +	if (line.get_buf32() != NULL) +	{ +		kdu_sample32 *dp = line.get_buf32(); +		if (line.is_absolute()) +		{ // 32-bit absolute integers +			for (; n > 0; n--, sp+=num_components, dp++) +			{ +				dp->ival = ((kdu_int32)(*sp)) - 128; +			} +		} +		else +		{ // true 32-bit floats +			for (; n > 0; n--, sp+=num_components, dp++) +			{ +				dp->fval = (((float)(*sp)) / 256.0F) - 0.5F; +			} +		} +	} +	else +    { +		kdu_sample16 *dp = line.get_buf16(); +		if (line.is_absolute()) +		{ // 16-bit absolute integers +			for (; n > 0; n--, sp+=num_components, dp++) +			{ +				dp->ival = ((kdu_int16)(*sp)) - 128; +			} +		} +		else +		{ // 16-bit normalized representation. +			for (; n > 0; n--, sp+=num_components, dp++) +			{ +				dp->ival = (((kdu_int16)(*sp)) - 128) << (KDU_FIX_POINT-8); +			} +		} +    } + +	scan->next_x_tnum++; +	if (idx == (num_components-1)) +	{ +		scan->accessed_samples += line.get_width(); +	} +	if (scan->accessed_samples == cols) +	{ // Send empty line to free list. +		assert(scan == incomplete_lines); +		incomplete_lines = scan->next; +		scan->next = free_lines; +		free_lines = scan; +	} + +  return true; +} diff --git a/indra/llkdu/llkdumem.h b/indra/llkdu/llkdumem.h new file mode 100644 index 0000000000..7064de4408 --- /dev/null +++ b/indra/llkdu/llkdumem.h @@ -0,0 +1,145 @@ +/**  + * @file llkdumem.h + * @brief Helper class for kdu memory management + * + * $LicenseInfo:firstyear=2010&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_LLKDUMEM_H +#define LL_LLKDUMEM_H + +// Support classes for reading and writing from memory buffers in KDU +#include "kdu_image.h" +#include "kdu_elementary.h" +#include "kdu_messaging.h" +#include "kdu_params.h" +#include "kdu_compressed.h" +#include "kdu_sample_processing.h" +#include "image_local.h" +#include "stdtypes.h" + +class LLKDUMemSource: public kdu_compressed_source +{ +public: // Member functions +	LLKDUMemSource(U8 *input_buffer, U32 size) +	{ +		mData = input_buffer; +		mSize = size; +		mCurPos = 0; +	} + +    ~LLKDUMemSource() +	{ +	} + +    int read(kdu_byte *buf, int num_bytes) +	{ +		U32 num_out; +		num_out = num_bytes; + +		if ((mSize - mCurPos) < (U32)num_bytes) +		{ +			num_out = mSize -mCurPos; +		} +		memcpy(buf, mData + mCurPos, num_out); +		mCurPos += num_out; +		return num_out; +	} + +	void reset() +	{ +		mCurPos = 0; +	} + +private: // Data +	U8 *mData; +	U32 mSize; +	U32 mCurPos; +}; + +class LLKDUMemTarget: public kdu_compressed_target +{ +public: // Member functions +	LLKDUMemTarget(U8 *output_buffer, U32 &output_size, const U32 buffer_size) +	{ +		mData = output_buffer; +		mSize = buffer_size; +		mCurPos = 0; +		mOutputSize = &output_size; +	} + +    ~LLKDUMemTarget() +    { +	} + +    bool write(const kdu_byte *buf, int num_bytes) +	{ +		U32 num_out; +		num_out = num_bytes; + +		if ((mSize - mCurPos) < (U32)num_bytes) +		{ +			num_out = mSize - mCurPos; +			memcpy(mData + mCurPos, buf, num_out); +			return false; +		} +		memcpy(mData + mCurPos, buf, num_out); +		mCurPos += num_out; +		*mOutputSize = mCurPos; +		return true; +	} +	 +private: // Data +	U8 *mData; +	U32 mSize; +	U32 mCurPos; +	U32 *mOutputSize; +}; + +class LLKDUMemIn : public kdu_image_in_base +{ +public: // Member functions +    LLKDUMemIn(const U8 *data, +				const U32 size, +				const U16 rows, +				const U16 cols, +				U8 in_num_components, +				siz_params *siz); +    ~LLKDUMemIn(); + +    bool get(int comp_idx, kdu_line_buf &line, int x_tnum); + +private: // Data +	const U8 *mData; +    int first_comp_idx; +    int num_components; +    int rows, cols; +    int alignment_bytes; // Number of 0's at end of each line. +    int precision[3]; +    image_line_buf *incomplete_lines; // Each "sample" represents a full pixel +    image_line_buf *free_lines; +    int num_unread_rows; + +	U32 mCurPos; +	U32 mDataSize; +}; +#endif diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp index a442a0edb8..2ffc56644f 100644 --- a/indra/llmath/llcamera.cpp +++ b/indra/llmath/llcamera.cpp @@ -42,7 +42,6 @@ LLCamera::LLCamera() :  	mPlaneCount(6),  	mFrustumCornerDist(0.f)  { -	alignPlanes();  	calculateFrustumPlanes();  }  @@ -53,7 +52,6 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p  	mPlaneCount(6),  	mFrustumCornerDist(0.f)  { -	alignPlanes();  	mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO);  	mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE);  	if(far_plane < 0) far_plane = DEFAULT_FAR_PLANE; @@ -67,19 +65,6 @@ LLCamera::~LLCamera()  } -const LLCamera& LLCamera::operator=(const LLCamera& rhs) -{ -	memcpy(this, &rhs, sizeof(LLCamera)); -	alignPlanes(); -	LLVector4a::memcpyNonAliased16((F32*) mAgentPlanes, (F32*) rhs.mAgentPlanes, 4*7*sizeof(F32)); -	return *this; -} - -void LLCamera::alignPlanes() -{ -	mAgentPlanes = (LLPlane*) LL_NEXT_ALIGNED_ADDRESS<U8>(mAgentPlaneBuffer); -} -  // ---------------- LLCamera::getFoo() member functions ----------------  F32 LLCamera::getMinView() const  @@ -100,11 +85,11 @@ F32 LLCamera::getMaxView() const  // ---------------- LLCamera::setFoo() member functions ---------------- -void LLCamera::setUserClipPlane(LLPlane plane) +void LLCamera::setUserClipPlane(LLPlane& plane)  {  	mPlaneCount = 7;  	mAgentPlanes[6] = plane; -	mPlaneMask[6] = calcPlaneMask(plane); +	mPlaneMask[6] = plane.calcPlaneMask();  }  void LLCamera::disableUserClipPlane() @@ -190,38 +175,33 @@ S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius)  	};  	U8 mask = 0; -	S32 result = 2; - +	bool result = false; +	LLVector4a rscale, maxp, minp; +	LLSimdScalar d;  	for (U32 i = 0; i < mPlaneCount; i++)  	{  		mask = mPlaneMask[i]; -		if (mask == 0xff) -		{ -			continue; -		} - -		const LLPlane& p = mAgentPlanes[i]; -		const LLVector4a& n = reinterpret_cast<const LLVector4a&>(p); -		float d = p.mV[3]; -		LLVector4a rscale; -		rscale.setMul(radius, scaler[mask]); - -		LLVector4a minp, maxp; -		minp.setSub(center, rscale); -		maxp.setAdd(center, rscale); - -		if (n.dot3(minp) > -d)  +		if (mask != 0xff)  		{ -			return 0; -		} -	 -		if (n.dot3(maxp) > -d) -		{ -			result = 1; +			const LLPlane& p(mAgentPlanes[i]); +			p.getAt<3>(d); +			rscale.setMul(radius, scaler[mask]); +			minp.setSub(center, rscale); +			d = -d; +			if (p.dot3(minp).getF32() > d)  +			{ +				return 0; +			} +			 +			if(!result) +			{ +				maxp.setAdd(center, rscale); +				result = (p.dot3(maxp).getF32() > d); +			}  		}  	} -	return result; +	return result?1:2;  } @@ -239,43 +219,33 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a&  	};  	U8 mask = 0; -	S32 result = 2; - +	bool result = false; +	LLVector4a rscale, maxp, minp; +	LLSimdScalar d;  	for (U32 i = 0; i < mPlaneCount; i++)  	{ -		if (i == 5) -		{ -			continue; -		} -  		mask = mPlaneMask[i]; -		if (mask == 0xff) -		{ -			continue; -		} - -		const LLPlane& p = mAgentPlanes[i]; -		const LLVector4a& n = reinterpret_cast<const LLVector4a&>(p); -		float d = p.mV[3]; -		LLVector4a rscale; -		rscale.setMul(radius, scaler[mask]); - -		LLVector4a minp, maxp; -		minp.setSub(center, rscale); -		maxp.setAdd(center, rscale); - -		if (n.dot3(minp) > -d)  -		{ -			return 0; -		} -	 -		if (n.dot3(maxp) > -d) +		if ((i != 5) && (mask != 0xff))  		{ -			result = 1; +			const LLPlane& p(mAgentPlanes[i]); +			p.getAt<3>(d); +			rscale.setMul(radius, scaler[mask]); +			minp.setSub(center, rscale); +			d = -d; +			if (p.dot3(minp).getF32() > d)  +			{ +				return 0; +			} +			 +			if(!result) +			{ +				maxp.setAdd(center, rscale); +				result = (p.dot3(maxp).getF32() > d); +			}  		}  	} -	return result; +	return result?1:2;  }  int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)  @@ -396,28 +366,22 @@ int LLCamera::sphereInFrustumOld(const LLVector3 &sphere_center, const F32 radiu  int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) const   {  	// Returns 1 if sphere is in frustum, 0 if not. -	int res = 2; +	bool res = false;  	for (int i = 0; i < 6; i++)  	{ -		if (mPlaneMask[i] == 0xff) -		{ -			continue; -		} - -		float d = mAgentPlanes[i].dist(sphere_center); - -		if (d > radius)  +		if (mPlaneMask[i] != 0xff)  		{ -			return 0; -		} +			float d = mAgentPlanes[i].dist(sphere_center); -		if (d > -radius) -		{ -			res = 1; +			if (d > radius)  +			{ +				return 0; +			} +			res = res || (d > -radius);  		}  	} -	return res; +	return res?1:2;  } @@ -569,25 +533,6 @@ LLPlane planeFromPoints(LLVector3 p1, LLVector3 p2, LLVector3 p3)  	return LLPlane(p1, n);  } -U8 LLCamera::calcPlaneMask(const LLPlane& plane) -{ -	U8 mask = 0; -	 -	if (plane.mV[0] >= 0) -	{ -		mask |= 1; -	} -	if (plane.mV[1] >= 0) -	{ -		mask |= 2; -	} -	if (plane.mV[2] >= 0) -	{ -		mask |= 4; -	} - -	return mask; -}  void LLCamera::ignoreAgentFrustumPlane(S32 idx)  { @@ -597,13 +542,12 @@ void LLCamera::ignoreAgentFrustumPlane(S32 idx)  	}  	mPlaneMask[idx] = 0xff; -	mAgentPlanes[idx].clearVec(); +	mAgentPlanes[idx].clear();  }  void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)  { -	alignPlanes(); - +	  	for (int i = 0; i < 8; i++)  	{  		mAgentFrustum[i] = frust[i]; @@ -636,7 +580,7 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)  	//cache plane octant facing mask for use in AABBInFrustum  	for (U32 i = 0; i < mPlaneCount; i++)  	{ -		mPlaneMask[i] = calcPlaneMask(mAgentPlanes[i]); +		mPlaneMask[i] = mAgentPlanes[i].calcPlaneMask();  	}  } @@ -689,9 +633,10 @@ void LLCamera::calculateWorldFrustumPlanes()  	F32 d;  	LLVector3 center = mOrigin - mXAxis*mNearPlane;  	mWorldPlanePos = center; +	LLVector3 pnorm;	  	for (int p=0; p<4; p++)  	{ -		LLVector3 pnorm = LLVector3(mLocalPlanes[p]); +		mLocalPlanes[p].getVector3(pnorm);  		LLVector3 norm = rotateToAbsolute(pnorm);  		norm.normVec();  		d = -(center * norm); @@ -701,13 +646,15 @@ void LLCamera::calculateWorldFrustumPlanes()  	LLVector3 zaxis(0, 0, 1.0f);  	F32 yaw = getYaw();  	{ -		LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]); +		LLVector3 tnorm; +		mLocalPlanes[PLANE_LEFT].getVector3(tnorm);  		tnorm.rotVec(yaw, zaxis);  		d = -(mOrigin * tnorm);  		mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);  	}  	{ -		LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]); +		LLVector3 tnorm; +		mLocalPlanes[PLANE_RIGHT].getVector3(tnorm);  		tnorm.rotVec(yaw, zaxis);  		d = -(mOrigin * tnorm);  		mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d); diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index e15bd7ad43..82d80f1057 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -79,8 +79,6 @@ public:  	{  		*this = rhs;  	} - -	const LLCamera& operator=(const LLCamera& rhs);  	enum {  		PLANE_LEFT = 0, @@ -119,6 +117,9 @@ public:  	};  private: +	LLPlane mAgentPlanes[7];  //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP +	U8 mPlaneMask[8];         // 8 for alignment	 +	  	F32 mView;					// angle between top and bottom frustum planes in radians.  	F32 mAspect;				// width/height  	S32 mViewHeightInPixels;	// for ViewHeightInPixels() only @@ -132,10 +133,6 @@ private:  	LLPlane mWorldPlanes[PLANE_NUM];  	LLPlane mHorizPlanes[HORIZ_PLANE_NUM]; -	LLPlane* mAgentPlanes;  //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP -	U8 mAgentPlaneBuffer[sizeof(LLPlane)*8]; -	U8 mPlaneMask[7]; -  	U32 mPlaneCount;  //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in  	LLVector3 mWorldPlanePos;		// Position of World Planes (may be offset from camera) @@ -149,11 +146,9 @@ public:  	LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane);  	virtual ~LLCamera(); -	void alignPlanes(); -	void setUserClipPlane(LLPlane plane); +	void setUserClipPlane(LLPlane& plane);  	void disableUserClipPlane(); -	U8 calcPlaneMask(const LLPlane& plane);  	virtual void setView(F32 vertical_fov_rads);  	void setViewHeightInPixels(S32 height);  	void setAspect(F32 new_aspect); diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index ed97ff76ba..276f7b0f06 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -33,11 +33,7 @@  #include <vector>  #include <set> -#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG -#define OCT_ERRS LL_ERRS("OctreeErrors") -#else  #define OCT_ERRS LL_WARNS("OctreeErrors") -#endif  #define LL_OCTREE_PARANOIA_CHECK 0  #if LL_DARWIN diff --git a/indra/llmath/llplane.h b/indra/llmath/llplane.h index 443f3f46b9..a611894721 100644 --- a/indra/llmath/llplane.h +++ b/indra/llmath/llplane.h @@ -36,19 +36,23 @@  // The plane normal = [A, B, C]  // The closest approach = D / sqrt(A*A + B*B + C*C) -class LLPlane : public LLVector4 +class LLPlane  {  public: +	 +	// Constructors  	LLPlane() {}; // no default constructor  	LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); }  	LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); } -	void setVec(const LLVector3 &p0, F32 d) { LLVector4::setVec(p0[0], p0[1], p0[2], d); } -	void setVec(const LLVector3 &p0, const LLVector3 &n) +	inline void setVec(const LLVector3 &p0, F32 d) { mV.set(p0[0], p0[1], p0[2], d); } +	 +	// Set +	inline void setVec(const LLVector3 &p0, const LLVector3 &n)  	{  		F32 d = -(p0 * n);  		setVec(n, d);  	} -	void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2) +	inline void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2)  	{  		LLVector3 u, v, w;  		u = p1 - p0; @@ -58,8 +62,38 @@ public:  		F32 d = -(w * p0);  		setVec(w, d);  	} -	LLPlane& operator=(const LLVector4& v2) {  LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;} +	 +	inline LLPlane& operator=(const LLVector4& v2) {  mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;} +	 +	inline LLPlane& operator=(const LLVector4a& v2) {  mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;}	 +	 +	inline void set(const LLPlane& p2) { mV = p2.mV; } +	 +	//   	F32 dist(const LLVector3 &v2) const { return mV[0]*v2[0] + mV[1]*v2[1] + mV[2]*v2[2] + mV[3]; } +	 +	inline LLSimdScalar dot3(const LLVector4a& b) const { return mV.dot3(b); } +	 +	// Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates +	// the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead	 +	inline F32 operator[](const S32 idx) const { return mV[idx]; } +	 +	// preferable when index is known at compile time +	template <int N> LL_FORCE_INLINE void getAt(LLSimdScalar& v) const { v = mV.getScalarAt<N>(); }  +	 +	// reset the vector to 0, 0, 0, 1 +	inline void clear() { mV.set(0, 0, 0, 1); } +	 +	inline void getVector3(LLVector3& vec) const { vec.set(mV[0], mV[1], mV[2]); } +	 +	// Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero. +	inline U8 calcPlaneMask()  +	{  +		return mV.greaterEqual(LLVector4a::getZero()).getGatheredBits() & LLVector4Logical::MASK_XYZ; +	} +		 +private: +	LLVector4a mV;  }; diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 79022eade3..596082509d 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -67,7 +67,7 @@ public:  		extern const LLVector4a LL_V4A_ZERO;  		return LL_V4A_ZERO;  	} - +	  	// Return a vector of all epsilon, where epsilon is a small float suitable for approximate equality checks  	static inline const LLVector4a& getEpsilon()  	{ diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index 26aa2c250b..2f28673c07 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -20,6 +20,7 @@ include_directories(      ${LLRENDER_INCLUDE_DIRS}      ${LLXML_INCLUDE_DIRS}      ${LLWINDOW_INCLUDE_DIRS} +    ${LLQTWEBKIT_INCLUDE_DIR}      )  set(llplugin_SOURCE_FILES diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 69ed0fb09c..595c470a19 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -160,7 +160,7 @@ void LLPluginClassMedia::idle(void)  		mPlugin->idle();  	} -	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked())) +	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))  	{  		// Can't process a size change at this time  	} @@ -522,7 +522,15 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie  			}  		break;  	} -	 + +#if LL_DARWIN	 +	if(modifiers & MASK_ALT) +	{ +		// Option-key modified characters should be handled by the unicode input path instead of this one. +		result = false; +	} +#endif +  	if(result)  	{  		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); @@ -674,7 +682,21 @@ void LLPluginClassMedia::sendPickFileResponse(const std::string &file)  {  	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");  	message.setValue("file", file); -	if(mPlugin->isBlocked()) +	if(mPlugin && mPlugin->isBlocked()) +	{ +		// If the plugin sent a blocking pick-file request, the response should unblock it. +		message.setValueBoolean("blocking_response", true); +	} +	sendMessage(message); +} + +void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password) +{ +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); +	message.setValueBoolean("ok", ok); +	message.setValue("username", username); +	message.setValue("password", password); +	if(mPlugin && mPlugin->isBlocked())  	{  		// If the plugin sent a blocking pick-file request, the response should unblock it.  		message.setValueBoolean("blocking_response", true); @@ -947,6 +969,12 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)  		{  			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);  		} +		else if(message_name == "auth_request") +		{ +			mAuthURL = message.getValue("url"); +			mAuthRealm = message.getValue("realm"); +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); +		}  		else  		{  			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; @@ -1019,6 +1047,15 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)  			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);  		} +		else if(message_name == "link_hovered") +		{ +			// text is not currently used -- the tooltip hover text is taken from the "title". +			mHoverLink = message.getValue("link"); +			mHoverText = message.getValue("title"); +			// message.getValue("text"); +				 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); +		}  		else  		{  			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; @@ -1192,6 +1229,20 @@ void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)  	sendMessage(message);  } +void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore) +{ +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); +	message.setValueBoolean("ignore", ignore); +	sendMessage(message); +} + +void LLPluginClassMedia::addCertificateFilePath(const std::string& path) +{ +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path"); +	message.setValue("path", path); +	sendMessage(message); +} +  void LLPluginClassMedia::crashPlugin()  {  	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 9cb67fe909..c826e13c40 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -85,6 +85,8 @@ public:  	void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; +	void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; +	  	// Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent.  	// This will initially be false, and will also be false for some time after setSize while the resize is processed.  	// Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values @@ -159,6 +161,8 @@ public:  	void sendPickFileResponse(const std::string &file); +	void sendAuthResponse(bool ok, const std::string &username, const std::string &password); +  	// Valid after a MEDIA_EVENT_CURSOR_CHANGED event  	std::string getCursorName() const { return mCursorName; }; @@ -198,6 +202,8 @@ public:  	void setBrowserUserAgent(const std::string& user_agent);  	void proxyWindowOpened(const std::string &target, const std::string &uuid);  	void proxyWindowClosed(const std::string &uuid); +	void ignore_ssl_cert_errors(bool ignore); +	void addCertificateFilePath(const std::string& path);  	// This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE  	std::string	getNavigateURI() const { return mNavigateURI; }; @@ -231,7 +237,15 @@ public:  	S32 getGeometryY() const { return mGeometryY; };  	S32 getGeometryWidth() const { return mGeometryWidth; };  	S32 getGeometryHeight() const { return mGeometryHeight; }; +	 +	// These are valid during MEDIA_EVENT_AUTH_REQUEST +	std::string	getAuthURL() const { return mAuthURL; }; +	std::string	getAuthRealm() const { return mAuthRealm; }; +	// These are valid during MEDIA_EVENT_LINK_HOVERED +	std::string	getHoverText() const { return mHoverText; }; +	std::string	getHoverLink() const { return mHoverLink; }; +	  	std::string getMediaName() const { return mMediaName; };  	std::string getMediaDescription() const { return mMediaDescription; }; @@ -369,6 +383,10 @@ protected:  	S32				mGeometryY;  	S32				mGeometryWidth;  	S32				mGeometryHeight; +	std::string		mAuthURL; +	std::string		mAuthRealm; +	std::string		mHoverText; +	std::string		mHoverLink;  	/////////////////////////////////////////  	// media_time class diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index c9efff216c..42e93cc6d7 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -59,7 +59,11 @@ public:  		MEDIA_EVENT_GEOMETRY_CHANGE,		// The plugin requested its window geometry be changed (per the javascript window interface)  		MEDIA_EVENT_PLUGIN_FAILED_LAUNCH,	// The plugin failed to launch  -		MEDIA_EVENT_PLUGIN_FAILED			// The plugin died unexpectedly +		MEDIA_EVENT_PLUGIN_FAILED,			// The plugin died unexpectedly + +		MEDIA_EVENT_AUTH_REQUEST,			// The plugin wants to display an auth dialog + +		MEDIA_EVENT_LINK_HOVERED			// Got a "link hovered" event from the plugin  	} EMediaEvent; diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 28f152f49c..1869e1dd47 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -1878,21 +1878,57 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)  	}  	else  	{  //no exact match found, get closest point -		iter = mSkinWeights.begin(); -		weight_map::iterator best = iter; +		const F32 epsilon = 2.f/65536; +		weight_map::iterator iter_up = mSkinWeights.lower_bound(pos); +		weight_map::iterator iter_down = ++iter_up; + +		weight_map::iterator best = iter_up;  		F32 min_dist = (iter->first - pos).magVecSquared(); -		while (++iter != mSkinWeights.end()) -		{ -			F32 dist = (iter->first - pos).magVecSquared(); -			if (dist < min_dist) +		bool done = false; +		while (!done) +		{ //search up and down mSkinWeights from lower bound of pos until a  +		  //match is found within epsilon.  If no match is found within epsilon, +		  //return closest match +			done = true; +			if (iter_up != mSkinWeights.end() && ++iter_up != mSkinWeights.end())  			{ -				best = iter; -				min_dist = dist; +				done = false; +				F32 dist = (iter_up->first - pos).magVecSquared(); + +				if (dist < epsilon) +				{ +					return iter_up->second; +				} + +				if (dist < min_dist) +				{ +					best = iter_up; +					min_dist = dist; +				}  			} -		} +			if (iter_down != mSkinWeights.begin() && --iter_down != mSkinWeights.begin()) +			{ +				done = false; + +				F32 dist = (iter_down->first - pos).magVecSquared(); + +				if (dist < epsilon) +				{ +					return iter_down->second; +				} + +				if (dist < min_dist) +				{ +					best = iter_down; +					min_dist = dist; +				} + +			} +		} +		  		return best->second;  	}					  } diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index d802a3045d..9022026248 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -325,6 +325,7 @@ LLGLManager::LLGLManager() :  	mHasVertexShader(FALSE),  	mHasFragmentShader(FALSE),  	mHasOcclusionQuery(FALSE), +	mHasOcclusionQuery2(FALSE),  	mHasPointParameters(FALSE),  	mHasDrawBuffers(FALSE),  	mHasTextureRectangle(FALSE), @@ -666,6 +667,7 @@ void LLGLManager::initExtensions()  	mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts);  	mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");  	mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts); +	mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);  	mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);  	mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);  	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad @@ -782,6 +784,10 @@ void LLGLManager::initExtensions()  	{  		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_occlusion_query" << LL_ENDL;  	} +	if (!mHasOcclusionQuery2) +	{ +		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_occlusion_query2" << LL_ENDL; +	}  	if (!mHasPointParameters)  	{  		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_point_parameters" << LL_ENDL; @@ -1831,7 +1837,7 @@ LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& mode  	mModelview = modelview;  	mProjection = projection; -	setPlane(p.mV[0], p.mV[1], p.mV[2], p.mV[3]); +	setPlane(p[0], p[1], p[2], p[3]);  }  void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d) diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 4630811679..ff4e6078c9 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -89,6 +89,7 @@ public:  	BOOL mHasVertexShader;  	BOOL mHasFragmentShader;  	BOOL mHasOcclusionQuery; +	BOOL mHasOcclusionQuery2;  	BOOL mHasPointParameters;  	BOOL mHasDrawBuffers;  	BOOL mHasDepthClamp; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 761e4b67b3..684e393cba 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -111,6 +111,7 @@ set(llui_SOURCE_FILES      llviewmodel.cpp      llview.cpp      llviewquery.cpp +    llwindowshade.cpp      )  set(llui_HEADER_FILES @@ -210,6 +211,7 @@ set(llui_HEADER_FILES      llviewmodel.h      llview.h      llviewquery.h +    llwindowshade.h      )  set_source_files_properties(${llui_HEADER_FILES} diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index ac30fce392..19ac4c58a8 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -38,6 +38,12 @@  static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack");  static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel"); +void LLLayoutStack::OrientationNames::declareValues() +{ +	declare("horizontal", HORIZONTAL); +	declare("vertical", VERTICAL); +} +  //  // LLLayoutPanel  // @@ -47,47 +53,47 @@ LLLayoutPanel::LLLayoutPanel(const Params& p)   	mMaxDim(p.max_dim),    	mAutoResize(p.auto_resize),   	mUserResize(p.user_resize), -		mCollapsed(FALSE), -		mCollapseAmt(0.f), -		mVisibleAmt(1.f), // default to fully visible -		mResizeBar(NULL)  -	{ +	mCollapsed(FALSE), +	mCollapseAmt(0.f), +	mVisibleAmt(1.f), // default to fully visible +	mResizeBar(NULL)  +{  	// panels initialized as hidden should not start out partially visible  	if (!getVisible()) -		{ +	{  		mVisibleAmt = 0.f; -		} -		} +	} +}  void LLLayoutPanel::initFromParams(const Params& p) -		{ +{  	LLPanel::initFromParams(p);  	setFollowsNone(); -	} +}  LLLayoutPanel::~LLLayoutPanel() -	{ -		// probably not necessary, but... -		delete mResizeBar; -		mResizeBar = NULL; -	} +{ +	// probably not necessary, but... +	delete mResizeBar; +	mResizeBar = NULL; +}  F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation) -	{ +{  	if (orientation == LLLayoutStack::HORIZONTAL) -		{ -			F32 collapse_amt =  -			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth())); -			return mVisibleAmt * collapse_amt; -		} -		else +	{ +		F32 collapse_amt =  +		clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth())); +		return mVisibleAmt * collapse_amt; +	} +	else  	{  			F32 collapse_amt =   			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinDim / (F32)llmax(1, getRect().getHeight())));  			return mVisibleAmt * collapse_amt; -		}  	} +}  //  // LLLayoutStack @@ -109,7 +115,7 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)  	mMinWidth(0),  	mMinHeight(0),  	mPanelSpacing(p.border_size), -	mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL), +	mOrientation(p.orientation),  	mAnimate(p.animate),  	mAnimatedThisFrame(false),  	mClip(p.clip), diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index 2fc6164d7a..4ac8ef0ee9 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -37,12 +37,24 @@ class LLLayoutPanel;  class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>  {  public: +	typedef enum e_layout_orientation +	{ +		HORIZONTAL, +		VERTICAL +	} ELayoutOrientation; + +	struct OrientationNames +	:	public LLInitParam::TypeValuesHelper<ELayoutOrientation, OrientationNames> +	{ +		static void declareValues(); +	}; +  	struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry>  	{};  	struct Params : public LLInitParam::Block<Params, LLView::Params>  	{ -		Mandatory<std::string>	orientation; +		Mandatory<ELayoutOrientation, OrientationNames>	orientation;  		Optional<S32>			border_size;  		Optional<bool>			animate,  								clip; @@ -54,12 +66,6 @@ public:  	typedef LayoutStackRegistry child_registry_t; -	typedef enum e_layout_orientation -	{ -		HORIZONTAL, -		VERTICAL -	} ELayoutOrientation; -  	virtual ~LLLayoutStack();  	/*virtual*/ void draw(); @@ -171,6 +177,9 @@ public:  	~LLLayoutPanel();  	void initFromParams(const Params& p); +	void setMinDim(S32 value) { mMinDim = value; } +	void setMaxDim(S32 value) { mMaxDim = value; } +  protected:  	LLLayoutPanel(const Params& p)	; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 4064b7cc84..8c8c38415e 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -88,6 +88,7 @@ LLLineEditor::Params::Params()  	revert_on_esc("revert_on_esc", true),  	commit_on_focus_lost("commit_on_focus_lost", true),  	ignore_tab("ignore_tab", true), +	is_password("is_password", false),  	cursor_color("cursor_color"),  	text_color("text_color"),  	text_readonly_color("text_readonly_color"), @@ -129,7 +130,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)  	mBorderThickness( 0 ),  	mIgnoreArrowKeys( FALSE ),  	mIgnoreTab( p.ignore_tab ), -	mDrawAsterixes( FALSE ), +	mDrawAsterixes( p.is_password ),  	mSelectAllonFocusReceived( p.select_on_focus ),  	mPassDelete(FALSE),  	mReadOnly(FALSE), diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index ce2dfdeeb8..723423a5b9 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -85,7 +85,8 @@ public:  		Optional<bool>					select_on_focus,  										revert_on_esc,  										commit_on_focus_lost, -										ignore_tab; +										ignore_tab, +										is_password;  		// colors  		Optional<LLUIColor>				cursor_color, diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index c347e15792..cd0f0e36b0 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -82,6 +82,7 @@ LLNotificationForm::FormButton::FormButton()  LLNotificationForm::FormInput::FormInput()  :	type("type"), +	text("text"),  	max_length_chars("max_length_chars"),  	width("width", 0),  	value("value") @@ -421,7 +422,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par  		it != end_it;  		++it)  	{ -		mUniqueContext.push_back(it->key); +		mUniqueContext.push_back(it->value);  	}  	lldebugs << "notification \"" << mName << "\": tag count is " << p.tags.size() << llendl; @@ -792,13 +793,19 @@ bool LLNotification::isEquivalentTo(LLNotificationPtr that) const  	{  		const LLSD& these_substitutions = this->getSubstitutions();  		const LLSD& those_substitutions = that->getSubstitutions(); +		const LLSD& this_payload = this->getPayload(); +		const LLSD& that_payload = that->getPayload();  		// highlander bit sez there can only be one of these  		for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end();  			it != end_it;  			++it)  		{ -			if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString()) +			// if templates differ in either substitution strings or payload with the given field name +			// then they are considered inequivalent +			// use of get() avoids converting the LLSD value to a map as the [] operator would +			if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString() +				|| this_payload.get(*it).asString() != that_payload.get(*it).asString())  			{  				return false;  			} diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index f8f4469958..34d3537781 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -195,6 +195,7 @@ public:  		Mandatory<std::string>	type;  		Optional<S32>			width;  		Optional<S32>			max_length_chars; +		Optional<std::string>	text;  		Optional<std::string>	value;  		FormInput(); diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index 5a6ab40a2e..eff572b553 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -74,11 +74,13 @@ struct LLNotificationTemplate  	struct UniquenessContext : public LLInitParam::Block<UniquenessContext>  	{ -		Mandatory<std::string>	key; +		Mandatory<std::string>	value;  		UniquenessContext() -		:	key("key") -		{} +		:	value("value") +		{ +			addSynonym(value, "key"); +		}  	}; @@ -88,7 +90,7 @@ struct LLNotificationTemplate  		// this idiom allows   		// <notification unique="true">  		// as well as -		// <notification> <unique> <context key=""/> </unique>... +		// <notification> <unique> <context></context> </unique>...  		Optional<bool>			dummy_val;  	public:  		Multiple<UniquenessContext>	contexts; @@ -243,8 +245,8 @@ struct LLNotificationTemplate      // (used for things like progress indications, or repeating warnings      // like "the grid is going down in N minutes")      bool mUnique; -    // if we want to be unique only if a certain part of the payload is constant -    // specify the field names for the payload. The notification will only be +    // if we want to be unique only if a certain part of the payload or substitutions args +	// are constant specify the field names for the payload. The notification will only be      // combined if all of the fields named in the context are identical in the      // new and the old notification; otherwise, the notification will be      // duplicated. This is to support suppressing duplicate offers from the same diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index afd60cbb3e..0a06b5e74f 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -827,7 +827,7 @@ LLUICtrl* LLUICtrl::findRootMostFocusRoot()  {  	LLUICtrl* focus_root = NULL;  	LLUICtrl* next_view = this; -	while(next_view) +	while(next_view && next_view->hasTabStop())  	{  		if (next_view->isFocusRoot())  		{ diff --git a/indra/llui/llview.h b/indra/llui/llview.h index b7cd87e269..7e84eafce4 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -413,14 +413,9 @@ public:  	LLControlVariable *findControl(const std::string& name); -    // Moved setValue(), getValue(), setControlValue(), setControlName(), -    // controlListener() to LLUICtrl because an LLView is NOT assumed to -    // contain a value. If that's what you want, use LLUICtrl instead. -//	virtual bool	handleEvent(LLPointer<LLEvent> event, const LLSD& userdata); -  	const child_list_t*	getChildList() const { return &mChildList; } -	const child_list_const_iter_t	beginChild()  { return mChildList.begin(); } -	const child_list_const_iter_t	endChild()  { return mChildList.end(); } +	child_list_const_iter_t	beginChild() const { return mChildList.begin(); } +	child_list_const_iter_t	endChild() const { return mChildList.end(); }  	// LLMouseHandler functions  	//  Default behavior is to pass events to children diff --git a/indra/llui/llwindowshade.cpp b/indra/llui/llwindowshade.cpp new file mode 100644 index 0000000000..77e94385d4 --- /dev/null +++ b/indra/llui/llwindowshade.cpp @@ -0,0 +1,328 @@ +/** + * @file LLWindowShade.cpp + * @brief Notification dialog that slides down and optionally disabled a piece of UI + * + * $LicenseInfo:firstyear=2006&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 "llwindowshade.h" + +#include "lllayoutstack.h" +#include "lltextbox.h" +#include "lliconctrl.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "lllineeditor.h" + +const S32 MIN_NOTIFICATION_AREA_HEIGHT = 30; +const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100; + +LLWindowShade::Params::Params() +:	bg_image("bg_image"), +	modal("modal", false), +	text_color("text_color"), +	can_close("can_close", true) +{ +	mouse_opaque = false; +} + +LLWindowShade::LLWindowShade(const LLWindowShade::Params& params) +:	LLUICtrl(params), +	mNotification(params.notification), +	mModal(params.modal), +	mFormHeight(0), +	mTextColor(params.text_color) +{ +	setFocusRoot(true); +} + +void LLWindowShade::initFromParams(const LLWindowShade::Params& params) +{ +	LLUICtrl::initFromParams(params); + +	LLLayoutStack::Params layout_p; +	layout_p.name = "notification_stack"; +	layout_p.rect = params.rect; +	layout_p.follows.flags = FOLLOWS_ALL; +	layout_p.mouse_opaque = false; +	layout_p.orientation = LLLayoutStack::VERTICAL; +	layout_p.border_size = 0; + +	LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); +	addChild(stackp); + +	LLLayoutPanel::Params panel_p; +	panel_p.rect = LLRect(0, 30, 800, 0); +	panel_p.name = "notification_area"; +	panel_p.visible = false; +	panel_p.user_resize = false; +	panel_p.background_visible = true; +	panel_p.bg_alpha_image = params.bg_image; +	panel_p.auto_resize = false; +	LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); +	stackp->addChild(notification_panel); + +	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); +	panel_p.auto_resize = true; +	panel_p.user_resize = false; +	panel_p.rect = params.rect; +	panel_p.name = "background_area"; +	panel_p.mouse_opaque = false; +	panel_p.background_visible = false; +	panel_p.bg_alpha_color = LLColor4(0.f, 0.f, 0.f, 0.2f); +	LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); +	stackp->addChild(dummy_panel); + +	layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>(); +	layout_p.rect = LLRect(0, 30, 800, 0); +	layout_p.follows.flags = FOLLOWS_ALL; +	layout_p.orientation = LLLayoutStack::HORIZONTAL; +	stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); +	notification_panel->addChild(stackp); + +	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); +	panel_p.rect.height = 30; +	LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); +	stackp->addChild(panel); + +	LLIconCtrl::Params icon_p; +	icon_p.name = "notification_icon"; +	icon_p.rect = LLRect(5, 23, 21, 8); +	panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); + +	LLTextBox::Params text_p; +	text_p.rect = LLRect(31, 20, panel->getRect().getWidth() - 5, 0); +	text_p.follows.flags = FOLLOWS_ALL; +	text_p.text_color = mTextColor; +	text_p.font = LLFontGL::getFontSansSerifSmall(); +	text_p.font.style = "BOLD"; +	text_p.name = "notification_text"; +	text_p.use_ellipses = true; +	text_p.wrap = true; +	panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); + +	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); +	panel_p.auto_resize = false; +	panel_p.user_resize = false; +	panel_p.name="form_elements"; +	panel_p.rect = LLRect(0, 30, 130, 0); +	LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); +	stackp->addChild(form_elements_panel); + +	if (params.can_close) +	{ +		panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); +		panel_p.auto_resize = false; +		panel_p.user_resize = false; +		panel_p.rect = LLRect(0, 30, 25, 0); +		LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); +		stackp->addChild(close_panel); + +		LLButton::Params button_p; +		button_p.name = "close_notification"; +		button_p.rect = LLRect(5, 23, 21, 7); +		button_p.image_color.control="DkGray_66"; +		button_p.image_unselected.name="Icon_Close_Foreground"; +		button_p.image_selected.name="Icon_Close_Press"; +		button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this); + +		close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); +	} + +	LLSD payload = mNotification->getPayload(); + +	LLNotificationFormPtr formp = mNotification->getForm(); +	LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area"); +	notification_area.getChild<LLUICtrl>("notification_icon")->setValue(mNotification->getIcon()); +	notification_area.getChild<LLUICtrl>("notification_text")->setValue(mNotification->getMessage()); +	notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(mNotification->getMessage()); + +	LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType();  +	LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements"); +	form_elements.deleteAllChildren(); + +	const S32 FORM_PADDING_HORIZONTAL = 10; +	const S32 FORM_PADDING_VERTICAL = 3; +	const S32 WIDGET_HEIGHT = 24; +	const S32 LINE_EDITOR_WIDTH = 120; +	S32 cur_x = FORM_PADDING_HORIZONTAL; +	S32 cur_y = FORM_PADDING_VERTICAL + WIDGET_HEIGHT; +	S32 form_width = cur_x; + +	if (ignore_type != LLNotificationForm::IGNORE_NO) +	{ +		LLCheckBoxCtrl::Params checkbox_p; +		checkbox_p.name = "ignore_check"; +		checkbox_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT); +		checkbox_p.label = formp->getIgnoreMessage(); +		checkbox_p.label_text.text_color = LLColor4::black; +		checkbox_p.commit_callback.function = boost::bind(&LLWindowShade::onClickIgnore, this, _1); +		checkbox_p.initial_value = formp->getIgnored(); + +		LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); +		check->setRect(check->getBoundingRect()); +		form_elements.addChild(check); +		cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL; +		form_width = llmax(form_width, cur_x); +	} + +	for (S32 i = 0; i < formp->getNumElements(); i++) +	{ +		LLSD form_element = formp->getElement(i); +		std::string type = form_element["type"].asString(); +		if (type == "button") +		{ +			LLButton::Params button_p; +			button_p.name = form_element["name"]; +			button_p.label = form_element["text"]; +			button_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT); +			button_p.click_callback.function = boost::bind(&LLWindowShade::onClickNotificationButton, this, form_element["name"].asString()); +			button_p.auto_resize = true; + +			LLButton* button = LLUICtrlFactory::create<LLButton>(button_p); +			button->autoResize(); +			form_elements.addChild(button); + +			if (form_element["default"].asBoolean()) +			{ +				form_elements.setDefaultBtn(button); +			} + +			cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL; +			form_width = llmax(form_width, cur_x); +		} +		else if (type == "text" || type == "password") +		{ +			// if not at beginning of line... +			if (cur_x != FORM_PADDING_HORIZONTAL) +			{ +				// start new line +				cur_x = FORM_PADDING_HORIZONTAL; +				cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL; +			} +			LLTextBox::Params label_p; +			label_p.name = form_element["name"].asString() + "_label"; +			label_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT); +			label_p.initial_value = form_element["text"]; +			label_p.text_color = mTextColor; +			label_p.font_valign = LLFontGL::VCENTER; +			label_p.v_pad = 5; +			LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p); +			textbox->reshapeToFitText(); +			textbox->reshape(textbox->getRect().getWidth(), form_elements.getRect().getHeight() - 2 * FORM_PADDING_VERTICAL);  +			form_elements.addChild(textbox); +			cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL; + +			LLLineEditor::Params line_p; +			line_p.name = form_element["name"]; +			line_p.keystroke_callback = boost::bind(&LLWindowShade::onEnterNotificationText, this, _1, form_element["name"].asString()); +			line_p.is_password = type == "password"; +			line_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT); + +			LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p); +			form_elements.addChild(line_editor); +			form_width = llmax(form_width, cur_x + LINE_EDITOR_WIDTH + FORM_PADDING_HORIZONTAL); + +			// reset to start of next line +			cur_x = FORM_PADDING_HORIZONTAL; +			cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL; +		} +	} + +	mFormHeight = form_elements.getRect().getHeight() - (cur_y - FORM_PADDING_VERTICAL) + WIDGET_HEIGHT; +	form_elements.reshape(form_width, mFormHeight); +	form_elements.setMinDim(form_width); + +	// move all form elements back onto form surface +	S32 delta_y = WIDGET_HEIGHT + FORM_PADDING_VERTICAL - cur_y; +	for (child_list_const_iter_t it = form_elements.getChildList()->begin(), end_it = form_elements.getChildList()->end(); +		it != end_it; +		++it) +	{ +		(*it)->translate(0, delta_y); +	} +} + +void LLWindowShade::show() +{ +	getChildRef<LLLayoutPanel>("notification_area").setVisible(true); +	getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal); + +	setMouseOpaque(mModal); +} + +void LLWindowShade::draw() +{ +	LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect(); + +	LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area"); + +	notification_area->reshape(notification_area->getRect().getWidth(),  +		llclamp(message_rect.getHeight() + 10,  +				llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT), +				MAX_NOTIFICATION_AREA_HEIGHT)); + +	LLUICtrl::draw(); +	if (mNotification && !mNotification->isActive()) +	{ +		hide(); +	} +} + +void LLWindowShade::hide() +{ +	getChildRef<LLLayoutPanel>("notification_area").setVisible(false); +	getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false); + +	setMouseOpaque(false); +} + +void LLWindowShade::onCloseNotification() +{ +	LLNotifications::instance().cancel(mNotification); +} + +void LLWindowShade::onClickIgnore(LLUICtrl* ctrl) +{ +	bool check = ctrl->getValue().asBoolean(); +	if (mNotification && mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) +	{ +		// question was "show again" so invert value to get "ignore" +		check = !check; +	} +	mNotification->setIgnored(check); +} + +void LLWindowShade::onClickNotificationButton(const std::string& name) +{ +	if (!mNotification) return; + +	mNotificationResponse[name] = true; + +	mNotification->respond(mNotificationResponse); +} + +void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name) +{ +	mNotificationResponse[name] = ctrl->getValue().asString(); +} diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h new file mode 100644 index 0000000000..0047195929 --- /dev/null +++ b/indra/llui/llwindowshade.h @@ -0,0 +1,69 @@ +/** + * @file llwindowshade.h + * @brief Notification dialog that slides down and optionally disabled a piece of UI + * + * $LicenseInfo:firstyear=2006&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_LLWINDOWSHADE_H +#define LL_LLWINDOWSHADE_H + +#include "lluictrl.h" +#include "llnotifications.h" + +class LLWindowShade : public LLUICtrl +{ +public: +	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> +	{ +		Mandatory<LLNotificationPtr>	notification; +		Optional<LLUIImage*>			bg_image; +		Optional<LLUIColor>				text_color; +		Optional<bool>					modal, +										can_close; + +		Params(); +	}; + +	void show(); +	/*virtual*/ void draw(); +	void hide(); + +private: +	friend class LLUICtrlFactory; + +	LLWindowShade(const Params& p); +	void initFromParams(const Params& params); + +	void onCloseNotification(); +	void onClickNotificationButton(const std::string& name); +	void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name); +	void onClickIgnore(LLUICtrl* ctrl); + +	LLNotificationPtr	mNotification; +	LLSD				mNotificationResponse; +	bool				mModal; +	S32					mFormHeight; +	LLUIColor			mTextColor; +}; + +#endif // LL_LLWINDOWSHADE_H diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index bf3233f386..4d2677fd91 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -59,12 +59,13 @@ set(viewer_HEADER_FILES  # Libraries on which this library depends, needed for Linux builds  # Sort by high-level to low-level -if (NOT LINUX OR VIEWER) +if (LINUX AND VIEWER)    set(llwindow_LINK_LIBRARIES        ${UI_LIBRARIES}     # for GTK        ${SDL_LIBRARY} +      fontconfig          # For FCInit and other FC* functions.        ) -endif (NOT LINUX OR VIEWER) +endif (LINUX AND VIEWER)  if (DARWIN)    list(APPEND llwindow_SOURCE_FILES diff --git a/indra/mac_updater/CMakeLists.txt b/indra/mac_updater/CMakeLists.txt index 44f98e5e18..a4a6b50c6c 100644 --- a/indra/mac_updater/CMakeLists.txt +++ b/indra/mac_updater/CMakeLists.txt @@ -3,6 +3,7 @@  project(mac_updater)  include(00-Common) +include(OpenSSL)  include(CURL)  include(LLCommon)  include(LLVFS) @@ -49,6 +50,8 @@ set_target_properties(mac-updater  target_link_libraries(mac-updater      ${LLVFS_LIBRARIES} +    ${OPENSSL_LIBRARIES} +    ${CRYPTO_LIBRARIES}      ${CURL_LIBRARIES}      ${LLCOMMON_LIBRARIES}      ) diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp index f8a871930e..da7de01799 100644 --- a/indra/media_plugins/example/media_plugin_example.cpp +++ b/indra/media_plugins/example/media_plugin_example.cpp @@ -6,21 +6,21 @@   * $LicenseInfo:firstyear=2008&license=viewerlgpl$   * Second Life Viewer Source Code   * Copyright (C) 2010, Linden Research, Inc. - *  + *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public   * License as published by the Free Software Foundation;   * version 2.1 of the License only. - *  + *   * This library is distributed in the hope that it will be useful,   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * Lesser General Public License for more details. - *  + *   * You should have received a copy of the GNU Lesser General Public   * License along with this library; if not, write to the Free Software   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  + *   * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA   * $/LicenseInfo$   * @endcond @@ -39,48 +39,48 @@  ////////////////////////////////////////////////////////////////////////////////  //  class MediaPluginExample : -		public MediaPluginBase +        public MediaPluginBase  { -	public: -		MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ); -		~MediaPluginExample(); - -		/*virtual*/ void receiveMessage( const char* message_string ); - -	private: -		bool init(); -		void update( F64 milliseconds ); -		void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ); -		bool mFirstTime; - -		time_t mLastUpdateTime; -		enum Constants { ENumObjects = 10 }; -		unsigned char* mBackgroundPixels; -		int mColorR[ ENumObjects ]; -		int mColorG[ ENumObjects ]; -		int mColorB[ ENumObjects ]; -		int mXpos[ ENumObjects ]; -		int mYpos[ ENumObjects ]; -		int mXInc[ ENumObjects ]; -		int mYInc[ ENumObjects ]; -		int mBlockSize[ ENumObjects ]; -		bool mMouseButtonDown; -		bool mStopAction; +    public: +        MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ); +        ~MediaPluginExample(); + +        /*virtual*/ void receiveMessage( const char* message_string ); + +    private: +        bool init(); +        void update( F64 milliseconds ); +        void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ); +        bool mFirstTime; + +        time_t mLastUpdateTime; +        enum Constants { ENumObjects = 10 }; +        unsigned char* mBackgroundPixels; +        int mColorR[ ENumObjects ]; +        int mColorG[ ENumObjects ]; +        int mColorB[ ENumObjects ]; +        int mXpos[ ENumObjects ]; +        int mYpos[ ENumObjects ]; +        int mXInc[ ENumObjects ]; +        int mYInc[ ENumObjects ]; +        int mBlockSize[ ENumObjects ]; +        bool mMouseButtonDown; +        bool mStopAction;  };  ////////////////////////////////////////////////////////////////////////////////  //  MediaPluginExample::MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ) : -	MediaPluginBase( host_send_func, host_user_data ) +    MediaPluginBase( host_send_func, host_user_data )  { -	mFirstTime = true; -	mWidth = 0; -	mHeight = 0; -	mDepth = 4; -	mPixels = 0; -	mMouseButtonDown = false; -	mStopAction = false; -	mLastUpdateTime = 0; +    mFirstTime = true; +    mWidth = 0; +    mHeight = 0; +    mDepth = 4; +    mPixels = 0; +    mMouseButtonDown = false; +    mStopAction = false; +    mLastUpdateTime = 0;  }  //////////////////////////////////////////////////////////////////////////////// @@ -93,395 +93,320 @@ MediaPluginExample::~MediaPluginExample()  //  void MediaPluginExample::receiveMessage( const char* message_string )  { -	LLPluginMessage message_in; - -	if ( message_in.parse( message_string ) >= 0 ) -	{ -		std::string message_class = message_in.getClass(); -		std::string message_name = message_in.getName(); - -		if ( message_class == LLPLUGIN_MESSAGE_CLASS_BASE ) -		{ -			if ( message_name == "init" ) -			{ -				LLPluginMessage message( "base", "init_response" ); -				LLSD versions = LLSD::emptyMap(); -				versions[ LLPLUGIN_MESSAGE_CLASS_BASE ] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; -				versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; -				versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; -				message.setValueLLSD( "versions", versions ); - -				std::string plugin_version = "Example media plugin, Example Version 1.0.0.0"; -				message.setValue( "plugin_version", plugin_version ); -				sendMessage( message ); -			} -			else -			if ( message_name == "idle" ) -			{ -				// no response is necessary here. -				F64 time = message_in.getValueReal( "time" ); - -				// Convert time to milliseconds for update() -				update( time ); -			} -			else -			if ( message_name == "cleanup" ) -			{ -				// clean up here -			} -			else -			if ( message_name == "shm_added" ) -			{ -				SharedSegmentInfo info; -				info.mAddress = message_in.getValuePointer( "address" ); -				info.mSize = ( size_t )message_in.getValueS32( "size" ); -				std::string name = message_in.getValue( "name" ); - -				mSharedSegments.insert( SharedSegmentMap::value_type( name, info ) ); - -			} -			else -			if ( message_name == "shm_remove" ) -			{ -				std::string name = message_in.getValue( "name" ); - -				SharedSegmentMap::iterator iter = mSharedSegments.find( name ); -				if( iter != mSharedSegments.end() ) -				{ -					if ( mPixels == iter->second.mAddress ) -					{ -						// This is the currently active pixel buffer. -						// Make sure we stop drawing to it. -						mPixels = NULL; -						mTextureSegmentName.clear(); -					}; -					mSharedSegments.erase( iter ); -				} -				else -				{ -					//std::cerr << "MediaPluginExample::receiveMessage: unknown shared memory region!" << std::endl; -				}; - -				// Send the response so it can be cleaned up. -				LLPluginMessage message( "base", "shm_remove_response" ); -				message.setValue( "name", name ); -				sendMessage( message ); -			} -			else -			{ -				//std::cerr << "MediaPluginExample::receiveMessage: unknown base message: " << message_name << std::endl; -			}; -		} -		else -		if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA ) -		{ -			if ( message_name == "init" ) -			{ -				// Plugin gets to decide the texture parameters to use. -				LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params" ); -				message.setValueS32( "default_width", mWidth ); -				message.setValueS32( "default_height", mHeight ); -				message.setValueS32( "depth", mDepth ); -				message.setValueU32( "internalformat", GL_RGBA ); -				message.setValueU32( "format", GL_RGBA ); -				message.setValueU32( "type", GL_UNSIGNED_BYTE ); -				message.setValueBoolean( "coords_opengl", false ); -				sendMessage( message ); -			} -			else if ( message_name == "size_change" ) -			{ -				std::string name = message_in.getValue( "name" ); -				S32 width = message_in.getValueS32( "width" ); -				S32 height = message_in.getValueS32( "height" ); -				S32 texture_width = message_in.getValueS32( "texture_width" ); -				S32 texture_height = message_in.getValueS32( "texture_height" ); - -				if ( ! name.empty() ) -				{ -					// Find the shared memory region with this name -					SharedSegmentMap::iterator iter = mSharedSegments.find( name ); -					if ( iter != mSharedSegments.end() ) -					{ -						mPixels = ( unsigned char* )iter->second.mAddress; -						mWidth = width; -						mHeight = height; - -						mTextureWidth = texture_width; -						mTextureHeight = texture_height; - -						init(); -					}; -				}; - -				LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response" ); -				message.setValue( "name", name ); -				message.setValueS32( "width", width ); -				message.setValueS32( "height", height ); -				message.setValueS32( "texture_width", texture_width ); -				message.setValueS32( "texture_height", texture_height ); -				sendMessage( message ); -			} -			else -			if ( message_name == "load_uri" ) -			{ -				std::string uri = message_in.getValue( "uri" ); -				if ( ! uri.empty() ) -				{ -				}; -			} -			else -			if ( message_name == "mouse_event" ) -			{ -				std::string event = message_in.getValue( "event" ); -				S32 button = message_in.getValueS32( "button" ); - -				// left mouse button -				if ( button == 0 ) -				{ -					int mouse_x = message_in.getValueS32( "x" ); -					int mouse_y = message_in.getValueS32( "y" ); -					std::string modifiers = message_in.getValue( "modifiers" ); - -					if ( event == "move" ) -					{ -						if ( mMouseButtonDown ) -							write_pixel( mouse_x, mouse_y, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80 ); -					} -					else -					if ( event == "down" ) -					{ -						mMouseButtonDown = true; -					} -					else -					if ( event == "up" ) -					{ -						mMouseButtonDown = false; -					} -					else -					if ( event == "double_click" ) -					{ -					}; -				}; -			} -			else -			if ( message_name == "key_event" ) -			{ -				std::string event = message_in.getValue( "event" ); -				S32 key = message_in.getValueS32( "key" ); -				std::string modifiers = message_in.getValue( "modifiers" ); - -				if ( event == "down" ) -				{ -					if ( key == ' ') -					{ -						mLastUpdateTime = 0; -						update( 0.0f ); -					}; -				}; -			} -			else -			{ -				//std::cerr << "MediaPluginExample::receiveMessage: unknown media message: " << message_string << std::endl; -			}; -		} -		else -		if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER ) -		{ -			if ( message_name == "browse_reload" ) -			{ -				mLastUpdateTime = 0; -				mFirstTime = true; -				mStopAction = false; -				update( 0.0f ); -			} -			else -			if ( message_name == "browse_stop" ) -			{ -				for( int n = 0; n < ENumObjects; ++n ) -					mXInc[ n ] = mYInc[ n ] = 0; - -				mStopAction = true; -				update( 0.0f ); -			} -			else -			{ -				//std::cerr << "MediaPluginExample::receiveMessage: unknown media_browser message: " << message_string << std::endl; -			}; -		} -		else -		{ -			//std::cerr << "MediaPluginExample::receiveMessage: unknown message class: " << message_class << std::endl; -		}; -	}; +//  std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; +    LLPluginMessage message_in; + +    if(message_in.parse(message_string) >= 0) +    { +        std::string message_class = message_in.getClass(); +        std::string message_name = message_in.getName(); +        if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) +        { +            if(message_name == "init") +            { +                LLPluginMessage message("base", "init_response"); +                LLSD versions = LLSD::emptyMap(); +                versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; +                versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; +                versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; +                message.setValueLLSD("versions", versions); + +                std::string plugin_version = "Example plugin 1.0..0"; +                message.setValue("plugin_version", plugin_version); +                sendMessage(message); +            } +            else if(message_name == "idle") +            { +                // no response is necessary here. +                F64 time = message_in.getValueReal("time"); + +                // Convert time to milliseconds for update() +                update((int)(time * 1000.0f)); +            } +            else if(message_name == "cleanup") +            { +            } +            else if(message_name == "shm_added") +            { +                SharedSegmentInfo info; +                info.mAddress = message_in.getValuePointer("address"); +                info.mSize = (size_t)message_in.getValueS32("size"); +                std::string name = message_in.getValue("name"); + +                mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + +            } +            else if(message_name == "shm_remove") +            { +                std::string name = message_in.getValue("name"); + +                SharedSegmentMap::iterator iter = mSharedSegments.find(name); +                if(iter != mSharedSegments.end()) +                { +                    if(mPixels == iter->second.mAddress) +                    { +                        // This is the currently active pixel buffer.  Make sure we stop drawing to it. +                        mPixels = NULL; +                        mTextureSegmentName.clear(); +                    } +                    mSharedSegments.erase(iter); +                } +                else +                { +//                  std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; +                } + +                // Send the response so it can be cleaned up. +                LLPluginMessage message("base", "shm_remove_response"); +                message.setValue("name", name); +                sendMessage(message); +            } +            else +            { +//              std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; +            } +        } +        else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) +        { +            if(message_name == "init") +            { +                // Plugin gets to decide the texture parameters to use. +                mDepth = 4; +                LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); +                message.setValueS32("default_width", 1024); +                message.setValueS32("default_height", 1024); +                message.setValueS32("depth", mDepth); +                message.setValueU32("internalformat", GL_RGBA); +                message.setValueU32("format", GL_RGBA); +                message.setValueU32("type", GL_UNSIGNED_BYTE); +                message.setValueBoolean("coords_opengl", true); +                sendMessage(message); +            } +            else if(message_name == "size_change") +            { +                std::string name = message_in.getValue("name"); +                S32 width = message_in.getValueS32("width"); +                S32 height = message_in.getValueS32("height"); +                S32 texture_width = message_in.getValueS32("texture_width"); +                S32 texture_height = message_in.getValueS32("texture_height"); + +                if(!name.empty()) +                { +                    // Find the shared memory region with this name +                    SharedSegmentMap::iterator iter = mSharedSegments.find(name); +                    if(iter != mSharedSegments.end()) +                    { +                        mPixels = (unsigned char*)iter->second.mAddress; +                        mWidth = width; +                        mHeight = height; + +                        mTextureWidth = texture_width; +                        mTextureHeight = texture_height; +                    }; +                }; + +                LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); +                message.setValue("name", name); +                message.setValueS32("width", width); +                message.setValueS32("height", height); +                message.setValueS32("texture_width", texture_width); +                message.setValueS32("texture_height", texture_height); +                sendMessage(message); + +            } +            else if(message_name == "load_uri") +            { +            } +            else if(message_name == "mouse_event") +            { +                std::string event = message_in.getValue("event"); +                if(event == "down") +                { + +                } +                else if(event == "up") +                { +                } +                else if(event == "double_click") +                { +                } +            } +        } +        else +        { +//          std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; +        }; +    }  }  ////////////////////////////////////////////////////////////////////////////////  //  void MediaPluginExample::write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b )  { -	// make sure we don't write outside the buffer -	if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) ) -		return; -		 -	if ( mBackgroundPixels != NULL ) -	{ -		unsigned char *pixel = mBackgroundPixels; -		pixel += y * mWidth * mDepth; -		pixel += ( x * mDepth ); -		pixel[ 0 ] = b; -		pixel[ 1 ] = g; -		pixel[ 2 ] = r; - -		setDirty( x, y, x + 1, y + 1 ); -	}; +    // make sure we don't write outside the buffer +    if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) ) +        return; + +    if ( mBackgroundPixels != NULL ) +    { +        unsigned char *pixel = mBackgroundPixels; +        pixel += y * mWidth * mDepth; +        pixel += ( x * mDepth ); +        pixel[ 0 ] = b; +        pixel[ 1 ] = g; +        pixel[ 2 ] = r; + +        setDirty( x, y, x + 1, y + 1 ); +    };  }  ////////////////////////////////////////////////////////////////////////////////  //  void MediaPluginExample::update( F64 milliseconds )  { -	if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 ) -		return; - -	if ( mPixels == 0 ) -			return; - -	if ( mFirstTime ) -	{ -		for( int n = 0; n < ENumObjects; ++n ) -		{ -			mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 ); -			mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 ); - -			mColorR[ n ] = rand() % 0x60 + 0x60; -			mColorG[ n ] = rand() % 0x60 + 0x60; -			mColorB[ n ] = rand() % 0x60 + 0x60; - -			mXInc[ n ] = 0; -			while ( mXInc[ n ] == 0 ) -				mXInc[ n ] = rand() % 7 - 3; - -			mYInc[ n ] = 0; -			while ( mYInc[ n ] == 0 ) -				mYInc[ n ] = rand() % 9 - 4; - -			mBlockSize[ n ] = rand() % 0x30 + 0x10; -		}; - -		delete [] mBackgroundPixels; -				 -		mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ]; - -		mFirstTime = false; -	}; - -	if ( mStopAction ) -		return; - -	if ( time( NULL ) > mLastUpdateTime + 3 ) -	{ -		const int num_squares = rand() % 20 + 4; -		int sqr1_r = rand() % 0x80 + 0x20; -		int sqr1_g = rand() % 0x80 + 0x20; -		int sqr1_b = rand() % 0x80 + 0x20; -		int sqr2_r = rand() % 0x80 + 0x20; -		int sqr2_g = rand() % 0x80 + 0x20; -		int sqr2_b = rand() % 0x80 + 0x20; - -		for ( int y1 = 0; y1 < num_squares; ++y1 ) -		{ -			for ( int x1 = 0; x1 < num_squares; ++x1 ) -			{ -				int px_start = mWidth * x1 / num_squares; -				int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares; -				int py_start = mHeight * y1 / num_squares; -				int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares; - -				for( int y2 = py_start; y2 < py_end; ++y2 ) -				{ -					for( int x2 = px_start; x2 < px_end; ++x2 ) -					{ -						int rowspan = mWidth * mDepth; - -						if ( ( y1 % 2 ) ^ ( x1 % 2 ) ) -						{ -							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r; -							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g; -							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b; -						} -						else -						{ -							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r; -							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g; -							mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b; -						}; -					}; -				}; -			}; -		}; - -		time( &mLastUpdateTime ); -	}; - -	memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth ); - -	for( int n = 0; n < ENumObjects; ++n ) -	{ -		if ( rand() % 50 == 0 ) -		{ -				mXInc[ n ] = 0; -				while ( mXInc[ n ] == 0 ) -					mXInc[ n ] = rand() % 7 - 3; - -				mYInc[ n ] = 0; -				while ( mYInc[ n ] == 0 ) -					mYInc[ n ] = rand() % 9 - 4; -		}; - -		if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] ) -			mXInc[ n ] =- mXInc[ n ]; - -		if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] ) -			mYInc[ n ] =- mYInc[ n ]; - -		mXpos[ n ] += mXInc[ n ]; -		mYpos[ n ] += mYInc[ n ]; - -		for( int y = 0; y < mBlockSize[ n ]; ++y ) -		{ -			for( int x = 0; x < mBlockSize[ n ]; ++x ) -			{ -				mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ]; -				mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ]; -				mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ]; -			}; -		}; -	}; - -	setDirty( 0, 0, mWidth, mHeight ); +    if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 ) +        return; + +    if ( mPixels == 0 ) +            return; + +    if ( mFirstTime ) +    { +        for( int n = 0; n < ENumObjects; ++n ) +        { +            mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 ); +            mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 ); + +            mColorR[ n ] = rand() % 0x60 + 0x60; +            mColorG[ n ] = rand() % 0x60 + 0x60; +            mColorB[ n ] = rand() % 0x60 + 0x60; + +            mXInc[ n ] = 0; +            while ( mXInc[ n ] == 0 ) +                mXInc[ n ] = rand() % 7 - 3; + +            mYInc[ n ] = 0; +            while ( mYInc[ n ] == 0 ) +                mYInc[ n ] = rand() % 9 - 4; + +            mBlockSize[ n ] = rand() % 0x30 + 0x10; +        }; + +        delete [] mBackgroundPixels; + +        mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ]; + +        mFirstTime = false; +    }; + +    if ( mStopAction ) +        return; + +    if ( time( NULL ) > mLastUpdateTime + 3 ) +    { +        const int num_squares = rand() % 20 + 4; +        int sqr1_r = rand() % 0x80 + 0x20; +        int sqr1_g = rand() % 0x80 + 0x20; +        int sqr1_b = rand() % 0x80 + 0x20; +        int sqr2_r = rand() % 0x80 + 0x20; +        int sqr2_g = rand() % 0x80 + 0x20; +        int sqr2_b = rand() % 0x80 + 0x20; + +        for ( int y1 = 0; y1 < num_squares; ++y1 ) +        { +            for ( int x1 = 0; x1 < num_squares; ++x1 ) +            { +                int px_start = mWidth * x1 / num_squares; +                int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares; +                int py_start = mHeight * y1 / num_squares; +                int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares; + +                for( int y2 = py_start; y2 < py_end; ++y2 ) +                { +                    for( int x2 = px_start; x2 < px_end; ++x2 ) +                    { +                        int rowspan = mWidth * mDepth; + +                        if ( ( y1 % 2 ) ^ ( x1 % 2 ) ) +                        { +                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r; +                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g; +                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b; +                        } +                        else +                        { +                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r; +                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g; +                            mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b; +                        }; +                    }; +                }; +            }; +        }; + +        time( &mLastUpdateTime ); +    }; + +    memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth ); + +    for( int n = 0; n < ENumObjects; ++n ) +    { +        if ( rand() % 50 == 0 ) +        { +                mXInc[ n ] = 0; +                while ( mXInc[ n ] == 0 ) +                    mXInc[ n ] = rand() % 7 - 3; + +                mYInc[ n ] = 0; +                while ( mYInc[ n ] == 0 ) +                    mYInc[ n ] = rand() % 9 - 4; +        }; + +        if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] ) +            mXInc[ n ] =- mXInc[ n ]; + +        if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] ) +            mYInc[ n ] =- mYInc[ n ]; + +        mXpos[ n ] += mXInc[ n ]; +        mYpos[ n ] += mYInc[ n ]; + +        for( int y = 0; y < mBlockSize[ n ]; ++y ) +        { +            for( int x = 0; x < mBlockSize[ n ]; ++x ) +            { +                mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ]; +                mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ]; +                mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ]; +            }; +        }; +    }; + +    setDirty( 0, 0, mWidth, mHeight );  };  ////////////////////////////////////////////////////////////////////////////////  //  bool MediaPluginExample::init()  { -	LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" ); -	message.setValue( "name", "Example Plugin" ); -	sendMessage( message ); +    LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" ); +    message.setValue( "name", "Example Plugin" ); +    sendMessage( message ); -	return true; +    return true;  };  ////////////////////////////////////////////////////////////////////////////////  //  int init_media_plugin( LLPluginInstance::sendMessageFunction host_send_func, -						void* host_user_data, -						LLPluginInstance::sendMessageFunction *plugin_send_func, -						void **plugin_user_data ) +                        void* host_user_data, +                        LLPluginInstance::sendMessageFunction *plugin_send_func, +                        void **plugin_user_data )  { -	MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data ); -	*plugin_send_func = MediaPluginExample::staticReceiveMessage; -	*plugin_user_data = ( void* )self; +    MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data ); +    *plugin_send_func = MediaPluginExample::staticReceiveMessage; +    *plugin_user_data = ( void* )self; -	return 0; +    return 0;  } + diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index 05f1236606..3b1f679540 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -27,6 +27,7 @@ include_directories(      ${LLIMAGE_INCLUDE_DIRS}      ${LLRENDER_INCLUDE_DIRS}      ${LLWINDOW_INCLUDE_DIRS} +    ${LLQTWEBKIT_INCLUDE_DIR}  ) diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index bd1a44a930..d6f8ae3e16 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -341,7 +341,7 @@ private:  		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f);  		url << "%22%3E%3C/body%3E%3C/html%3E"; -		lldebugs << "data url is: " << url.str() << llendl; +		//lldebugs << "data url is: " << url.str() << llendl;  		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() );  //		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); @@ -407,6 +407,8 @@ private:  		{  			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");  			message.setValue("uri", event.getEventUri()); +			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); +			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));  			sendMessage(message);  			setStatus(STATUS_LOADING); @@ -569,6 +571,57 @@ private:  		return blockingPickFile();  	} +	std::string mAuthUsername; +	std::string mAuthPassword; +	bool mAuthOK; +	 +	//////////////////////////////////////////////////////////////////////////////// +	// virtual +	bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) +	{ +		mAuthOK = false; + +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request"); +		message.setValue("url", in_url); +		message.setValue("realm", in_realm); +		message.setValueBoolean("blocking_request", true); +				 +		// The "blocking_request" key in the message means this sendMessage call will block until a response is received. +		sendMessage(message); +		 +		if(mAuthOK) +		{ +			out_username = mAuthUsername; +			out_password = mAuthPassword; +		} +		 +		return mAuthOK; +	} +	 +	void authResponse(LLPluginMessage &message) +	{ +		mAuthOK = message.getValueBoolean("ok"); +		if(mAuthOK) +		{ +			mAuthUsername = message.getValue("username"); +			mAuthPassword = message.getValue("password"); +		} +	} +	 +	//////////////////////////////////////////////////////////////////////////////// +	// virtual +	void onLinkHovered(const EventType& event) +	{ +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) +		{ +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered"); +			message.setValue("link", event.getEventUri()); +			message.setValue("title", event.getStringValue()); +			message.setValue("text", event.getStringValue2()); +			sendMessage(message); +		} +	} +	  	LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)  	{  		int result = 0; @@ -1096,6 +1149,10 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)  			{  				onPickFileResponse(message_in.getValue("file"));  			} +			if(message_name == "auth_response") +			{ +				authResponse(message_in); +			}  			else  			{  //				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; @@ -1182,6 +1239,22 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)  				mUserAgent = message_in.getValue("user_agent");  				LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );  			} +			else if(message_name == "ignore_ssl_cert_errors") +			{ +#if LLQTWEBKIT_API_VERSION >= 3 +				LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") ); +#else +				llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl; +#endif +			} +			else if(message_name == "add_certificate_file_path") +			{ +#if LLQTWEBKIT_API_VERSION >= 6 +				LLQtWebKit::getInstance()->addCAFile( message_in.getValue("path") ); +#else +				llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl; +#endif +			}  			else if(message_name == "init_history")  			{  				// Initialize browser history diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c6b1266206..18e1dd6e59 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -54,6 +54,7 @@ include_directories(      ${LLCOMMON_INCLUDE_DIRS}      ${LLCONVEXDECOMP_INCLUDE_DIRS}      ${LLIMAGE_INCLUDE_DIRS} +    ${LLKDU_INCLUDE_DIRS}      ${LLINVENTORY_INCLUDE_DIRS}      ${LLMATH_INCLUDE_DIRS}      ${LLMESSAGE_INCLUDE_DIRS} @@ -231,6 +232,7 @@ set(viewer_SOURCE_FILES      llfloaterurlentry.cpp      llfloatervoiceeffect.cpp      llfloaterwater.cpp +    llfloaterwebcontent.cpp      llfloaterwhitelistentry.cpp      llfloaterwindlight.cpp      llfloaterwindowsize.cpp @@ -773,6 +775,7 @@ set(viewer_HEADER_FILES      llfloaterurlentry.h      llfloatervoiceeffect.h      llfloaterwater.h +    llfloaterwebcontent.h      llfloaterwhitelistentry.h      llfloaterwindlight.h      llfloaterwindowsize.h @@ -1481,11 +1484,6 @@ if (WINDOWS)      # In the meantime, if you have any ideas on how to easily maintain one list, either here or in viewer_manifest.py      # and have the build deps get tracked *please* tell me about it. -    if(LLKDU_LIBRARY) -      # Configure a var for llkdu which may not exist for all builds. -      set(LLKDU_DLL_SOURCE ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llkdu.dll) -    endif(LLKDU_LIBRARY) -      if(USE_GOOGLE_PERFTOOLS)        # Configure a var for tcmalloc location, if used.        # Note the need to specify multiple names explicitly. @@ -1502,7 +1500,6 @@ if (WINDOWS)        #${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libtcmalloc_minimal.dll => None ... Skipping libtcmalloc_minimal.dll        ${CMAKE_SOURCE_DIR}/../etc/message.xml        ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg -      ${LLKDU_DLL_SOURCE}        ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llcommon.dll        ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll        ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll @@ -1695,7 +1692,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}      ${LLAUDIO_LIBRARIES}      ${LLCHARACTER_LIBRARIES}      ${LLIMAGE_LIBRARIES} -    ${LLIMAGEJ2COJ_LIBRARIES}      ${LLINVENTORY_LIBRARIES}      ${LLMESSAGE_LIBRARIES}      ${LLPLUGIN_LIBRARIES} @@ -1733,6 +1729,17 @@ target_link_libraries(${VIEWER_BINARY_NAME}      ${TCMALLOC_LIBRARIES}      ) +if (USE_KDU) +    target_link_libraries(${VIEWER_BINARY_NAME} +        ${LLKDU_LIBRARIES} +        ${KDU_LIBRARY} +        ) +else (USE_KDU) +    target_link_libraries(${VIEWER_BINARY_NAME} +        ${LLIMAGEJ2COJ_LIBRARIES} +        ) +endif (USE_KDU) +      build_version(viewer)  set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH @@ -1880,29 +1887,31 @@ if (PACKAGE)      set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)    endif (LINUX) -  if(CMAKE_CFG_INTDIR STREQUAL ".") +  if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) +    if(CMAKE_CFG_INTDIR STREQUAL ".")        set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) -  else(CMAKE_CFG_INTDIR STREQUAL ".") +    else(CMAKE_CFG_INTDIR STREQUAL ".")        # set LLBUILD_CONFIG to be a shell variable evaluated at build time        # reflecting the configuration we are currently building.        set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) -  endif(CMAKE_CFG_INTDIR STREQUAL ".") -  add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" -    COMMAND "${PYTHON_EXECUTABLE}" -    ARGS -      "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" -      "${LLBUILD_CONFIG}" -      "${VIEWER_DIST_DIR}" -      "${VIEWER_EXE_GLOBS}" -      "${VIEWER_LIB_GLOB}" -      "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms" -      "${VIEWER_SYMBOL_FILE}" -    DEPENDS generate_breakpad_symbols.py -    VERBATIM -  ) -  add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}") -  add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") -  add_dependencies(package generate_breakpad_symbols) +    endif(CMAKE_CFG_INTDIR STREQUAL ".") +    add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" +      COMMAND "${PYTHON_EXECUTABLE}" +      ARGS +        "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" +        "${LLBUILD_CONFIG}" +        "${VIEWER_DIST_DIR}" +        "${VIEWER_EXE_GLOBS}" +        "${VIEWER_LIB_GLOB}" +        "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms" +        "${VIEWER_SYMBOL_FILE}" +        DEPENDS generate_breakpad_symbols.py +        VERBATIM) + +    add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}") +    add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") +    add_dependencies(package generate_breakpad_symbols) +  endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)  endif (PACKAGE)  if (LL_TESTS) diff --git a/indra/newview/app_settings/lindenlab.pem b/indra/newview/app_settings/lindenlab.pem new file mode 100644 index 0000000000..cf88d0e047 --- /dev/null +++ b/indra/newview/app_settings/lindenlab.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEUDCCA7mgAwIBAgIJAN4ppNGwj6yIMA0GCSqGSIb3DQEBBAUAMIHMMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j +aXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5jLjEpMCcGA1UECxMgTGluZGVu +IExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIExpbmRlbiBMYWIg +Q2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZIhvcNAQkBFhBjYUBsaW5kZW5s +YWIuY29tMB4XDTA1MDQyMTAyNDAzMVoXDTI1MDQxNjAyNDAzMVowgcwxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp +c2NvMRkwFwYDVQQKExBMaW5kZW4gTGFiLCBJbmMuMSkwJwYDVQQLEyBMaW5kZW4g +TGFiIENlcnRpZmljYXRlIEF1dGhvcml0eTEpMCcGA1UEAxMgTGluZGVuIExhYiBD +ZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgkqhkiG9w0BCQEWEGNhQGxpbmRlbmxh +Yi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKXh1MThucdTbMg9bYBO +rAm8yWns32YojB0PRfbq8rUjepEhTm3/13s0u399Uc202v4ejcGhkIDWJZd2NZMF +oKrhmRfxGHSKPCuFaXC3jh0lRECj7k8FoPkcmaPjSyodrDFDUUuv+C06oYJoI+rk +8REyal9NwgHvqCzOrZtiTXAdAgMBAAGjggE2MIIBMjAdBgNVHQ4EFgQUO1zK2e1f +1wO1fHAjq6DTJobKDrcwggEBBgNVHSMEgfkwgfaAFDtcytntX9cDtXxwI6ug0yaG +yg63oYHSpIHPMIHMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW +MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5j +LjEpMCcGA1UECxMgTGluZGVuIExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAn +BgNVBAMTIExpbmRlbiBMYWIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZI +hvcNAQkBFhBjYUBsaW5kZW5sYWIuY29tggkA3imk0bCPrIgwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQQFAAOBgQA/ZkgfvwHYqk1UIAKZS3kMCxz0HvYuEQtviwnu +xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9 +e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu +glmQ1A== +-----END CERTIFICATE----- + diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f295867559..a7e7e913c2 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -686,6 +686,39 @@        <key>Value</key>        <string>http://www.secondlife.com</string>      </map> +    <key>BrowserIgnoreSSLCertErrors</key> +    <map> +      <key>Comment</key> +      <string>FOR TESTING ONLY: Tell the built-in web browser to ignore SSL cert errors.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>BrowserUseDefaultCAFile</key> +    <map> +      <key>Comment</key> +      <string>Tell the built-in web browser to use the CA.pem file shipped with the client.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map> +    <key>BrowserCAFilePath</key> +    <map> +      <key>Comment</key> +      <string>Tell the built-in web browser the path to an alternative CA.pem file (only used if BrowserUseDefaultCAFile is false).</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string></string> +    </map>        <key>BlockAvatarAppearanceMessages</key>          <map>          <key>Comment</key> @@ -4807,6 +4840,17 @@        <key>Value</key>        <string>http://map.secondlife.com.s3.amazonaws.com/</string>      </map> +    <key>CurrentMapServerURL</key> +    <map> +      <key>Comment</key> +      <string>Current Session World map URL</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string></string> +    </map>      <key>MapShowEvents</key>      <map>        <key>Comment</key> @@ -6873,7 +6917,18 @@      <key>MediaBrowserWindowLimit</key>      <map>        <key>Comment</key> -      <string>Maximum number of media brower windows that can be open at once (0 for no limit)</string> +      <string>Maximum number of media brower windows that can be open at once in the media browser floater (0 for no limit)</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>S32</string> +      <key>Value</key> +      <integer>5</integer> +    </map> +    <key>WebContentWindowLimit</key> +    <map> +      <key>Comment</key> +      <string>Maximum number of web brower windows that can be open at once in the Web content floater (0 for no limit)</string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> @@ -10373,6 +10428,17 @@        <key>Value</key>        <real>500.0</real>      </map> +    <key>UpdaterMaximumBandwidth</key> +    <map> +      <key>Comment</key> +      <string>Maximum allowable downstream bandwidth for updater service (kilo bits per second)</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>500.0</real> +    </map>      <key>ToolTipDelay</key>      <map>        <key>Comment</key> @@ -11473,16 +11539,16 @@        <key>Value</key>        <integer>15</integer>      </map> -    <key>UpdaterServiceActive</key> +    <key>UpdaterServiceSetting</key>      <map>        <key>Comment</key> -      <string>Enable or disable the updater service.</string> +      <string>Configure updater service.</string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> -      <string>Boolean</string> +      <string>U32</string>        <key>Value</key> -      <integer>1</integer> +      <integer>3</integer>      </map>      <key>UpdaterServiceCheckPeriod</key>      <map> @@ -12761,5 +12827,16 @@        <key>Value</key>        <string>name</string>      </map> +    <key>ReleaseNotesURL</key> +    <map> +      <key>Comment</key> +      <string>Release notes URL template</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string>http://secondlife.com/app/releasenotes/?channel=[CHANNEL]&version=[VERSION]</string> +    </map>  </map>  </llsd> diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index c49a878648..2825c32d79 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2697,6 +2697,9 @@ void LLAgentCamera::lookAtLastChat()  		new_camera_pos -= delta_pos * 0.4f;  		new_camera_pos += left * 0.3f;  		new_camera_pos += up * 0.2f; + +		setFocusOnAvatar(FALSE, FALSE); +  		if (chatter_av->mHeadp)  		{  			setFocusGlobal(gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), gAgent.getLastChatter()); @@ -2707,7 +2710,6 @@ void LLAgentCamera::lookAtLastChat()  			setFocusGlobal(chatter->getPositionGlobal(), gAgent.getLastChatter());  			mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();  		} -		setFocusOnAvatar(FALSE, TRUE);  	}  	else  	{ @@ -2727,9 +2729,10 @@ void LLAgentCamera::lookAtLastChat()  		new_camera_pos += left * 0.3f;  		new_camera_pos += up * 0.2f; +		setFocusOnAvatar(FALSE, FALSE); +  		setFocusGlobal(chatter->getPositionGlobal(), gAgent.getLastChatter());  		mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal(); -		setFocusOnAvatar(FALSE, TRUE);  	}  } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 55ecc9bd20..0093279859 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -83,6 +83,8 @@  #include "llfeaturemanager.h"  #include "llurlmatch.h"  #include "lltextutil.h" +#include "lllogininstance.h" +#include "llprogressview.h"  #include "llweb.h"  #include "llsecondlifeurls.h" @@ -603,10 +605,14 @@ LLAppViewer::LLAppViewer() :  	setupErrorHandling();  	sInstance = this;  	gLoggedInTime.stop(); +	 +	LLLoginInstance::instance().setUpdaterService(mUpdater.get());  }  LLAppViewer::~LLAppViewer()  { +	LLLoginInstance::instance().setUpdaterService(0); +	  	destroyMainloopTimeout();  	// If we got to this destructor somehow, the app didn't hang. @@ -2463,26 +2469,120 @@ bool LLAppViewer::initConfiguration()  }  namespace { -	// *TODO - decide if there's a better place for this function. +    // *TODO - decide if there's a better place for these functions.  	// do we need a file llupdaterui.cpp or something? -brad + +	void apply_update_callback(LLSD const & notification, LLSD const & response) +	{ +		lldebugs << "LLUpdate user response: " << response << llendl; +		if(response["OK_okcancelbuttons"].asBoolean()) +		{ +			llinfos << "LLUpdate restarting viewer" << llendl; +			static const bool install_if_ready = true; +			// *HACK - this lets us launch the installer immediately for now +			LLUpdaterService().startChecking(install_if_ready); +		} +	} +	 +	void apply_update_ok_callback(LLSD const & notification, LLSD const & response) +	{ +		llinfos << "LLUpdate restarting viewer" << llendl; +		static const bool install_if_ready = true; +		// *HACK - this lets us launch the installer immediately for now +		LLUpdaterService().startChecking(install_if_ready); +	} +	 +	void on_update_downloaded(LLSD const & data) +	{ +		std::string notification_name; +		void (*apply_callback)(LLSD const &, LLSD const &) = NULL; + +		if(data["required"].asBoolean()) +		{ +			apply_callback = &apply_update_ok_callback; +			if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT) +			{ +				// The user never saw the progress bar. +				notification_name = "RequiredUpdateDownloadedVerboseDialog"; +			} +			else +			{ +				notification_name = "RequiredUpdateDownloadedDialog"; +			} +		} +		else +		{ +			apply_callback = &apply_update_callback; +			if(LLStartUp::getStartupState() < STATE_STARTED) +			{ +				// CHOP-262 we need to use a different notification +				// method prior to login. +				notification_name = "DownloadBackgroundDialog"; +			} +			else +			{ +				notification_name = "DownloadBackgroundTip"; +			} +		} + +		LLSD substitutions; +		substitutions["VERSION"] = data["version"]; + +		// truncate version at the rightmost '.'  +		std::string version_short(data["version"]); +		size_t short_length = version_short.rfind('.'); +		if (short_length != std::string::npos) +		{ +			version_short.resize(short_length); +		} + +		LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]"); +		relnotes_url.setArg("[VERSION_SHORT]", version_short); + +		// *TODO thread the update service's response through to this point +		std::string const & channel = LLVersionInfo::getChannel(); +		boost::shared_ptr<char> channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free); + +		relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get()); +		relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL")); +		substitutions["RELEASE_NOTES_FULL_URL"] = relnotes_url.getString(); + +		LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback); +	} + +	void install_error_callback(LLSD const & notification, LLSD const & response) +	{ +		LLAppViewer::instance()->forceQuit(); +	} +	  	bool notify_update(LLSD const & evt)  	{ +		std::string notification_name;  		switch (evt["type"].asInteger())  		{  			case LLUpdaterService::DOWNLOAD_COMPLETE: -				LLNotificationsUtil::add("DownloadBackground"); +				on_update_downloaded(evt);  				break;  			case LLUpdaterService::INSTALL_ERROR: -				LLNotificationsUtil::add("FailedUpdateInstall"); +				if(evt["required"].asBoolean()) { +					LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), &install_error_callback); +				} else { +					LLNotificationsUtil::add("FailedUpdateInstall"); +				}  				break;  			default: -				llinfos << "unhandled update event " << evt << llendl;  				break;  		}  		// let others also handle this event by default  		return false;  	} +	 +	bool on_bandwidth_throttle(LLUpdaterService * updater, LLSD const & evt) +	{ +		updater->setBandwidthLimit(evt.asInteger() * (1024/8)); +		return false; // Let others receive this event. +	};  };  void LLAppViewer::initUpdater() @@ -2505,7 +2605,10 @@ void LLAppViewer::initUpdater()  						 channel,   						 version);   	mUpdater->setCheckPeriod(check_period); -	if(gSavedSettings.getBOOL("UpdaterServiceActive")) +	mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("UpdaterMaximumBandwidth") * (1024/8)); +	gSavedSettings.getControl("UpdaterMaximumBandwidth")->getSignal()-> +		connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2)); +	if(gSavedSettings.getU32("UpdaterServiceSetting"))  	{  		bool install_if_ready = true;  		mUpdater->startChecking(install_if_ready); @@ -2935,8 +3038,10 @@ void LLAppViewer::handleViewerCrash()  		pApp->removeMarkerFile(false);  	} +#if LL_SEND_CRASH_REPORTS  	// Call to pure virtual, handled by platform specific llappviewer instance.  	pApp->handleCrashReporting();  +#endif  	return;  } @@ -3147,7 +3252,7 @@ static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_q  void LLAppViewer::userQuit()  { -	if (gDisconnected) +	if (gDisconnected || gViewerWindow->getProgressView()->getVisible())  	{  		requestQuit();  	} @@ -4672,6 +4777,35 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)  		return;  	} +	LL_INFOS("eventhost") << "Found lleventhost at '" << dso_path << "'" << LL_ENDL; +#if ! defined(LL_WINDOWS) +	{ +		std::string outfile("/tmp/lleventhost.file.out"); +		std::string command("file '" + dso_path + "' > '" + outfile + "' 2>&1"); +		int rc = system(command.c_str()); +		if (rc != 0) +		{ +			LL_WARNS("eventhost") << command << " ==> " << rc << ':' << LL_ENDL; +		} +		else +		{ +			LL_INFOS("eventhost") << command << ':' << LL_ENDL; +		} +		{ +			std::ifstream reader(outfile.c_str()); +			std::string line; +			while (std::getline(reader, line)) +			{ +				size_t len = line.length(); +				if (len && line[len-1] == '\n') +					line.erase(len-1); +				LL_INFOS("eventhost") << line << LL_ENDL; +			} +		} +		remove(outfile.c_str()); +	} +#endif // LL_WINDOWS +  	apr_dso_handle_t * eventhost_dso_handle = NULL;  	apr_pool_t * eventhost_dso_memory_pool = NULL; @@ -4680,13 +4814,13 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)  	apr_status_t rv = apr_dso_load(&eventhost_dso_handle,  		dso_path.c_str(),  		eventhost_dso_memory_pool); -	ll_apr_assert_status(rv); +	llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));  	llassert_always(eventhost_dso_handle != NULL);  	int (*ll_plugin_start_func)(LLSD const &) = NULL;  	rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_start_func, eventhost_dso_handle, "ll_plugin_start"); -	ll_apr_assert_status(rv); +	llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));  	llassert_always(ll_plugin_start_func != NULL);  	LLSD args; diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp index d6a813d608..6e77d1e336 100644 --- a/indra/newview/llbrowsernotification.cpp +++ b/indra/newview/llbrowsernotification.cpp @@ -29,8 +29,9 @@  #include "llnotificationhandler.h"  #include "llnotifications.h" -#include "llfloaterreg.h"  #include "llmediactrl.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h"  using namespace LLNotificationsUI; @@ -39,10 +40,19 @@ bool LLBrowserNotification::processNotification(const LLSD& notify)  	LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());  	if (!notification) return false; -	LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(notification->getPayload()["media_id"].asUUID()); +	LLUUID media_id = notification->getPayload()["media_id"].asUUID(); +	LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(media_id);  	if (media_instance)  	{  		media_instance->showNotification(notification);  	} +	else if (LLViewerMediaFocus::instance().getControlsMediaID() == media_id) +	{ +		LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(media_id); +		if (impl) +		{ +			impl->showNotification(notification); +		} +	}  	return false;  } diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp index d35c9ed853..e5a9be0203 100644 --- a/indra/newview/llbuycurrencyhtml.cpp +++ b/indra/newview/llbuycurrencyhtml.cpp @@ -33,6 +33,7 @@  #include "llfloaterreg.h"  #include "llcommandhandler.h"  #include "llviewercontrol.h" +#include "llstatusbar.h"  // support for secondlife:///app/buycurrencyhtml/{ACTION}/{NEXT_ACTION}/{RETURN_CODE} SLapps  class LLBuyCurrencyHTMLHandler :  @@ -156,4 +157,7 @@ void LLBuyCurrencyHTML::closeDialog()  	{  		buy_currency_floater->closeFloater();  	}; +	 +	// Update L$ balance in the status bar in case L$ were purchased +	LLStatusBar::sendMoneyBalanceRequest();  } diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 6e778de2d8..c98bcbda45 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -586,7 +586,7 @@ void LLChatHistory::initFromParams(const LLChatHistory::Params& p)  	LLLayoutStack::Params layout_p;  	layout_p.rect = stack_rect;  	layout_p.follows.flags = FOLLOWS_ALL; -	layout_p.orientation = "vertical"; +	layout_p.orientation = LLLayoutStack::VERTICAL;  	layout_p.mouse_opaque = false;  	LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p, this); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 8ae3ccbae3..2873bc0059 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -272,7 +272,7 @@ LLSD LLFloaterAbout::getInfo()  	}  	// TODO: Implement media plugin version query -	info["QT_WEBKIT_VERSION"] = "4.6 (version number hard-coded)"; +	info["QT_WEBKIT_VERSION"] = "4.7.1 (version number hard-coded)";  	if (gPacketsIn > 0)  	{ diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp index 58c79fdf15..e21a8594bc 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -267,17 +267,23 @@ void LLFloaterBuyCurrencyUI::onClickBuy()  {  	mManager.buy(getString("buy_currency"));  	updateUI(); +	// Update L$ balance +	LLStatusBar::sendMoneyBalanceRequest();  }  void LLFloaterBuyCurrencyUI::onClickCancel()  {  	closeFloater(); +	// Update L$ balance +	LLStatusBar::sendMoneyBalanceRequest();  }  void LLFloaterBuyCurrencyUI::onClickErrorWeb()  {  	LLWeb::loadURLExternal(mManager.errorURI());  	closeFloater(); +	// Update L$ balance +	LLStatusBar::sendMoneyBalanceRequest();  }  // static diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp index bde620d965..013cf74c7b 100644 --- a/indra/newview/llfloaterbuycurrencyhtml.cpp +++ b/indra/newview/llfloaterbuycurrencyhtml.cpp @@ -82,7 +82,7 @@ void LLFloaterBuyCurrencyHTML::navigateToFinalURL()  	LLStringUtil::format( buy_currency_url, replace );  	// write final URL to debug console -	llinfos << "Buy currency HTML prased URL is " << buy_currency_url << llendl; +	llinfos << "Buy currency HTML parsed URL is " << buy_currency_url << llendl;  	// kick off the navigation  	mBrowser->navigateTo( buy_currency_url, "text/html" ); @@ -105,7 +105,7 @@ void LLFloaterBuyCurrencyHTML::handleMediaEvent( LLPluginClassMedia* self, EMedi  //  void LLFloaterBuyCurrencyHTML::onClose( bool app_quitting )  { -	// update L$ balanace one more time +	// Update L$ balance one more time  	LLStatusBar::sendMoneyBalanceRequest();  	destroy(); diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp index cec98e9992..a650886d89 100644 --- a/indra/newview/llfloaterhelpbrowser.cpp +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -132,9 +132,10 @@ void LLFloaterHelpBrowser::onClickOpenWebBrowser(void* user_data)  void LLFloaterHelpBrowser::openMedia(const std::string& media_url)  { -	mBrowser->setHomePageUrl(media_url); -	//mBrowser->navigateTo("data:text/html;charset=utf-8,I'd really love to be going to:<br><b>" + media_url + "</b>"); // tofu HACK for debugging =:) -	mBrowser->navigateTo(media_url); +	// explicitly make the media mime type for this floater since it will +	// only ever display one type of content (Web). +	mBrowser->setHomePageUrl(media_url, "text/html"); +	mBrowser->navigateTo(media_url, "text/html");  	setCurrentURL(media_url);  } diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp index d20092e344..7a670dd90c 100644 --- a/indra/newview/llfloatermediabrowser.cpp +++ b/indra/newview/llfloatermediabrowser.cpp @@ -306,17 +306,14 @@ void LLFloaterMediaBrowser::setCurrentURL(const std::string& url)  {  	mCurrentURL = url; -	// redirects will navigate momentarily to about:blank, don't add to history -	if (mCurrentURL != "about:blank") -	{ -		mAddressCombo->remove(mCurrentURL); -		mAddressCombo->add(mCurrentURL); -		mAddressCombo->selectByValue(mCurrentURL); +	mAddressCombo->remove(mCurrentURL); +	mAddressCombo->add(mCurrentURL); +	mAddressCombo->selectByValue(mCurrentURL); + +	// Serialize url history +	LLURLHistory::removeURL("browser", mCurrentURL); +	LLURLHistory::addURL("browser", mCurrentURL); -		// Serialize url history -		LLURLHistory::removeURL("browser", mCurrentURL); -		LLURLHistory::addURL("browser", mCurrentURL); -	}  	getChildView("back")->setEnabled(mBrowser->canNavigateBack());  	getChildView("forward")->setEnabled(mBrowser->canNavigateForward());  	getChildView("reload")->setEnabled(TRUE); @@ -334,8 +331,15 @@ void LLFloaterMediaBrowser::onClickRefresh(void* user_data)  {  	LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; -	self->mAddressCombo->remove(0); -	self->mBrowser->navigateTo(self->mCurrentURL); +	if( self->mBrowser->getMediaPlugin() &&  self->mBrowser->getMediaPlugin()->pluginSupportsMediaBrowser()) +	{ +		bool ignore_cache = true; +		self->mBrowser->getMediaPlugin()->browse_reload( ignore_cache ); +	} +	else +	{ +		self->mBrowser->navigateTo(self->mCurrentURL); +	}  }  //static  diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 332d0637bc..0f2924d8aa 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1,4241 +1,4324 @@ -/** - * @file llfloatermodelpreview.cpp - * @brief LLFloaterModelPreview class implementation - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" -#include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" -#include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" - -#include "llfloatermodelpreview.h" - -#include "llfilepicker.h" -#include "llimagebmp.h" -#include "llimagetga.h" -#include "llimagejpeg.h" -#include "llimagepng.h" - -#include "llagent.h" -#include "llbutton.h" -#include "llcombobox.h" -#include "lldatapacker.h" -#include "lldrawable.h" -#include "lldrawpoolavatar.h" -#include "llrender.h" -#include "llface.h" -#include "lleconomy.h" -#include "llfocusmgr.h" -#include "llfloaterperms.h" -#include "lliconctrl.h" -#include "llmatrix4a.h" -#include "llmenubutton.h" -#include "llmeshrepository.h" -#include "llsdutil_math.h" -#include "lltextbox.h" -#include "lltoolmgr.h" -#include "llui.h" -#include "llvector4a.h" -#include "llviewercamera.h" -#include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "pipeline.h" -#include "lluictrlfactory.h" -#include "llviewermenu.h" -#include "llviewermenufile.h" -#include "llviewerregion.h" -#include "llviewertexturelist.h" -#include "llstring.h" -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llradiogroup.h" -#include "llsliderctrl.h" -#include "llspinctrl.h" -#include "lltoggleablemenu.h" -#include "llvfile.h" -#include "llvfs.h" -#include "llcallbacklist.h" - -#include "glod/glod.h" - -//static -S32 LLFloaterModelPreview::sUploadAmount = 10; -LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; - -const S32 PREVIEW_BORDER_WIDTH = 2; -const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; -const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; -const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; -const S32 PREVIEW_TEXTURE_HEIGHT = 300; - -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); - - -std::string lod_name[NUM_LOD+1] = -{ -	"lowest", -	"low", -	"medium", -	"high", -	"I went off the end of the lod_name array.  Me so smart." -}; - -std::string lod_triangles_name[NUM_LOD+1] = -{ -	"lowest_triangles", -	"low_triangles", -	"medium_triangles", -	"high_triangles", -	"I went off the end of the lod_triangles_name array.  Me so smart." -}; - -std::string lod_vertices_name[NUM_LOD+1] = -{ -	"lowest_vertices", -	"low_vertices", -	"medium_vertices", -	"high_vertices", -	"I went off the end of the lod_vertices_name array.  Me so smart." -}; - -std::string lod_status_name[NUM_LOD+1] = -{ -	"lowest_status", -	"low_status", -	"medium_status", -	"high_status", -	"I went off the end of the lod_status_name array.  Me so smart." -}; - -std::string lod_icon_name[NUM_LOD+1] = -{ -	"status_icon_lowest", -	"status_icon_low", -	"status_icon_medium", -	"status_icon_high", -	"I went off the end of the lod_status_name array.  Me so smart." -}; - -std::string lod_status_image[NUM_LOD+1] = -{ -	"ModelImport_Status_Good", -	"ModelImport_Status_Warning", -	"ModelImport_Status_Error", -	"I went off the end of the lod_status_image array.  Me so smart." -}; - -std::string lod_label_name[NUM_LOD+1] = -{ -	"lowest_label", -	"low_label", -	"medium_label", -	"high_label", -	"I went off the end of the lod_label_name array.  Me so smart." -}; - - -bool validate_face(const LLVolumeFace& face) -{ -	for (U32 i = 0; i < face.mNumIndices; ++i) -	{ -		if (face.mIndices[i] >= face.mNumVertices) -		{ -			llwarns << "Face has invalid index." << llendl; -			return false; -		} -	} - -	return true; -} - -bool validate_model(const LLModel* mdl) -{ -	if (mdl->getNumVolumeFaces() == 0) -	{ -		llwarns << "Model has no faces!" << llendl; -		return false; -	} - -	for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) -	{ -		if (mdl->getVolumeFace(i).mNumVertices == 0) -		{ -			llwarns << "Face has no vertices." << llendl; -			return false; -		} - -		if (mdl->getVolumeFace(i).mNumIndices == 0) -		{ -			llwarns << "Face has no indices." << llendl; -			return false; -		} - -		if (!validate_face(mdl->getVolumeFace(i))) -		{ -			return false; -		} -	} - -	return true; -} - -BOOL stop_gloderror() -{ -	GLuint error = glodGetError(); - -	if (error != GLOD_NO_ERROR) -	{ -		llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; -		return TRUE; -	} - -	return FALSE; -} - - -LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) -	: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) -	{ -		mMP = mp; -		mLOD = lod; -	} - -void LLMeshFilePicker::notify(const std::string& filename) -{ -	mMP->loadModel(mFile, mLOD); -} - - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : -LLFloater(key) -{ -	sInstance = this; -	mLastMouseX = 0; -	mLastMouseY = 0; -	mGLName = 0; -	mStatusLock = new LLMutex(NULL); - -	mLODMode[LLModel::LOD_HIGH] = 0; -	for (U32 i = 0; i < LLModel::LOD_HIGH; i++) -	{ -		mLODMode[i] = 1; -	} -} - -//----------------------------------------------------------------------------- -// postBuild() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::postBuild() -{ -	if (!LLFloater::postBuild()) -	{ -		return FALSE; -	} - -	setViewOption("show_textures", true); - -	childSetAction("lod_browse", onBrowseLOD, this); - -	childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); -	childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); - -	childSetCommitCallback("lod_generate", onAutoFillCommit, this); - -	childSetCommitCallback("lod_mode", onLODParamCommit, this); -	childSetCommitCallback("lod_error_threshold", onLODParamCommit, this); -	childSetCommitCallback("lod_triangle_limit", onLODParamCommit, this); -	childSetCommitCallback("build_operator", onLODParamCommit, this); -	childSetCommitCallback("queue_mode", onLODParamCommit, this); -	childSetCommitCallback("border_mode", onLODParamCommit, this); -	childSetCommitCallback("share_tolerance", onLODParamCommit, this); - -	childSetTextArg("status", "[STATUS]", getString("status_idle")); - -	//childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); -	childSetAction("ok_btn", onUpload, this); -	childDisable("ok_btn"); - -	childSetAction("clear_materials", onClearMaterials, this); - -	childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - -	childSetCommitCallback("upload_skin", onUploadSkinCommit, this); -	childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - -	childSetCommitCallback("import_scale", onImportScaleCommit, this); - -	childSetCommitCallback("lod_file_or_limit", refresh, this); -	childSetCommitCallback("physics_load_radio", refresh, this); -	//childSetCommitCallback("physics_optimize", refresh, this); -	//childSetCommitCallback("physics_use_hull", refresh, this); - -	childDisable("upload_skin"); -	childDisable("upload_joints"); -	childDisable("ok_btn"); - -	mViewOptionMenuButton = getChild<LLMenuButton>("options_gear_btn"); - -	mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2)); -	mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2)); -	mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2)); - - - -	mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -	mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT); - -	initDecompControls(); - -	LLView* preview_panel = getChild<LLView>("preview_panel"); - -	mPreviewRect = preview_panel->getRect(); - -	mModelPreview = new LLModelPreview(512, 512, this); -	mModelPreview->setPreviewTarget(16.f); - -	//set callbacks for left click on line editor rows -	for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) -	{ -		LLTextBox* text = getChild<LLTextBox>(lod_label_name[i]); -		if (text) -		{ -			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); -		} - -		text = getChild<LLTextBox>(lod_triangles_name[i]); -		if (text) -		{ -			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); -		} - -		text = getChild<LLTextBox>(lod_vertices_name[i]); -		if (text) -		{ -			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); -		} - -		text = getChild<LLTextBox>(lod_status_name[i]); -		if (text) -		{ -			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); -		} -	} - -	return TRUE; -} - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::~LLFloaterModelPreview() -{ -	sInstance = NULL; - -	if ( mModelPreview->containsRiggedAsset() ) -	{ -		gAgentAvatarp->resetJointPositions(); -	} - -	delete mModelPreview; - -	if (mGLName) -	{ -		LLImageGL::deleteTextures(1, &mGLName ); -	} - -	delete mStatusLock; -	mStatusLock = NULL; -} - -void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) -{ -	mViewOption[userdata.asString()] = !mViewOption[userdata.asString()]; -	mModelPreview->refresh(); -} - -bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata) -{ -	return mViewOption[userdata.asString()]; -} - -bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata) -{ -	return !mViewOptionDisabled[userdata.asString()]; -} - -void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled) -{ -	mViewOptionDisabled[option] = !enabled; -} - -void LLFloaterModelPreview::enableViewOption(const std::string& option) -{ -	setViewOptionEnabled(option, true); -} - -void LLFloaterModelPreview::disableViewOption(const std::string& option) -{ -	setViewOptionEnabled(option, false); -} - -void LLFloaterModelPreview::setViewOption(const std::string& option, bool value) -{ -	mViewOption[option] = value; -} - -void LLFloaterModelPreview::loadModel(S32 lod) -{ -	mModelPreview->mLoading = true; - -	(new LLMeshFilePicker(mModelPreview, lod))->getFile(); -} - -//static -void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) -{ -	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - -	if (!fp->mModelPreview) -	{ -		return; -	} - -	fp->mModelPreview->calcResourceCost(); -	fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) -{ -	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - -	if (!fp->mModelPreview) -	{ -		return; -	} - -	fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) -{ -	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - -	if (!fp->mModelPreview) -	{ -		return; -	} - -	fp->mModelPreview->refresh(); -	fp->mModelPreview->resetPreviewTarget(); -	fp->mModelPreview->clearBuffers(); -} - -//static -void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) -{ -	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - -	if (!fp->mModelPreview) -	{ -		return; -	} - -	S32 which_mode = 0; - -	LLComboBox* combo = (LLComboBox*) ctrl; - -	which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order - -	fp->mModelPreview->setPreviewLOD(which_mode); -} - -//static -void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) -{ -	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - -	fp->mModelPreview->generateNormals(); -} - -//static -void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) -{ -	LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; - -	fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) -{ -	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - -	fp->mModelPreview->genLODs(); -} - -//static -void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) -{ -	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; -	fp->mModelPreview->genLODs(fp->mModelPreview->mPreviewLOD); -	fp->mModelPreview->updateStatusMessages(); -	fp->mModelPreview->refresh(); -} - - -//----------------------------------------------------------------------------- -// draw() -//----------------------------------------------------------------------------- -void LLFloaterModelPreview::draw() -{ -	LLFloater::draw(); -	LLRect r = getRect(); - -	mModelPreview->update(); - -	if (!mModelPreview->mLoading) -	{ -		childSetTextArg("status", "[STATUS]", getString("status_idle")); -	} - -	childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); -	childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - -	if (!mCurRequest.empty()) -	{ -		LLMutexLock lock(mStatusLock); -		childSetTextArg("status", "[STATUS]", mStatusMessage); -	} - -	U32 resource_cost = mModelPreview->mResourceCost*10; - -	if (childGetValue("upload_textures").asBoolean()) -	{ -		resource_cost += mModelPreview->mTextureSet.size()*10; -	} - -	childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); - -	if (mModelPreview) -	{ -		gGL.color3f(1.f, 1.f, 1.f); - -		gGL.getTexUnit(0)->bind(mModelPreview); - - -		LLView* preview_panel = getChild<LLView>("preview_panel"); - -		LLRect rect = preview_panel->getRect(); -		if (rect != mPreviewRect) -		{ -			mModelPreview->refresh(); -			mPreviewRect = preview_panel->getRect(); -		} - -		gGL.begin( LLRender::QUADS ); -		{ -			gGL.texCoord2f(0.f, 1.f); -			gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); -			gGL.texCoord2f(0.f, 0.f); -			gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); -			gGL.texCoord2f(1.f, 0.f); -			gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); -			gGL.texCoord2f(1.f, 1.f); -			gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); -		} -		gGL.end(); - -		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -	} -} - -//----------------------------------------------------------------------------- -// handleMouseDown() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) -{ -	if (mPreviewRect.pointInRect(x, y)) -	{ -		bringToFront( x, y ); -		gFocusMgr.setMouseCapture(this); -		gViewerWindow->hideCursor(); -		mLastMouseX = x; -		mLastMouseY = y; -		return TRUE; -	} - -	return LLFloater::handleMouseDown(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleMouseUp() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) -{ -	gFocusMgr.setMouseCapture(FALSE); -	gViewerWindow->showCursor(); -	return LLFloater::handleMouseUp(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleHover() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleHover	(S32 x, S32 y, MASK mask) -{ -	MASK local_mask = mask & ~MASK_ALT; - -	if (mModelPreview && hasMouseCapture()) -	{ -		if (local_mask == MASK_PAN) -		{ -			// pan here -			mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); -		} -		else if (local_mask == MASK_ORBIT) -		{ -			F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; -			F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; - -			mModelPreview->rotate(yaw_radians, pitch_radians); -		} -		else -		{ - -			F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; -			F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; - -			mModelPreview->rotate(yaw_radians, 0.f); -			mModelPreview->zoom(zoom_amt); -		} - - -		mModelPreview->refresh(); - -		LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); -	} - -	if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) -	{ -		return LLFloater::handleHover(x, y, mask); -	} -	else if (local_mask == MASK_ORBIT) -	{ -		gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); -	} -	else if (local_mask == MASK_PAN) -	{ -		gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); -	} -	else -	{ -		gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); -	} - -	return TRUE; -} - -//----------------------------------------------------------------------------- -// handleScrollWheel() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) -{ -	if (mPreviewRect.pointInRect(x, y) && mModelPreview) -	{ -		mModelPreview->zoom((F32)clicks * -0.2f); -		mModelPreview->refresh(); -	} - -	return TRUE; -} - -//static -void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) -{ -	if (LLConvexDecomposition::getInstance() == NULL) -	{ -		llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; -		return; -	} - -	if (sInstance) -	{ -		LLCDParam* param = (LLCDParam*) data; -		std::string name(param->mName); -		sInstance->mDecompParams[name] = ctrl->getValue(); - -		if (name == "Simplify Method") -		{ -			 if (ctrl->getValue().asInteger() == 0) -			 { -				sInstance->childSetVisible("Retain%", true); -				sInstance->childSetVisible("Detail Scale", false); -			 } -			else -			{ -				sInstance->childSetVisible("Retain%", false); -				sInstance->childSetVisible("Detail Scale", true); -			} -		} -	} -} - -//static -void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) -{ -	LLCDStageData* stage = (LLCDStageData*) data; - -	if (sInstance) -	{ -		if (!sInstance->mCurRequest.empty()) -		{ -			llinfos << "Decomposition request still pending." << llendl; -			return; -		} - -		if (sInstance->mModelPreview) -		{ -			for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) -			{ -				LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; -				DecompRequest* request = new DecompRequest(stage->mName, mdl); -				sInstance->mCurRequest.insert(request); -				gMeshRepo.mDecompThread->submitRequest(request); -			} -		} -	} -} - -//static -void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata) -{ -	sInstance->loadModel(LLModel::LOD_PHYSICS); -} - -//static -void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) -{ -	S32 which_mode = 3; -	LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo"); -	if (iface) -	{ -		which_mode = iface->getFirstSelectedIndex(); -	} - -	sInstance->mModelPreview->setPhysicsFromLOD(which_mode); -} - -//static -void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) -{ -	if (sInstance) -	{ -		for (std::set<LLPointer<DecompRequest> >::iterator iter = sInstance->mCurRequest.begin(); -			iter != sInstance->mCurRequest.end(); ++iter) -		{ -		    DecompRequest* req = *iter; -		    req->mContinue = 0; -		} -	} -} - -void LLFloaterModelPreview::initDecompControls() -{ -	LLSD key; - -	childSetCommitCallback("cancel_btn", onPhysicsStageCancel, NULL); -	childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); -	childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); - -	static const LLCDStageData* stage = NULL; -	static S32 stage_count = 0; - -	if (!stage && LLConvexDecomposition::getInstance() != NULL) -	{ -		stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); -	} - -	static const LLCDParam* param = NULL; -	static S32 param_count = 0; -	if (!param && LLConvexDecomposition::getInstance() != NULL) -	{ -		param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); -	} - -	for (S32 j = stage_count-1; j >= 0; --j) -	{ -		LLButton* button = getChild<LLButton>(stage[j].mName); -		if (button) -		{ -			button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); -		} - -		gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; -		// protected against stub by stage_count being 0 for stub above -		LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - -		//llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; -		//llinfos << "------------------------------------" << llendl; - -		for (S32 i = 0; i < param_count; ++i) -		{ -			if (param[i].mStage != j) -			{ -				continue; -			} - -			std::string name(param[i].mName ? param[i].mName : ""); -			std::string description(param[i].mDescription ? param[i].mDescription : ""); - -			std::string type = "unknown"; - -			llinfos << name << " - " << description << llendl; - -			if (param[i].mType == LLCDParam::LLCD_FLOAT) -			{ -				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); -				//llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; - -				LLSliderCtrl* slider = getChild<LLSliderCtrl>(name); -				if (slider) -				{ -					slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat); -					slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat); -					slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat); -					slider->setValue(param[i].mDefault.mFloat); -					slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); -				} -			} -			else if (param[i].mType == LLCDParam::LLCD_INTEGER) -			{ -				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); -				//llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - -				LLSliderCtrl* slider = getChild<LLSliderCtrl>(name); -				if (slider) -				{ -					slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue); -					slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); -					slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); -					slider->setValue(param[i].mDefault.mIntOrEnumValue); -					slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); -				} -			} -			else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) -			{ -				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); -				//llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; - -				LLCheckBoxCtrl* check_box = getChild<LLCheckBoxCtrl>(name); -				if (check_box) -				{ -					check_box->setValue(param[i].mDefault.mBool); -					check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); -				} -			} -			else if (param[i].mType == LLCDParam::LLCD_ENUM) -			{ -				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); -				//llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - -				{ //plug into combo box - -					//llinfos << "Accepted values: " << llendl; -					LLComboBox* combo_box = getChild<LLComboBox>(name); -					for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) -					{ -						//llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue -						//	<< " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; - -						combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, -							LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); -					} -					combo_box->setValue(param[i].mDefault.mIntOrEnumValue); -					combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); -				} - -				//llinfos << "----" << llendl; -			} -			//llinfos << "-----------------------------" << llendl; -		} -	} - -	childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); -} - -//----------------------------------------------------------------------------- -// onMouseCaptureLost() -//----------------------------------------------------------------------------- -// static -void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) -{ -	gViewerWindow->showCursor(); -} - -//----------------------------------------------------------------------------- -// LLModelLoader -//----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) -{ -	mJointMap["mPelvis"] = "mPelvis"; -	mJointMap["mTorso"] = "mTorso"; -	mJointMap["mChest"] = "mChest"; -	mJointMap["mNeck"] = "mNeck"; -	mJointMap["mHead"] = "mHead"; -	mJointMap["mSkull"] = "mSkull"; -	mJointMap["mEyeRight"] = "mEyeRight"; -	mJointMap["mEyeLeft"] = "mEyeLeft"; -	mJointMap["mCollarLeft"] = "mCollarLeft"; -	mJointMap["mShoulderLeft"] = "mShoulderLeft"; -	mJointMap["mElbowLeft"] = "mElbowLeft"; -	mJointMap["mWristLeft"] = "mWristLeft"; -	mJointMap["mCollarRight"] = "mCollarRight"; -	mJointMap["mShoulderRight"] = "mShoulderRight"; -	mJointMap["mElbowRight"] = "mElbowRight"; -	mJointMap["mWristRight"] = "mWristRight"; -	mJointMap["mHipRight"] = "mHipRight"; -	mJointMap["mKneeRight"] = "mKneeRight"; -	mJointMap["mAnkleRight"] = "mAnkleRight"; -	mJointMap["mFootRight"] = "mFootRight"; -	mJointMap["mToeRight"] = "mToeRight"; -	mJointMap["mHipLeft"] = "mHipLeft"; -	mJointMap["mKneeLeft"] = "mKneeLeft"; -	mJointMap["mAnkleLeft"] = "mAnkleLeft"; -	mJointMap["mFootLeft"] = "mFootLeft"; -	mJointMap["mToeLeft"] = "mToeLeft"; - -	mJointMap["avatar_mPelvis"] = "mPelvis"; -	mJointMap["avatar_mTorso"] = "mTorso"; -	mJointMap["avatar_mChest"] = "mChest"; -	mJointMap["avatar_mNeck"] = "mNeck"; -	mJointMap["avatar_mHead"] = "mHead"; -	mJointMap["avatar_mSkull"] = "mSkull"; -	mJointMap["avatar_mEyeRight"] = "mEyeRight"; -	mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; -	mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; -	mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; -	mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; -	mJointMap["avatar_mWristLeft"] = "mWristLeft"; -	mJointMap["avatar_mCollarRight"] = "mCollarRight"; -	mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; -	mJointMap["avatar_mElbowRight"] = "mElbowRight"; -	mJointMap["avatar_mWristRight"] = "mWristRight"; -	mJointMap["avatar_mHipRight"] = "mHipRight"; -	mJointMap["avatar_mKneeRight"] = "mKneeRight"; -	mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; -	mJointMap["avatar_mFootRight"] = "mFootRight"; -	mJointMap["avatar_mToeRight"] = "mToeRight"; -	mJointMap["avatar_mHipLeft"] = "mHipLeft"; -	mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; -	mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; -	mJointMap["avatar_mFootLeft"] = "mFootLeft"; -	mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - -	mJointMap["hip"] = "mPelvis"; -	mJointMap["abdomen"] = "mTorso"; -	mJointMap["chest"] = "mChest"; -	mJointMap["neck"] = "mNeck"; -	mJointMap["head"] = "mHead"; -	mJointMap["figureHair"] = "mSkull"; -	mJointMap["lCollar"] = "mCollarLeft"; -	mJointMap["lShldr"] = "mShoulderLeft"; -	mJointMap["lForeArm"] = "mElbowLeft"; -	mJointMap["lHand"] = "mWristLeft"; -	mJointMap["rCollar"] = "mCollarRight"; -	mJointMap["rShldr"] = "mShoulderRight"; -	mJointMap["rForeArm"] = "mElbowRight"; -	mJointMap["rHand"] = "mWristRight"; -	mJointMap["rThigh"] = "mHipRight"; -	mJointMap["rShin"] = "mKneeRight"; -	mJointMap["rFoot"] = "mFootRight"; -	mJointMap["lThigh"] = "mHipLeft"; -	mJointMap["lShin"] = "mKneeLeft"; -	mJointMap["lFoot"] = "mFootLeft"; -} - -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) -{ -	LLVector4a box[] = -	{ -		LLVector4a(-1, 1,-1), -		LLVector4a(-1, 1, 1), -		LLVector4a(-1,-1,-1), -		LLVector4a(-1,-1, 1), -		LLVector4a( 1, 1,-1), -		LLVector4a( 1, 1, 1), -		LLVector4a( 1,-1,-1), -		LLVector4a( 1,-1, 1), -	}; - -	for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) -	{ -		const LLVolumeFace& face = model->getVolumeFace(j); - -		LLVector4a center; -		center.setAdd(face.mExtents[0], face.mExtents[1]); -		center.mul(0.5f); -		LLVector4a size; -		size.setSub(face.mExtents[1],face.mExtents[0]); -		size.mul(0.5f); - -		for (U32 i = 0; i < 8; i++) -		{ -			LLVector4a t; -			t.setMul(size, box[i]); -			t.add(center); - -			LLVector4a v; - -			mat.affineTransform(t, v); - -			if (first_transform) -			{ -				first_transform = FALSE; -				min = max = v; -			} -			else -			{ -				update_min_max(min, max, v); -			} -		} -	} -} - -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) -{ -	LLVector4a mina, maxa; -	LLMatrix4a mata; - -	mata.loadu(mat); -	mina.load3(min.mV); -	maxa.load3(max.mV); - -	stretch_extents(model, mata, mina, maxa, first_transform); - -	min.set(mina.getF32ptr()); -	max.set(maxa.getF32ptr()); -} - -void LLModelLoader::run() -{ -	DAE dae; -	domCOLLADA* dom = dae.open(mFilename); - -	if (dom) -	{ -		daeDatabase* db = dae.getDatabase(); - -		daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - -		daeDocument* doc = dae.getDoc(mFilename); -		if (!doc) -		{ -			llwarns << "can't find internal doc" << llendl; -			return; -		} - -		daeElement* root = doc->getDomRoot(); -		if (!root) -		{ -			llwarns << "document has no root" << llendl; -			return; -		} - -		//get unit scale -		mTransform.setIdentity(); - -		domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - -		if (unit) -		{ -			F32 meter = unit->getMeter(); -			mTransform.mMatrix[0][0] = meter; -			mTransform.mMatrix[1][1] = meter; -			mTransform.mMatrix[2][2] = meter; -		} - -		//get up axis rotation -		LLMatrix4 rotation; - -		domUpAxisType up = UPAXISTYPE_Y_UP;  // default is Y_UP -		domAsset::domUp_axis* up_axis = -		daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - -		if (up_axis) -		{ -			up = up_axis->getValue(); -		} - -		if (up == UPAXISTYPE_X_UP) -		{ -			rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); -		} -		else if (up == UPAXISTYPE_Y_UP) -		{ -			rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); -		} - -		rotation *= mTransform; -		mTransform = rotation; - - -		for (daeInt idx = 0; idx < count; ++idx) -		{ //build map of domEntities to LLModel -			domMesh* mesh = NULL; -			db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - -			if (mesh) -			{ -				LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh); - -				if (model.notNull() && validate_model(model)) -				{ -					mModelList.push_back(model); -					mModel[mesh] = model; -				} -			} -		} - -		count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); -		for (daeInt idx = 0; idx < count; ++idx) -		{ //add skinned meshes as instances -			domSkin* skin = NULL; -			db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - -			if (skin) -			{ -				domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement()); - -				if (geom) -				{ -					domMesh* mesh = geom->getMesh(); -					if (mesh) -					{ -						LLModel* model = mModel[mesh]; -						if (model) -						{ -							LLVector3 mesh_scale_vector; -							LLVector3 mesh_translation_vector; -							model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - -							LLMatrix4 normalized_transformation; -							normalized_transformation.setTranslation(mesh_translation_vector); - -							LLMatrix4 mesh_scale; -							mesh_scale.initScale(mesh_scale_vector); -							mesh_scale *= normalized_transformation; -							normalized_transformation = mesh_scale; - -							glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); -							inv_mat = inv_mat.inverse(); -							LLMatrix4 inverse_normalized_transformation(inv_mat.m); - -							domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - -							if (bind_mat) -							{ //get bind shape matrix -								domFloat4x4& dom_value = bind_mat->getValue(); - -								for (int i = 0; i < 4; i++) -								{ -									for(int j = 0; j < 4; j++) -									{ -										model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; -									} -								} - -								LLMatrix4 trans = normalized_transformation; -								trans *= model->mBindShapeMatrix; -								model->mBindShapeMatrix = trans; - -							} - - -							//The joint transfom map that we'll populate below -							std::map<std::string,LLMatrix4> jointTransforms; -							jointTransforms.clear(); - -							//Some collada setup for accessing the skeleton -							daeElement* pElement = 0; -							dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - -							//Try to get at the skeletal instance controller -							domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement ); -							bool missingSkeletonOrScene = false; - -							//If no skeleton, do a breadth-first search to get at specific joints -							if ( !pSkeleton ) -							{ -								daeElement* pScene = root->getDescendant("visual_scene"); -								if ( !pScene ) -								{ -									llwarns<<"No visual scene - unable to parse bone offsets "<<llendl; -									missingSkeletonOrScene = true; -								} -								else -								{ -									//Get the children at this level -									daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren(); -									S32 childCount = children.getCount(); - -									//Process any children that are joints -									//Not all children are joints, some code be ambient lights, cameras, geometry etc.. -									for (S32 i = 0; i < childCount; ++i) -									{ -										domNode* pNode = daeSafeCast<domNode>(children[i]); -										if ( isNodeAJoint( pNode ) ) -										{ -											processJointNode( pNode, jointTransforms ); -										} -									} -								} -							} -							else -							//Has Skeleton -							{ -								//Get the root node of the skeleton -								daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); -								if ( pSkeletonRootNode ) -								{ -									//Once we have the root node - start acccessing it's joint components -									const int jointCnt = mJointMap.size(); -									std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin(); - -									//Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. -									for ( int i=0; i<jointCnt; ++i, ++jointIt ) -									{ -										//Build a joint for the resolver to work with -										char str[64]={0}; -										sprintf(str,"./%s",(*jointIt).second.c_str() ); -										//llwarns<<"Joint "<< str <<llendl; - -										//Setup the resolver -                                        daeSIDResolver resolver( pSkeletonRootNode, str ); - -                                        //Look for the joint -                                        domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() ); -                                        if ( pJoint ) -                                        { -											//Pull out the translate id and store it in the jointTranslations map -											daeSIDResolver jointResolver( pJoint, "./translate" ); -											domTranslate* pTranslate = daeSafeCast<domTranslate>( jointResolver.getElement() ); - -											LLMatrix4 workingTransform; - -											//Translation via SID -											if ( pTranslate ) -											{ -												extractTranslation( pTranslate, workingTransform ); -											} -											else -											{ -												//Translation via child from element -												daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); -												if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) -												{ -													llwarns<< "The found element is not a translate node" <<llendl; -													missingSkeletonOrScene = true; -												} -												else -												{ -													extractTranslationViaElement( pTranslateElement, workingTransform ); -												} -											} - -											//Store the joint transform w/respect to it's name. -											jointTransforms[(*jointIt).second.c_str()] = workingTransform; -                                        } -									} - -									//If anything failed in regards to extracting the skeleton, joints or translation id, -									//mention it -									if ( missingSkeletonOrScene  ) -									{ -										llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl; -									} -								}//got skeleton? -							} - -							if ( !missingSkeletonOrScene ) -							{ -								//Set the joint translations on the avatar -								//The joints are reset in the dtor -								const int jointCnt = mJointMap.size(); -								std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin(); -								for ( int i=0; i<jointCnt; ++i, ++jointIt ) -								{ -									std::string lookingForJoint = (*jointIt).first.c_str(); -									if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) -									{ -										LLMatrix4 jointTransform = jointTransforms[lookingForJoint]; -										LLJoint* pJoint = gAgentAvatarp->getJoint( lookingForJoint ); -										if ( pJoint ) -										{ -											pJoint->storeCurrentXform( jointTransform.getTranslation() ); -										} -										else -										{ -											//Most likely an error in the asset. -											llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; -										} -										//Reposition the avatars pelvis (avPos+offset) -										//if ( lookingForJoint == "mPelvis" ) -										//{ -										//	const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); -										//	gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); -										//	gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); -										//} -									} -								} -							} //missingSkeletonOrScene - -							domSkin::domJoints* joints = skin->getJoints(); - -							domInputLocal_Array& joint_input = joints->getInput_array(); - -							for (size_t i = 0; i < joint_input.getCount(); ++i) -							{ -								domInputLocal* input = joint_input.get(i); -								xsNMTOKEN semantic = input->getSemantic(); - -								if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) -								{ //found joint source, fill model->mJointMap and model->mJointList -									daeElement* elem = input->getSource().getElement(); - -									domSource* source = daeSafeCast<domSource>(elem); -									if (source) -									{ - - -										domName_array* names_source = source->getName_array(); - -										if (names_source) -										{ -											domListOfNames &names = names_source->getValue(); - -											for (size_t j = 0; j < names.getCount(); ++j) -											{ -												std::string name(names.get(j)); -												if (mJointMap.find(name) != mJointMap.end()) -												{ -													name = mJointMap[name]; -												} -												model->mJointList.push_back(name); -												model->mJointMap[name] = j; -											} -										} -										else -										{ -											domIDREF_array* names_source = source->getIDREF_array(); -											if (names_source) -											{ -												xsIDREFS& names = names_source->getValue(); - -												for (size_t j = 0; j < names.getCount(); ++j) -												{ -													std::string name(names.get(j).getID()); -													if (mJointMap.find(name) != mJointMap.end()) -													{ -														name = mJointMap[name]; -													} -													model->mJointList.push_back(name); -													model->mJointMap[name] = j; -												} -											} -										} -									} -								} -								else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) -								{ //found inv_bind_matrix array, fill model->mInvBindMatrix -									domSource* source = daeSafeCast<domSource>(input->getSource().getElement()); -									if (source) -									{ -										domFloat_array* t = source->getFloat_array(); -										if (t) -										{ -											domListOfFloats& transform = t->getValue(); -											S32 count = transform.getCount()/16; - -											for (S32 k = 0; k < count; ++k) -											{ -												LLMatrix4 mat; - -												for (int i = 0; i < 4; i++) -												{ -													for(int j = 0; j < 4; j++) -													{ -														mat.mMatrix[i][j] = transform[k*16 + i + j*4]; -													} -												} - -												model->mInvBindMatrix.push_back(mat); -											} -										} -									} -								} -							} - -							//We need to construct the alternate bind matrix (which contains the new joint positions) -							//in the same order as they were stored in the joint buffer. The joints associated -							//with the skeleton are not stored in the same order as they are in the exported joint buffer. -							//This remaps the skeletal joints to be in the same order as the joints stored in the model. -							std::vector<std::string> :: const_iterator jointIt  = model->mJointList.begin(); -							const int jointCnt = model->mJointList.size(); -							for ( int i=0; i<jointCnt; ++i, ++jointIt ) -							{ -								std::string lookingForJoint = (*jointIt).c_str(); -								//Look for the joint xform that we extracted from the skeleton, using the jointIt as the key -								//and store it in the alternate bind matrix -								if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) -								{ -									LLMatrix4 jointTransform = jointTransforms[lookingForJoint]; -									LLMatrix4 newInverse = model->mInvBindMatrix[i]; -									newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); -									model->mAlternateBindMatrix.push_back( newInverse ); -								} -								else -								{ -									llwarns<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<llendl; -								} -							} - -							//grab raw position array - -							domVertices* verts = mesh->getVertices(); -							if (verts) -							{ -								domInputLocal_Array& inputs = verts->getInput_array(); -								for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) -								{ -									if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) -									{ -										domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement()); -										if (pos_source) -										{ -											domFloat_array* pos_array = pos_source->getFloat_array(); -											if (pos_array) -											{ -												domListOfFloats& pos = pos_array->getValue(); - -												for (size_t j = 0; j < pos.getCount(); j += 3) -												{ -													if (pos.getCount() <= j+2) -													{ -														llerrs << "WTF?" << llendl; -													} - -													LLVector3 v(pos[j], pos[j+1], pos[j+2]); - -													//transform from COLLADA space to volume space -													v = v * inverse_normalized_transformation; - -													model->mPosition.push_back(v); -												} -											} -										} -									} -								} -							} - -							//grab skin weights array -							domSkin::domVertex_weights* weights = skin->getVertex_weights(); -							if (weights) -							{ -								domInputLocalOffset_Array& inputs = weights->getInput_array(); -								domFloat_array* vertex_weights = NULL; -								for (size_t i = 0; i < inputs.getCount(); ++i) -								{ -									if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) -									{ -										domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement()); -										if (weight_source) -										{ -											vertex_weights = weight_source->getFloat_array(); -										} -									} -								} - -								if (vertex_weights) -								{ -									domListOfFloats& w = vertex_weights->getValue(); -									domListOfUInts& vcount = weights->getVcount()->getValue(); -									domListOfInts& v = weights->getV()->getValue(); - -									U32 c_idx = 0; -									for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) -									{ //for each vertex -										daeUInt count = vcount[vc_idx]; - -										//create list of weights that influence this vertex -										LLModel::weight_list weight_list; - -										for (daeUInt i = 0; i < count; ++i) -										{ //for each weight -											daeInt joint_idx = v[c_idx++]; -											daeInt weight_idx = v[c_idx++]; - -											if (joint_idx == -1) -											{ -												//ignore bindings to bind_shape_matrix -												continue; -											} - -											F32 weight_value = w[weight_idx]; - -											weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); -										} - -										//sort by joint weight -										std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - -										std::vector<LLModel::JointWeight> wght; - -										F32 total = 0.f; - -										for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) -										{ //take up to 4 most significant weights -											if (weight_list[i].mWeight > 0.f) -											{ -												wght.push_back( weight_list[i] ); -												total += weight_list[i].mWeight; -											} -										} - -										F32 scale = 1.f/total; -										if (scale != 1.f) -										{ //normalize weights -											for (U32 i = 0; i < wght.size(); ++i) -											{ -												wght[i].mWeight *= scale; -											} -										} - -										model->mSkinWeights[model->mPosition[vc_idx]] = wght; -									} - -									//add instance to scene for this model - -									LLMatrix4 transform; -									std::vector<LLImportMaterial> materials; -									materials.resize(model->getNumVolumeFaces()); -									mScene[transform].push_back(LLModelInstance(model, transform, materials)); -									stretch_extents(model, transform, mExtents[0], mExtents[1], mFirstTransform); -								} -							} -						} -					} -				} -			} -		} - -		daeElement* scene = root->getDescendant("visual_scene"); - -		if (!scene) -		{ -			llwarns << "document has no visual_scene" << llendl; -			setLoadState( ERROR_PARSING ); -			return; -		} - -		processElement(scene); - -		doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); -	} -} - -bool LLModelLoader::isNodeAJoint( domNode* pNode ) -{ -	if ( pNode->getName() == NULL) -	{ -		return false; -	} - -	if ( mJointMap.find( pNode->getName() )  != mJointMap.end() ) -	{ -		return true; -	} - -	return false; -} - -void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) -{ -	domFloat3 jointTrans = pTranslate->getValue(); -	LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); -	transform.setTranslation( singleJointTranslation ); -} - -void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) -{ -	domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement ); -	domFloat3 translateChild = pTranslateChild->getValue(); -	LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); -	transform.setTranslation( singleJointTranslation ); -} - -void LLModelLoader::processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms ) -{ -	if (pNode->getName() == NULL) -	{ -		llwarns << "nameless node, can't process" << llendl; -		return; -	} - -	//llwarns<<"ProcessJointNode# Node:" <<pNode->getName()<<llendl; - -	//1. handle the incoming node - extract out translation via SID or element - -	LLMatrix4 workingTransform; - -	//Pull out the translate id and store it in the jointTranslations map -	daeSIDResolver jointResolver( pNode, "./translate" ); -	domTranslate* pTranslate = daeSafeCast<domTranslate>( jointResolver.getElement() ); - -	//Translation via SID was successful -	if ( pTranslate ) -	{ -		extractTranslation( pTranslate, workingTransform ); -	} -	else -	{ -		//Translation via child from element -		daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); -		if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) -		{ -			llwarns<< "The found element is not a translate node" <<llendl; -		} -		else -		{ -			extractTranslationViaElement( pTranslateElement, workingTransform ); -		} -	} - -	//Store the working transform relative to the nodes name. -	jointTransforms[ pNode->getName() ] = workingTransform; - -	//2. handle the nodes children - -	//Gather and handle the incoming nodes children -	daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren(); -	S32 childOfChildCount = childOfChild.getCount(); - -	for (S32 i = 0; i < childOfChildCount; ++i) -	{ -		domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] ); -		if ( pChildNode ) -		{ -			processJointNode( pChildNode, jointTransforms ); -		} -	} -} - -daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) -{ -    daeElement* pChildOfElement = pElement->getChild( name.c_str() ); -	if ( pChildOfElement ) -	{ -		return pChildOfElement; -	} -	llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; -    return NULL; -} - -void LLModelLoader::processElement(daeElement* element) -{ -	LLMatrix4 saved_transform = mTransform; - -	domTranslate* translate = daeSafeCast<domTranslate>(element); -	if (translate) -	{ -		domFloat3 dom_value = translate->getValue(); - -		LLMatrix4 translation; -		translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - -		translation *= mTransform; -		mTransform = translation; -	} - -	domRotate* rotate = daeSafeCast<domRotate>(element); -	if (rotate) -	{ -		domFloat4 dom_value = rotate->getValue(); - -		LLMatrix4 rotation; -		rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - -		rotation *= mTransform; -		mTransform = rotation; -	} - -	domScale* scale = daeSafeCast<domScale>(element); -	if (scale) -	{ -		domFloat3 dom_value = scale->getValue(); - -		LLMatrix4 scaling; -		scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - -		scaling *= mTransform; -		mTransform = scaling; -	} - -	domMatrix* matrix = daeSafeCast<domMatrix>(element); -	if (matrix) -	{ -		domFloat4x4 dom_value = matrix->getValue(); - -		LLMatrix4 matrix_transform; - -		for (int i = 0; i < 4; i++) -		{ -			for(int j = 0; j < 4; j++) -			{ -				matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; -			} -		} - -		matrix_transform *= mTransform; -		mTransform = matrix_transform; -	} - -	domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element); -	if (instance_geo) -	{ -		domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement()); -		if (geo) -		{ -			domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID()))); -			if (mesh) -			{ -				LLModel* model = mModel[mesh]; -				if (model) -				{ -					LLMatrix4 transformation = mTransform; - -					std::vector<LLImportMaterial> materials = getMaterials(model, instance_geo); - -					// adjust the transformation to compensate for mesh normalization -					LLVector3 mesh_scale_vector; -					LLVector3 mesh_translation_vector; -					model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - -					LLMatrix4 mesh_translation; -					mesh_translation.setTranslation(mesh_translation_vector); -					mesh_translation *= transformation; -					transformation = mesh_translation; - -					LLMatrix4 mesh_scale; -					mesh_scale.initScale(mesh_scale_vector); -					mesh_scale *= transformation; -					transformation = mesh_scale; - -					mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); - -					stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); -				} -			} -		} -	} - -	domInstance_node* instance_node = daeSafeCast<domInstance_node>(element); -	if (instance_node) -	{ -		daeElement* instance = instance_node->getUrl().getElement(); -		if (instance) -		{ -			processElement(instance); -		} -	} - -	//process children -	daeTArray< daeSmartRef<daeElement> > children = element->getChildren(); -	for (S32 i = 0; i < children.getCount(); i++) -	{ -		processElement(children[i]); -	} - -	domNode* node = daeSafeCast<domNode>(element); -	if (node) -	{ //this element was a node, restore transform before processiing siblings -		mTransform = saved_transform; -	} -} - -std::vector<LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) -{ -	std::vector<LLImportMaterial> materials; -	for (int i = 0; i < model->mMaterialList.size(); i++) -	{ -		LLImportMaterial import_material; - -		domInstance_material* instance_mat = NULL; - -		domBind_material::domTechnique_common* technique = -		daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - -		if (technique) -		{ -			daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>(); -			for (int j = 0; j < inst_materials.getCount(); j++) -			{ -				std::string symbol(inst_materials[j]->getSymbol()); - -				if (symbol == model->mMaterialList[i]) // found the binding -				{ -					instance_mat = inst_materials[j]; -				} -			} -		} - -		if (instance_mat) -		{ -			domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement()); -			if (material) -			{ -				domInstance_effect* instance_effect = -				daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); -				if (instance_effect) -				{ -					domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement()); -					if (effect) -					{ -						domProfile_COMMON* profile = -						daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); -						if (profile) -						{ -							import_material = profileToMaterial(profile); -						} -					} -				} -			} -		} - -		materials.push_back(import_material); -	} - -	return materials; -} - -LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) -{ -	LLImportMaterial mat; -	mat.mFullbright = FALSE; - -	daeElement* diffuse = material->getDescendant("diffuse"); -	if (diffuse) -	{ -		domCommon_color_or_texture_type_complexType::domTexture* texture = -		daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture")); -		if (texture) -		{ -			domCommon_newparam_type_Array newparams = material->getNewparam_array(); -			for (S32 i = 0; i < newparams.getCount(); i++) -			{ -				domFx_surface_common* surface = newparams[i]->getSurface(); -				if (surface) -				{ -					domFx_surface_init_common* init = surface->getFx_surface_init_common(); -					if (init) -					{ -						domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - -						if (init_from.getCount() > i) -						{ -							domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement()); -							if (image) -							{ -								// we only support init_from now - embedded data will come later -								domImage::domInit_from* init = image->getInit_from(); -								if (init) -								{ -									std::string filename = cdom::uriToNativePath(init->getValue().str()); - -									mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); -									mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); - -									mat.mDiffuseMap->forceToSaveRawImage(); -									mat.mDiffuseMapFilename = filename; -									mat.mDiffuseMapLabel = getElementLabel(material); -								} -							} -						} -					} -				} -			} -		} - -		domCommon_color_or_texture_type_complexType::domColor* color = -		daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color")); -		if (color) -		{ -			domFx_color_common domfx_color = color->getValue(); -			LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); -			mat.mDiffuseColor = value; -		} -	} - -	daeElement* emission = material->getDescendant("emission"); -	if (emission) -	{ -		LLColor4 emission_color = getDaeColor(emission); -		if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) -		{ -			mat.mFullbright = TRUE; -		} -	} - -	return mat; -} - -// try to get a decent label for this element -std::string LLModelLoader::getElementLabel(daeElement *element) -{ -	// if we have a name attribute, use it -	std::string name = element->getAttribute("name"); -	if (name.length()) -	{ -		return name; -	} - -	// if we have an ID attribute, use it -	if (element->getID()) -	{ -		return std::string(element->getID()); -	} - -	// if we have a parent, use it -	daeElement* parent = element->getParent(); -	if (parent) -	{ -		// if parent has a name, use it -		std::string name = parent->getAttribute("name"); -		if (name.length()) -		{ -			return name; -		} - -		// if parent has an ID, use it -		if (parent->getID()) -		{ -			return std::string(parent->getID()); -		} -	} - -	// try to use our type -	daeString element_name = element->getElementName(); -	if (element_name) -	{ -		return std::string(element_name); -	} - -	// if all else fails, use "object" -	return std::string("object"); -} - -LLColor4 LLModelLoader::getDaeColor(daeElement* element) -{ -	LLColor4 value; -	domCommon_color_or_texture_type_complexType::domColor* color = -	daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color")); -	if (color) -	{ -		domFx_color_common domfx_color = color->getValue(); -		value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); -	} - -	return value; -} - -//----------------------------------------------------------------------------- -// LLModelPreview -//----------------------------------------------------------------------------- - -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) -{ -	mNeedsUpdate = TRUE; -	mCameraDistance = 0.f; -	mCameraYaw = 0.f; -	mCameraPitch = 0.f; -	mCameraZoom = 1.f; -	mTextureName = 0; -	mPreviewLOD = 0; -	mModelLoader = NULL; -	mMaxTriangleLimit = 0; -	mDirty = false; -	mGenLOD = false; -	mLoading = false; -	mGroup = 0; -	mBuildShareTolerance = 0.f; -	mBuildQueueMode = GLOD_QUEUE_GREEDY; -	mBuildBorderMode = GLOD_BORDER_UNLOCK; -	mBuildOperator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; - -	mFMP = fmp; - -	glodInit(); -} - -LLModelPreview::~LLModelPreview() -{ -	if (mModelLoader) -	{ -		delete mModelLoader; -		mModelLoader = NULL; -	} - -	//*HACK : *TODO : turn this back on when we understand why this crashes -	//glodShutdown(); -} - -U32 LLModelPreview::calcResourceCost() -{ -	assert_main_thread(); - -	rebuildUploadData(); - -	if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) -	{ -		mFMP->childEnable("ok_btn"); -	} - -	U32 cost = 0; -	std::set<LLModel*> accounted; -	U32 num_points = 0; -	U32 num_hulls = 0; - -	F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); - -	F32 streaming_cost = 0.f; -	for (U32 i = 0; i < mUploadData.size(); ++i) -	{ -		LLModelInstance& instance = mUploadData[i]; - -		if (accounted.find(instance.mModel) == accounted.end()) -		{ -			accounted.insert(instance.mModel); - -			LLModel::convex_hull_decomposition& decomp = -			instance.mLOD[LLModel::LOD_PHYSICS] ? -			instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : -			instance.mModel->mConvexHullDecomp; - -			LLSD ret = LLModel::writeModel( -										   "", -										   instance.mLOD[4], -										   instance.mLOD[3], -										   instance.mLOD[2], -										   instance.mLOD[1], -										   instance.mLOD[0], -										   decomp, -										   mFMP->childGetValue("upload_skin").asBoolean(), -										   mFMP->childGetValue("upload_joints").asBoolean(), -										   TRUE); -			cost += gMeshRepo.calcResourceCost(ret); - -			num_hulls += decomp.size(); -			for (U32 i = 0; i < decomp.size(); ++i) -			{ -				num_points += decomp[i].size(); -			} - -			//calculate streaming cost -			LLMatrix4 transformation = instance.mTransform; - -			LLVector3 position = LLVector3(0, 0, 0) * transformation; - -			LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; -			LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; -			LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; -			F32 x_length = x_transformed.normalize(); -			F32 y_length = y_transformed.normalize(); -			F32 z_length = z_transformed.normalize(); -			LLVector3 scale = LLVector3(x_length, y_length, z_length); - -			F32 radius = scale.length()*debug_scale; - -			streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); -		} -	} - -	//mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); -	//mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); -	mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); -	F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; -	mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); -	mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); -	mFMP->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); - -	updateStatusMessages(); - -	return cost; -} - -void LLModelPreview::rebuildUploadData() -{ -	assert_main_thread(); - -	mUploadData.clear(); -	mTextureSet.clear(); - -	//fill uploaddata instance vectors from scene data - -	std::string requested_name = mFMP->getChild<LLUICtrl>("description_form")->getValue().asString(); - - -	LLSpinCtrl* scale_spinner = mFMP->getChild<LLSpinCtrl>("import_scale"); - -	if (!scale_spinner) -	{ -		llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl; -	} - -	F32 scale = scale_spinner->getValue().asReal(); - -	LLMatrix4 scale_mat; -	scale_mat.initScale(LLVector3(scale, scale, scale)); - -	F32 max_scale = 0.f; - -	if ( mBaseScene.size() > 0 ) -	{ -		mFMP->childEnable("ok_btn"); -	} - -	for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) -	{ //for each transform in scene -		LLMatrix4 mat = iter->first; - -		// compute position -		LLVector3 position = LLVector3(0, 0, 0) * mat; - -		// compute scale -		LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; -		LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; -		LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; -		F32 x_length = x_transformed.normalize(); -		F32 y_length = y_transformed.normalize(); -		F32 z_length = z_transformed.normalize(); - -		max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); - -		mat *= scale_mat; - -		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) -		{ //for each instance with said transform applied -			LLModelInstance instance = *model_iter; - -			LLModel* base_model = instance.mModel; -			if (base_model) -			{ -				base_model->mRequestedLabel = requested_name; -			} - -			S32 idx = 0; -			for (idx = 0; idx < mBaseModel.size(); ++idx) -			{  //find reference instance for this model -				if (mBaseModel[idx] == base_model) -				{ -					break; -				} -			} - -			for (U32 i = 0; i < LLModel::NUM_LODS; i++) -			{ //fill LOD slots based on reference model index -				if (!mModel[i].empty()) -				{ -					instance.mLOD[i] = mModel[i][idx]; -				} -				else -				{ -					instance.mLOD[i] = NULL; -				} -			} - -			instance.mTransform = mat; -			mUploadData.push_back(instance); -		} -	} - -	F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; - -	scale_spinner->setMaxValue(max_import_scale); - -	if (max_import_scale < scale) -	{ -		scale_spinner->setValue(max_import_scale); -	} - -} - - -void LLModelPreview::clearModel(S32 lod) -{ -	if (lod < 0 || lod > LLModel::LOD_PHYSICS) -	{ -		return; -	} - -	mVertexBuffer[lod].clear(); -	mModel[lod].clear(); -	mScene[lod].clear(); -} - -void LLModelPreview::loadModel(std::string filename, S32 lod) -{ -	assert_main_thread(); - -	LLMutexLock lock(this); - -	if (mModelLoader) -	{ -		delete mModelLoader; -		mModelLoader = NULL; -	} - -	if (filename.empty()) -	{ -		if (mBaseModel.empty()) -		{ -			// this is the initial file picking. Close the whole floater -			// if we don't have a base model to show for high LOD. -			mFMP->closeFloater(false); -		} - -		mLoading = false; -		return; -	} - -	mLODFile[lod] = filename; - -	if (lod == LLModel::LOD_HIGH) -	{ -		clearGLODGroup(); -	} - -	mModelLoader = new LLModelLoader(filename, lod, this); - -	mModelLoader->start(); - -	mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); - -	setPreviewLOD(lod); - -	if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) -	{ -		mFMP->childDisable("ok_btn"); -	} - -	if (lod == mPreviewLOD) -	{ -		mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); -	} -	else if (lod == LLModel::LOD_PHYSICS) -	{ -		mFMP->childSetText("physics_file", mLODFile[lod]); -	} - -	mFMP->openFloater(); -} - -void LLModelPreview::setPhysicsFromLOD(S32 lod) -{ -	assert_main_thread(); - -	if (lod >= 0 && lod <= 3) -	{ -		mModel[LLModel::LOD_PHYSICS] = mModel[lod]; -		mScene[LLModel::LOD_PHYSICS] = mScene[lod]; -		mLODFile[LLModel::LOD_PHYSICS].clear(); -		mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); -		mVertexBuffer[LLModel::LOD_PHYSICS].clear(); -		rebuildUploadData(); -		refresh(); -		updateStatusMessages(); -	} -} - -void LLModelPreview::clearIncompatible(S32 lod) -{ -	for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) -	{ //clear out any entries that aren't compatible with this model -		if (i != lod) -		{ -			if (mModel[i].size() != mModel[lod].size()) -			{ -				mModel[i].clear(); -				mScene[i].clear(); -				mVertexBuffer[i].clear(); - -				if (i == LLModel::LOD_HIGH) -				{ -					mBaseModel = mModel[lod]; -					clearGLODGroup(); -					mBaseScene = mScene[lod]; -					mVertexBuffer[5].clear(); -				} -			} -		} -	} -} - -void LLModelPreview::clearGLODGroup() -{ -	if (mGroup) -	{ -		for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) -		{ -			glodDeleteObject(iter->second); -			stop_gloderror(); -		} -		mObject.clear(); - -		glodDeleteGroup(mGroup); -		stop_gloderror(); -		mGroup = 0; -	} -} - -void LLModelPreview::loadModelCallback(S32 lod) -{ -	assert_main_thread(); - -	LLMutexLock lock(this); -	if (!mModelLoader) -	{ -		return; -	} - -	mModel[lod] = mModelLoader->mModelList; -	mScene[lod] = mModelLoader->mScene; -	mVertexBuffer[lod].clear(); - -	if (lod == LLModel::LOD_PHYSICS) -	{ -		mPhysicsMesh.clear(); -	} - -	setPreviewLOD(lod); - - -	if (lod == LLModel::LOD_HIGH) -	{ //save a copy of the highest LOD for automatic LOD manipulation -		if (mBaseModel.empty()) -		{ //first time we've loaded a model, auto-gen LoD -			mGenLOD = true; -		} - -		mBaseModel = mModel[lod]; -		clearGLODGroup(); - -		mBaseScene = mScene[lod]; -		mVertexBuffer[5].clear(); -	} - -	clearIncompatible(lod); - -	mDirty = true; - -	if (lod == LLModel::LOD_HIGH) -	{ -		resetPreviewTarget(); -	} - -	mLoading = false; -	refresh(); -} - -void LLModelPreview::resetPreviewTarget() -{ -	mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; -	mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; -	setPreviewTarget(mPreviewScale.magVec()*2.f); -} - -void LLModelPreview::generateNormals() -{ -	assert_main_thread(); - -	S32 which_lod = mPreviewLOD; - - -	if (which_lod > 4 || which_lod < 0 || -		mModel[which_lod].empty()) -	{ -		return; -	} - -	F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); - -	angle_cutoff *= DEG_TO_RAD; - -	if (which_lod == 3 && !mBaseModel.empty()) -	{ -		for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) -		{ -			(*iter)->generateNormals(angle_cutoff); -		} - -		mVertexBuffer[5].clear(); -	} - -	for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) -	{ -		(*iter)->generateNormals(angle_cutoff); -	} - -	mVertexBuffer[which_lod].clear(); -	refresh(); - -} - -void LLModelPreview::consolidate() -{ -	std::map<LLImportMaterial, std::vector<LLModelInstance> > composite; - -	LLMatrix4 identity; - -	//bake out each node in current scene to composite -	for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) -	{ //for each transform in current scene -		LLMatrix4 mat = iter->first; -		glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); -		LLMatrix4 norm_mat(inv_trans.m); - -		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) -		{ //for each instance with that transform -			LLModelInstance& source_instance = *model_iter; -			LLModel* source = source_instance.mModel; - -			if (!validate_model(source)) -			{ -				llerrs << "Invalid model found!" << llendl; -			} - -			for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) -			{ //for each face in instance -				const LLVolumeFace& src_face = source->getVolumeFace(i); -				LLImportMaterial& source_material = source_instance.mMaterial[i]; - -				//get model in composite that is composite for this material -				LLModel* model = NULL; - -				if (composite.find(source_material) != composite.end()) -				{ -					model = composite[source_material].rbegin()->mModel; -					if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) -					{ -						model = NULL; -					} -				} - -				if (model == NULL) -				{  //no model found, make new model -					std::vector<LLImportMaterial> materials; -					materials.push_back(source_material); -					LLVolumeParams volume_params; -					volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); -					model = new LLModel(volume_params, 0.f); -					model->mLabel = source->mLabel; -					model->setNumVolumeFaces(0); -					composite[source_material].push_back(LLModelInstance(model, identity, materials)); -				} - -				model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); -			} -		} -	} - - -	//condense composite into as few LLModel instances as possible -	LLModelLoader::model_list new_model; -	std::vector<LLModelInstance> instance_list; - -	LLVolumeParams volume_params; -	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - -	std::vector<LLImportMaterial> empty_material; -	LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); -	cur_instance.mModel->setNumVolumeFaces(0); - -	BOOL first_transform = TRUE; - -	LLModelLoader::scene new_scene; -	LLVector3 min,max; - -	for (std::map<LLImportMaterial, std::vector<LLModelInstance> >::iterator iter = composite.begin(); -		 iter != composite.end(); -		 ++iter) -	{ -		std::map<LLImportMaterial, std::vector<LLModelInstance> >::iterator next_iter = iter; ++next_iter; - -		for (std::vector<LLModelInstance>::iterator instance_iter = iter->second.begin(); -			 instance_iter != iter->second.end(); -			 ++instance_iter) -		{ -			LLModel* source = instance_iter->mModel; - -			if (instance_iter->mMaterial.size() != 1) -			{ -				llerrs << "WTF?" << llendl; -			} - -			if (source->getNumVolumeFaces() != 1) -			{ -				llerrs << "WTF?" << llendl; -			} - -			if (source->mMaterialList.size() != 1) -			{ -				llerrs << "WTF?" << llendl; -			} - -			cur_instance.mModel->addFace(source->getVolumeFace(0)); -			cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); -			cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); - -			BOOL last_model = FALSE; - -			std::vector<LLModelInstance>::iterator next_instance = instance_iter; ++next_instance; - -			if (next_iter == composite.end() && -				next_instance == iter->second.end()) -			{ -				last_model = TRUE; -			} - -			if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) -			{ -				cur_instance.mModel->mLabel = source->mLabel; - -				cur_instance.mModel->optimizeVolumeFaces(); -				cur_instance.mModel->normalizeVolumeFaces(); - -				if (!validate_model(cur_instance.mModel)) -				{ -					llerrs << "Invalid model detected." << llendl; -				} - -				new_model.push_back(cur_instance.mModel); - -				LLMatrix4 transformation = LLMatrix4(); - -				// adjust the transformation to compensate for mesh normalization -				LLVector3 mesh_scale_vector; -				LLVector3 mesh_translation_vector; -				cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - -				LLMatrix4 mesh_translation; -				mesh_translation.setTranslation(mesh_translation_vector); -				mesh_translation *= transformation; -				transformation = mesh_translation; - -				LLMatrix4 mesh_scale; -				mesh_scale.initScale(mesh_scale_vector); -				mesh_scale *= transformation; -				transformation = mesh_scale; - -				cur_instance.mTransform = transformation; - -				new_scene[transformation].push_back(cur_instance); -				stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); - -				if (!last_model) -				{ -					cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); -					cur_instance.mModel->setNumVolumeFaces(0); -				} -			} -		} -	} - -	mScene[mPreviewLOD] = new_scene; -	mModel[mPreviewLOD] = new_model; -	mVertexBuffer[mPreviewLOD].clear(); - -	if (mPreviewLOD == LLModel::LOD_HIGH) -	{ -		mBaseScene = new_scene; -		mBaseModel = new_model; -		clearGLODGroup(); -		mVertexBuffer[5].clear(); -	} - -	mPreviewTarget = (min+max)*0.5f; -	mPreviewScale = (max-min)*0.5f; -	setPreviewTarget(mPreviewScale.magVec()*2.f); - -	clearIncompatible(mPreviewLOD); - -	mResourceCost = calcResourceCost(); -	refresh(); -} - -void LLModelPreview::clearMaterials() -{ -	for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) -	{ //for each transform in current scene -		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) -		{ //for each instance with that transform -			LLModelInstance& source_instance = *model_iter; -			LLModel* source = source_instance.mModel; - -			for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) -			{ //for each face in instance -				LLImportMaterial& source_material = source_instance.mMaterial[i]; - -				//clear material info -				source_material.mDiffuseColor = LLColor4(1,1,1,1); -				source_material.mDiffuseMap = NULL; -				source_material.mDiffuseMapFilename.clear(); -				source_material.mDiffuseMapLabel.clear(); -				source_material.mFullbright = false; -			} -		} -	} - -	mVertexBuffer[mPreviewLOD].clear(); - -	if (mPreviewLOD == LLModel::LOD_HIGH) -	{ -		mBaseScene = mScene[mPreviewLOD]; -		mBaseModel = mModel[mPreviewLOD]; -		clearGLODGroup(); -		mVertexBuffer[5].clear(); -	} - -	mResourceCost = calcResourceCost(); -	refresh(); -} - -bool LLModelPreview::containsRiggedAsset( void ) -{ -	//loop through the models and determine if any of them contained a rigged asset, and if so -	//return true. -	//This is used to cleanup the joint positions after a preview. -	for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) -	{ -		LLModel* pModel = *iter; -		if ( pModel->mAlternateBindMatrix.size() > 0 ) -		{ -			return true; -		} -	} -	return false; -} -void LLModelPreview::genLODs(S32 which_lod, U32 decimation) -{ -	if (mBaseModel.empty()) -	{ -		return; -	} - -	if (which_lod == LLModel::LOD_PHYSICS) -	{ //clear physics mesh map -		mPhysicsMesh.clear(); -	} - -	LLVertexBuffer::unbind(); - -	stop_gloderror(); -	static U32 cur_name = 1; - -	S32 limit = -1; - -	U32 triangle_count = 0; - -	for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) -	{ -		LLModel* mdl = *iter; -		for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) -		{ -			triangle_count += mdl->getVolumeFace(i).mNumIndices/3; -		} -	} - -	U32 base_triangle_count = triangle_count; - -	U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - -	U32 lod_mode = 0; - -	LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); -	if (iface) -	{ -		lod_mode = iface->getFirstSelectedIndex(); -	} - -	F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); - -	if (lod_mode == 0) -	{ -		lod_mode = GLOD_TRIANGLE_BUDGET; -		if (which_lod != -1) -		{ -			limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); -		} -	} -	else -	{ -		lod_mode = GLOD_ERROR_THRESHOLD; -	} - -	U32 build_operator = 0; - -	iface = mFMP->childGetSelectionInterface("build_operator"); -	if (iface) -	{ -		build_operator = iface->getFirstSelectedIndex(); -	} - -	if (build_operator == 0) -	{ -		build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; -	} -	else -	{ -		build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; -	} - -	U32 queue_mode=0; -	iface = mFMP->childGetSelectionInterface("queue_mode"); -	if (iface) -	{ -		queue_mode = iface->getFirstSelectedIndex(); -	} - -	if (queue_mode == 0) -	{ -		queue_mode = GLOD_QUEUE_GREEDY; -	} -	else if (queue_mode == 1) -	{ -		queue_mode = GLOD_QUEUE_LAZY; -	} -	else -	{ -		queue_mode = GLOD_QUEUE_INDEPENDENT; -	} - -	U32 border_mode = 0; - -	iface = mFMP->childGetSelectionInterface("border_mode"); -	if (iface) -	{ -		border_mode = iface->getFirstSelectedIndex(); -	} - -	if (border_mode == 0) -	{ -		border_mode = GLOD_BORDER_UNLOCK; -	} -	else -	{ -		border_mode = GLOD_BORDER_LOCK; -	} - -	bool object_dirty = false; -	if (border_mode != mBuildBorderMode) -	{ -		mBuildBorderMode = border_mode; -		object_dirty = true; -	} - -	if (queue_mode != mBuildQueueMode) -	{ -		mBuildQueueMode = queue_mode; -		object_dirty = true; -	} - -	if (build_operator != mBuildOperator) -	{ -		mBuildOperator = build_operator; -		object_dirty = true; -	} - -	F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); -	if (share_tolerance != mBuildShareTolerance) -	{ -		mBuildShareTolerance = share_tolerance; -		object_dirty = true; -	} - -	if (mGroup == 0) -	{ -		object_dirty = true; -		mGroup = cur_name++; -		glodNewGroup(mGroup); -	} - -	if (object_dirty) -	{ -		for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) -		{ //build GLOD objects for each model in base model list -			LLModel* mdl = *iter; - -			if (mObject[mdl] != 0) -			{ -				glodDeleteObject(mObject[mdl]); -			} - -			mObject[mdl] = cur_name++; - -			glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); -			stop_gloderror(); - -			if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) -			{ //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation -				mVertexBuffer[5].clear(); -			} - -			if (mVertexBuffer[5].empty()) -			{ -				genBuffers(5, false); -			} - -			U32 tri_count = 0; -			for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) -			{ -				mVertexBuffer[5][mdl][i]->setBuffer(type_mask); -				U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); -				if (num_indices > 2) -				{ -					glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); -				} -				tri_count += num_indices/3; -				stop_gloderror(); -			} - -			glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator); -			stop_gloderror(); - -			glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode); -			stop_gloderror(); - -			glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode); -			stop_gloderror(); - -			glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance); -			stop_gloderror(); - -			glodBuildObject(mObject[mdl]); -			stop_gloderror(); -		} -	} - - -	S32 start = LLModel::LOD_HIGH; -	S32 end = 0; - -	if (which_lod != -1) -	{ -		start = end = which_lod; -	} - -	mMaxTriangleLimit = base_triangle_count; - -	for (S32 lod = start; lod >= end; --lod) -	{ -		if (which_lod == -1) -		{ -			if (lod < start) -			{ -				triangle_count /= decimation; -			} -		} -		else -		{ -			triangle_count = limit; -		} - -		mModel[lod].clear(); -		mModel[lod].resize(mBaseModel.size()); -		mVertexBuffer[lod].clear(); - -		U32 actual_tris = 0; -		U32 actual_verts = 0; -		U32 submeshes = 0; - -		glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); -		stop_gloderror(); - -		glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); -		stop_gloderror(); - -		glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count); -		stop_gloderror(); - -		glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); -		stop_gloderror(); - -		glodAdaptGroup(mGroup); -		stop_gloderror(); - -		for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) -		{ -			LLModel* base = mBaseModel[mdl_idx]; - -			GLint patch_count = 0; -			glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); -			stop_gloderror(); - -			LLVolumeParams volume_params; -			volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); -			mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - -			GLint* sizes = new GLint[patch_count*2]; -			glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); -			stop_gloderror(); - -			GLint* names = new GLint[patch_count]; -			glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); -			stop_gloderror(); - -			mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - -			LLModel* target_model = mModel[lod][mdl_idx]; - -			for (GLint i = 0; i < patch_count; ++i) -			{ -				LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); - -				if (sizes[i*2+1] > 0 && sizes[i*2] > 0) -				{ -					buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); -					buff->setBuffer(type_mask); -					glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); -					stop_gloderror(); -				} -				else -				{ //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) -					buff->allocateBuffer(1, 3, true); -					memset(buff->getMappedData(), 0, buff->getSize()); -					memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); -				} - -				buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - -				LLStrider<LLVector3> pos; -				LLStrider<LLVector3> norm; -				LLStrider<LLVector2> tc; -				LLStrider<U16> index; - -				buff->getVertexStrider(pos); -				buff->getNormalStrider(norm); -				buff->getTexCoord0Strider(tc); -				buff->getIndexStrider(index); - -				target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); -				actual_tris += buff->getNumIndices()/3; -				actual_verts += buff->getNumVerts(); -				++submeshes; - -				if (!validate_face(target_model->getVolumeFace(names[i]))) -				{ -					llerrs << "Invalid face generated during LOD generation." << llendl; -				} -			} - -			//blind copy skin weights and just take closest skin weight to point on -			//decimated mesh for now (auto-generating LODs with skin weights is still a bit -			//of an open problem). -			target_model->mPosition = base->mPosition; -			target_model->mSkinWeights = base->mSkinWeights; -			target_model->mJointMap = base->mJointMap; -			target_model->mJointList = base->mJointList; -			target_model->mInvBindMatrix = base->mInvBindMatrix; -			target_model->mBindShapeMatrix = base->mBindShapeMatrix; -			target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; -			//copy material list -			target_model->mMaterialList = base->mMaterialList; - -			if (!validate_model(target_model)) -			{ -				llerrs << "Invalid model generated when creating LODs" << llendl; -			} - -			delete [] sizes; -			delete [] names; -		} - -		//rebuild scene based on mBaseScene -		mScene[lod].clear(); -		mScene[lod] = mBaseScene; - -		for (U32 i = 0; i < mBaseModel.size(); ++i) -		{ -			LLModel* mdl = mBaseModel[i]; -			LLModel* target = mModel[lod][i]; -			if (target) -			{ -				for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) -				{ -					for (U32 j = 0; j < iter->second.size(); ++j) -					{ -						if (iter->second[j].mModel == mdl) -						{ -							iter->second[j].mModel = target; -						} -					} -				} -			} -		} -	} - -	mResourceCost = calcResourceCost(); - -	/*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) -	 { //build physics scene -	 mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; -	 mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - -	 for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) -	 { -	 mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); -	 } -	 }*/ -} - -void LLModelPreview::updateStatusMessages() -{ -	assert_main_thread(); - -	//triangle/vertex/submesh count for each mesh asset for each lod -	std::vector<S32> tris[LLModel::NUM_LODS]; -	std::vector<S32> verts[LLModel::NUM_LODS]; -	std::vector<S32> submeshes[LLModel::NUM_LODS]; - -	//total triangle/vertex/submesh count for each lod -	S32 total_tris[LLModel::NUM_LODS]; -	S32 total_verts[LLModel::NUM_LODS]; -	S32 total_submeshes[LLModel::NUM_LODS]; - -	for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) -	{ -		//initialize total for this lod to 0 -		total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; - -		for (U32 i = 0; i < mModel[lod].size(); ++i) -		{ //for each model in the lod -			S32 cur_tris = 0; -			S32 cur_verts = 0; -			S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); - -			for (S32 j = 0; j < cur_submeshes; ++j) -			{ //for each submesh (face), add triangles and vertices to current total -				const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); -				cur_tris += face.mNumIndices/3; -				cur_verts += face.mNumVertices; -			} - -			//add this model to the lod total -			total_tris[lod] += cur_tris; -			total_verts[lod] += cur_verts; -			total_submeshes[lod] += cur_submeshes; - -			//store this model's counts to asset data -			tris[lod].push_back(cur_tris); -			verts[lod].push_back(cur_verts); -			submeshes[lod].push_back(cur_submeshes); -		} -	} - -	if (mMaxTriangleLimit == 0) -	{ -		mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; -	} - - -	mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); - -	std::string mesh_status_na = mFMP->getString("mesh_status_na"); - -	S32 upload_status[LLModel::LOD_HIGH+1]; - -	bool upload_ok = true; - -	for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) -	{ -		upload_status[lod] = 0; - -		std::string message = "mesh_status_good"; - -		if (total_tris[lod] > 0) -		{ -			mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); -			mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); -		} -		else -		{ -			if (lod == LLModel::LOD_HIGH) -			{ -				upload_status[lod] = 2; -				message = "mesh_status_missing_lod"; -			} -			else -			{ -				for (S32 i = lod-1; i >= 0; --i) -				{ -					if (total_tris[i] > 0) -					{ -						upload_status[lod] = 2; -						message = "mesh_status_missing_lod"; -					} -				} -			} - -			mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); -			mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); -		} - -		const U32 lod_high = LLModel::LOD_HIGH; - -		if (lod != lod_high) -		{ -			if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) -			{ //number of submeshes is different -				message = "mesh_status_submesh_mismatch"; -				upload_status[lod] = 2; -			} -			else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) -			{ //number of meshes is different -				message = "mesh_status_mesh_mismatch"; -				upload_status[lod] = 2; -			} -			else if (!verts[lod].empty()) -			{ -				for (U32 i = 0; i < verts[lod].size(); ++i) -				{ -					S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; - -					if (max_verts > 0) -					{ -						if (verts[lod][i] > max_verts) -						{ //too many vertices in this lod -							message = "mesh_status_too_many_vertices"; -							upload_status[lod] = 2; -						} -					} -				} -			} -		} - -		LLIconCtrl* icon = mFMP->getChild<LLIconCtrl>(lod_icon_name[lod]); -		LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); -		icon->setVisible(true); -		icon->setImage(img); - -		if (upload_status[lod] >= 2) -		{ -			upload_ok = false; -		} - -		if (lod == mPreviewLOD) -		{ -			mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); -			icon = mFMP->getChild<LLIconCtrl>("lod_status_message_icon"); -			icon->setImage(img); -		} -	} - -	bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; - -	if ( upload_ok && !errorStateFromLoader ) -	{ -		mFMP->childEnable("ok_btn"); -	} -	else -	{ -		mFMP->childDisable("ok_btn"); -	} - -	//add up physics triangles etc -	S32 start = 0; -	S32 end = mModel[LLModel::LOD_PHYSICS].size(); - -	S32 phys_tris = 0; -	S32 phys_hulls = 0; -	S32 phys_points = 0; - -	for (S32 i = start; i < end; ++i) -	{ //add up hulls and points and triangles for selected mesh(es) -		LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; -		S32 cur_submeshes = model->getNumVolumeFaces(); - -		LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; - -		if (!decomp.empty()) -		{ -			phys_hulls += decomp.size(); -			for (U32 i = 0; i < decomp.size(); ++i) -			{ -				phys_points += decomp[i].size(); -			} -		} -		else -		{ //choose physics shape OR decomposition, can't use both -			for (S32 j = 0; j < cur_submeshes; ++j) -			{ //for each submesh (face), add triangles and vertices to current total -				const LLVolumeFace& face = model->getVolumeFace(j); -				phys_tris += face.mNumIndices/3; -			} -		} -	} - -	if (phys_tris > 0) -	{ -		mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); -	} -	else -	{ -		mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); -	} - -	if (phys_hulls > 0) -	{ -		mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); -		mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); -	} -	else -	{ -		mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); -		mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); -	} - -	LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; -	if (fmp) -	{ -		if (phys_tris > 0 || phys_hulls > 0) -		{ -			if (!fmp->isViewOptionEnabled("show_physics")) -			{ -				fmp->enableViewOption("show_physics"); -				fmp->setViewOption("show_physics", true); -			} -		} -		else -		{ -			fmp->disableViewOption("show_physics"); -			fmp->setViewOption("show_physics", false); -		} - -		//bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); - -		//fmp->childSetEnabled("physics_optimize", !use_hull); - -		bool enable = phys_tris > 0 || phys_hulls > 0; -		//enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); - -		//enable/disable "analysis" UI -		LLPanel* panel = fmp->getChild<LLPanel>("physics analysis"); -		LLView* child = panel->getFirstChild(); -		while (child) -		{ -			child->setEnabled(enable); -			child = panel->findNextSibling(child); -		} - -		enable = phys_hulls > 0; -		//enable/disable "simplification" UI -		panel = fmp->getChild<LLPanel>("physics simplification"); -		child = panel->getFirstChild(); -		while (child) -		{ -			child->setEnabled(enable); -			child = panel->findNextSibling(child); -		} -	} - -	const char* lod_controls[] = -	{ -		"lod_mode", -		"lod_triangle_limit", -		"lod_error_tolerance", -		"build_operator_text", -		"queue_mode_text", -		"border_mode_text", -		"share_tolerance_text", -		"build_operator", -		"queue_mode", -		"border_mode", -		"share_tolerance" -	}; -	const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); - -	const char* file_controls[] = -	{ -		"lod_browse", -		"lod_file" -	}; -	const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); - -	if (fmp) -	{ -		//enable/disable controls based on radio groups -		if (mFMP->childGetValue("lod_from_file").asBoolean()) -		{  -			fmp->mLODMode[mPreviewLOD] = 0; -			for (U32 i = 0; i < num_file_controls; ++i) -			{ -				mFMP->childEnable(file_controls[i]); -			} - -			for (U32 i = 0; i < num_lod_controls; ++i) -			{ -				mFMP->childDisable(lod_controls[i]); -			} -		} -		else if (mFMP->childGetValue("lod_none").asBoolean()) -		{ -			fmp->mLODMode[mPreviewLOD] = 2; -			for (U32 i = 0; i < num_file_controls; ++i) -			{ -				mFMP->childDisable(file_controls[i]); -			} - -			for (U32 i = 0; i < num_lod_controls; ++i) -			{ -				mFMP->childDisable(lod_controls[i]); -			} - -			if (!mModel[mPreviewLOD].empty()) -			{ -				mModel[mPreviewLOD].clear(); -				mScene[mPreviewLOD].clear(); -				mVertexBuffer[mPreviewLOD].clear(); - -				//this can cause phasing issues with the UI, so reenter this function and return -				updateStatusMessages(); -				return; -			} -		} -		else -		{	// auto generate, also the default case for wizard which has no radio selection -			fmp->mLODMode[mPreviewLOD] = 1; - -			for (U32 i = 0; i < num_file_controls; ++i) -			{ -				mFMP->childDisable(file_controls[i]); -			} - -			for (U32 i = 0; i < num_lod_controls; ++i) -			{ -				mFMP->childEnable(lod_controls[i]); -			} - -			//if (threshold) -			{	 -				U32 lod_mode = 0; -				LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); -				if (iface) -				{ -					lod_mode = iface->getFirstSelectedIndex(); -				} - -				LLSpinCtrl* threshold = mFMP->getChild<LLSpinCtrl>("lod_error_threshold"); -				LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit"); - -				limit->setMaxValue(mMaxTriangleLimit); -				limit->setValue(total_tris[mPreviewLOD]); - -				if (lod_mode == 0) -				{ -					limit->setVisible(true); -					threshold->setVisible(false); - -					limit->setMaxValue(mMaxTriangleLimit); -				} -				else -				{ -					limit->setVisible(false); -					threshold->setVisible(true); -				} -			} -		} -	} - -	if (mFMP->childGetValue("physics_load_from_file").asBoolean()) -	{ -		mFMP->childDisable("physics_lod_combo"); -		mFMP->childEnable("physics_file"); -		mFMP->childEnable("physics_browse"); -	} -	else -	{ -		mFMP->childEnable("physics_lod_combo"); -		mFMP->childDisable("physics_file"); -		mFMP->childDisable("physics_browse"); -	} -} - -void LLModelPreview::setPreviewTarget(F32 distance) -{ -	mCameraDistance = distance; -	mCameraZoom = 1.f; -	mCameraPitch = 0.f; -	mCameraYaw = 0.f; -	mCameraOffset.clearVec(); -} - -void LLModelPreview::clearBuffers() -{ -	for (U32 i = 0; i < 6; i++) -	{ -		mVertexBuffer[i].clear(); -	} -} - -void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) -{ -	U32 tri_count = 0; -	U32 vertex_count = 0; -	U32 mesh_count = 0; - -	LLModelLoader::model_list* model = NULL; - -	if (lod < 0 || lod > 4) -	{ -		model = &mBaseModel; -		lod = 5; -	} -	else -	{ -		model = &(mModel[lod]); -	} - -	if (!mVertexBuffer[lod].empty()) -	{ -		mVertexBuffer[lod].clear(); -	} - -	mVertexBuffer[lod].clear(); - -	LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - -	for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) -	{ -		LLModel* mdl = *iter; -		if (!mdl) -		{ -			continue; -		} - -		LLModel* base_mdl = *base_iter; -		base_iter++; - -		for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) -		{ -			const LLVolumeFace &vf = mdl->getVolumeFace(i); -			U32 num_vertices = vf.mNumVertices; -			U32 num_indices = vf.mNumIndices; - -			if (!num_vertices || ! num_indices) -			{ -				continue; -			} - -			LLVertexBuffer* vb = NULL; - -			bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); - -			U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - -			if (skinned) -			{ -				mask |= LLVertexBuffer::MAP_WEIGHT4; -			} - -			vb = new LLVertexBuffer(mask, 0); - -			vb->allocateBuffer(num_vertices, num_indices, TRUE); - -			LLStrider<LLVector3> vertex_strider; -			LLStrider<LLVector3> normal_strider; -			LLStrider<LLVector2> tc_strider; -			LLStrider<U16> index_strider; -			LLStrider<LLVector4> weights_strider; - -			vb->getVertexStrider(vertex_strider); -			vb->getNormalStrider(normal_strider); -			vb->getTexCoord0Strider(tc_strider); -			vb->getIndexStrider(index_strider); - -			if (skinned) -			{ -				vb->getWeight4Strider(weights_strider); -			} - -			LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); -			LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); -			LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - -			if (skinned) -			{ -				for (U32 i = 0; i < num_vertices; i++) -				{ -					//find closest weight to vf.mVertices[i].mPosition -					LLVector3 pos(vf.mPositions[i].getF32ptr()); - -					const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - -					LLVector4 w(0,0,0,0); -					if (weight_list.size() > 4) -					{ -						llerrs << "WTF?" << llendl; -					} - -					for (U32 i = 0; i < weight_list.size(); ++i) -					{ -						F32 wght = llmin(weight_list[i].mWeight, 0.999999f); -						F32 joint = (F32) weight_list[i].mJointIdx; -						w.mV[i] = joint + wght; -					} - -					*(weights_strider++) = w; -				} -			} - -			// build indices -			for (U32 i = 0; i < num_indices; i++) -			{ -				*(index_strider++) = vf.mIndices[i]; -			} - -			mVertexBuffer[lod][mdl].push_back(vb); - -			vertex_count += num_vertices; -			tri_count += num_indices/3; -			++mesh_count; - -		} -	} -} - -void LLModelPreview::update() -{ -	if (mDirty) -	{ -		mDirty = false; -		mResourceCost = calcResourceCost(); -		refresh(); -		updateStatusMessages(); -	} - -	if (mGenLOD) -	{ -		mGenLOD = false; -		genLODs(); -		refresh(); -		updateStatusMessages(); -	} - -} - -//----------------------------------------------------------------------------- -// render() -//----------------------------------------------------------------------------- -BOOL LLModelPreview::render() -{ -	assert_main_thread(); - -	LLMutexLock lock(this); -	mNeedsUpdate = FALSE; - -	bool edges = false; -	bool joint_positions = false; -	bool skin_weight = false; -	bool textures = false; -	bool physics = false; - -	LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; -	if (fmp) -	{ -		edges = fmp->isViewOptionChecked("show_edges"); -		joint_positions = fmp->isViewOptionChecked("show_joint_positions"); -		skin_weight = fmp->isViewOptionChecked("show_skin_weight"); -		textures = fmp->isViewOptionChecked("show_textures"); -		physics = fmp->isViewOptionChecked("show_physics"); -	} - -	S32 width = getWidth(); -	S32 height = getHeight(); - -	LLGLSUIDefault def; -	LLGLDisable no_blend(GL_BLEND); -	LLGLEnable cull(GL_CULL_FACE); -	LLGLDepthTest depth(GL_TRUE); -	LLGLDisable fog(GL_FOG); - -	{ -		//clear background to blue -		glMatrixMode(GL_PROJECTION); -		gGL.pushMatrix(); -		glLoadIdentity(); -		glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - -		glMatrixMode(GL_MODELVIEW); -		gGL.pushMatrix(); -		glLoadIdentity(); - -		gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - -		gl_rect_2d_simple( width, height ); - -		glMatrixMode(GL_PROJECTION); -		gGL.popMatrix(); - -		glMatrixMode(GL_MODELVIEW); -		gGL.popMatrix(); -	} - -	bool has_skin_weights = false; -	bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); -	bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - -	for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) -	{ -		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) -		{ -			LLModelInstance& instance = *model_iter; -			LLModel* model = instance.mModel; -			if (!model->mSkinWeights.empty()) -			{ -				has_skin_weights = true; -			} -		} -	} - -	if (has_skin_weights) -	{ //model has skin weights, enable view options for skin weights and joint positions -		if (fmp) -		{ -			fmp->enableViewOption("show_skin_weight"); -			fmp->setViewOptionEnabled("show_joint_positions", skin_weight); -		} -		mFMP->childEnable("upload_skin"); -	} -	else -	{ -		mFMP->childDisable("upload_skin"); -		if (fmp) -		{ -			fmp->setViewOption("show_skin_weight", false); -			fmp->disableViewOption("show_skin_weight"); -			fmp->disableViewOption("show_joint_positions"); -		} -		skin_weight = false; -	} - -	if (upload_skin && !has_skin_weights) -	{ //can't upload skin weights if model has no skin weights -		mFMP->childSetValue("upload_skin", false); -		upload_skin = false; -	} - -	if (!upload_skin && upload_joints) -	{ //can't upload joints if not uploading skin weights -		mFMP->childSetValue("upload_joints", false); -		upload_joints = false; -	} - -	mFMP->childSetEnabled("upload_joints", upload_skin); - -	F32 explode = mFMP->childGetValue("physics_explode").asReal(); - -	glClear(GL_DEPTH_BUFFER_BIT); - -	LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); -	F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); - -	LLViewerCamera::getInstance()->setAspect(aspect); - -	LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - -	LLVector3 offset = mCameraOffset; -	LLVector3 target_pos = mPreviewTarget+offset; - -	F32 z_near = 0.001f; -	F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); - -	if (skin_weight) -	{ -		target_pos = gAgentAvatarp->getPositionAgent(); -		z_near = 0.01f; -		z_far = 1024.f; -		mCameraDistance = 16.f; - -		//render avatar previews every frame -		refresh(); -	} - -	glLoadIdentity(); -	gPipeline.enableLightsPreview(); - -	LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * -	LLQuaternion(mCameraYaw, LLVector3::z_axis); - -	LLQuaternion av_rot = camera_rot; -	LLViewerCamera::getInstance()->setOriginAndLookAt( -													  target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot),		// camera -													  LLVector3::z_axis,																	// up -													  target_pos);											// point of interest - - -	LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - -	stop_glerror(); - -	gGL.pushMatrix(); -	const F32 BRIGHTNESS = 0.9f; -	gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); - -	LLGLEnable normalize(GL_NORMALIZE); - -	if (!mBaseModel.empty() && mVertexBuffer[5].empty()) -	{ -		genBuffers(-1, skin_weight); -		//genBuffers(3); -		//genLODs(); -	} - -	if (!mModel[mPreviewLOD].empty()) -	{ -		bool regen = mVertexBuffer[mPreviewLOD].empty(); -		if (!regen) -		{ -			const std::vector<LLPointer<LLVertexBuffer> >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; -			if (!vb_vec.empty()) -			{ -				const LLVertexBuffer* buff = vb_vec[0]; -				regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; -			} -		} - -		if (regen) -		{ -			genBuffers(mPreviewLOD, skin_weight); -		} - -		if (!skin_weight) -		{ -			for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) -			{ -				LLModelInstance& instance = *iter; - -				LLModel* model = instance.mLOD[mPreviewLOD]; - -				if (!model) -				{ -					continue; -				} - -				gGL.pushMatrix(); -				LLMatrix4 mat = instance.mTransform; - -				glMultMatrixf((GLfloat*) mat.mMatrix); - -				for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) -				{ -					LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - -					buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - -					if (textures) -					{ -						glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); -						if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) -						{ -							gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); -							if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) -							{ -								mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); -							} -						} -					} -					else -					{ -						glColor4f(1,1,1,1); -					} - -					buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -					gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -					glColor3f(0.4f, 0.4f, 0.4f); - -					if (edges) -					{ -						glLineWidth(3.f); -						glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -						buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -						glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -						glLineWidth(1.f); -					} -				} -				gGL.popMatrix(); -			} - -			if (physics) -			{ -				glClear(GL_DEPTH_BUFFER_BIT); -				LLGLEnable blend(GL_BLEND); -				gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO); - -				for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) -				{ -					LLModelInstance& instance = *iter; - -					LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - -					if (!model) -					{ -						continue; -					} - -					gGL.pushMatrix(); -					LLMatrix4 mat = instance.mTransform; - -					glMultMatrixf((GLfloat*) mat.mMatrix); - - -					bool render_mesh = true; - -					LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; -					if (decomp) -					{ -						LLMutexLock(decomp->mMutex); - -						std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > >::iterator iter = -							mPhysicsMesh.find(model); -						if (iter != mPhysicsMesh.end()) -						{ //render hull instead of mesh -							render_mesh = false; -							for (U32 i = 0; i < iter->second.size(); ++i) -							{ -								if (explode > 0.f) -								{ -									gGL.pushMatrix(); - -									LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; -									offset *= explode; - -									gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); -								} - -								static std::vector<LLColor4U> hull_colors; - -								if (i+1 >= hull_colors.size()) -								{ -									hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); -								} - -								LLVertexBuffer* buff = iter->second[i]; -								if (buff) -								{ -									buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - -									glColor4ubv(hull_colors[i].mV); -									buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); -								} - -								if (explode > 0.f) -								{ -									gGL.popMatrix(); -								} -							} -						} -					} - -					if (render_mesh) -					{ -						if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) -						{ -							genBuffers(LLModel::LOD_PHYSICS, false); -						} -						for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) -						{ -							LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - -							buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - -							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -							gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -							glColor4f(0.4f, 0.4f, 0.0f, 0.4f); - -							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - -							glColor3f(1.f, 1.f, 0.f); - -							glLineWidth(3.f); -							glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -							glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -							glLineWidth(1.f); -						} -					} - -					gGL.popMatrix(); -				} - -				gGL.setSceneBlendType(LLRender::BT_ALPHA); -			} -		} -		else -		{ -			LLVOAvatarSelf* avatar = gAgentAvatarp; -			target_pos = avatar->getPositionAgent(); - -			LLViewerCamera::getInstance()->setOriginAndLookAt( -															  target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot),		// camera -															  LLVector3::z_axis,																	// up -															  target_pos);											// point of interest - -			if (joint_positions) -			{ -				avatar->renderCollisionVolumes(); -			} - -			for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) -			{ -				for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) -				{ -					LLModelInstance& instance = *model_iter; -					LLModel* model = instance.mModel; - -					if (!model->mSkinWeights.empty()) -					{ -						for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) -						{ -							LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - -							const LLVolumeFace& face = model->getVolumeFace(i); - -							LLStrider<LLVector3> position; -							buffer->getVertexStrider(position); - -							LLStrider<LLVector4> weight; -							buffer->getWeight4Strider(weight); - -							//quick 'n dirty software vertex skinning - -							//build matrix palette -							LLMatrix4 mat[64]; -							for (U32 j = 0; j < model->mJointList.size(); ++j) -							{ -								LLJoint* joint = avatar->getJoint(model->mJointList[j]); -								if (joint) -								{ -									mat[j] = model->mInvBindMatrix[j]; -									mat[j] *= joint->getWorldMatrix(); -								} -							} - -							for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) -							{ -								LLMatrix4 final_mat; -								final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - -								LLVector4 wght; -								S32 idx[4]; - -								F32 scale = 0.f; -								for (U32 k = 0; k < 4; k++) -								{ -									F32 w = weight[j].mV[k]; - -									idx[k] = (S32) floorf(w); -									wght.mV[k] = w - floorf(w); -									scale += wght.mV[k]; -								} - -								wght *= 1.f/scale; - -								for (U32 k = 0; k < 4; k++) -								{ -									F32* src = (F32*) mat[idx[k]].mMatrix; -									F32* dst = (F32*) final_mat.mMatrix; - -									F32 w = wght.mV[k]; - -									for (U32 l = 0; l < 16; l++) -									{ -										dst[l] += src[l]*w; -									} -								} - -								//VECTORIZE THIS -								LLVector3 v(face.mPositions[j].getF32ptr()); - -								v = v * model->mBindShapeMatrix; -								v = v * final_mat; - -								position[j] = v; -							} - -							buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); -							glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); -							gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -							buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); -							glColor3f(0.4f, 0.4f, 0.4f); - -							if (edges) -							{ -								glLineWidth(3.f); -								glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -								buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); -								glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -								glLineWidth(1.f); -							} -						} -					} -				} -			} -		} -	} - -	gGL.popMatrix(); - -	return TRUE; -} - -//----------------------------------------------------------------------------- -// refresh() -//----------------------------------------------------------------------------- -void LLModelPreview::refresh() -{ -	mNeedsUpdate = TRUE; -} - -//----------------------------------------------------------------------------- -// rotate() -//----------------------------------------------------------------------------- -void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) -{ -	mCameraYaw = mCameraYaw + yaw_radians; - -	mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); -} - -//----------------------------------------------------------------------------- -// zoom() -//----------------------------------------------------------------------------- -void LLModelPreview::zoom(F32 zoom_amt) -{ -	F32 new_zoom = mCameraZoom+zoom_amt; - -	mCameraZoom	= llclamp(new_zoom, 1.f, 10.f); -} - -void LLModelPreview::pan(F32 right, F32 up) -{ -	mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); -	mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); -} - -void LLModelPreview::setPreviewLOD(S32 lod) -{ -	lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); - -	if (lod != mPreviewLOD) -	{ -		mPreviewLOD = lod; - -		LLComboBox* combo_box = mFMP->getChild<LLComboBox>("preview_lod_combo"); -		combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order -		mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); -		mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); - -		LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); -		LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); - -		for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) -		{ -			const LLColor4& color = (i == lod) ? highlight_color : normal_color; - -			mFMP->childSetColor(lod_status_name[i], color); -			mFMP->childSetColor(lod_label_name[i], color); -			mFMP->childSetColor(lod_triangles_name[i], color); -			mFMP->childSetColor(lod_vertices_name[i], color); -		} - -		LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; -		if (fmp) -		{ -			LLRadioGroup* radio = fmp->getChild<LLRadioGroup>("lod_file_or_limit"); -			radio->selectNthItem(fmp->mLODMode[mPreviewLOD]); -		} -	} -	refresh(); -	updateStatusMessages(); -} - -//static -void LLFloaterModelPreview::onBrowseLOD(void* data) -{ -	assert_main_thread(); - -	LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; -	mp->loadModel(mp->mModelPreview->mPreviewLOD); -} - -//static -void LLFloaterModelPreview::onUpload(void* user_data) -{ -	assert_main_thread(); - -	LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - -	mp->mModelPreview->rebuildUploadData(); - -	gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, -						  mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); - -	mp->closeFloater(false); -} - - -//static -void LLFloaterModelPreview::onClearMaterials(void* user_data) -{ -	LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; -	mp->mModelPreview->clearMaterials(); -} - -//static -void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) -{ -	sInstance->mModelPreview->mDirty = true; -} - -void LLFloaterModelPreview::updateResourceCost() -{ -	U32 cost = mModelPreview->mResourceCost; -	childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); -} - -//static -void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) -{ -	LLModelPreview* preview = (LLModelPreview*) userdata; -	preview->refresh(); -} - -LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) -{ -	mStage = stage; -	mContinue = 1; -	mModel = mdl; -	mDecompID = &mdl->mDecompID; -	mParams = sInstance->mDecompParams; - -	//copy out positions and indices -	if (mdl) -	{ -		U16 index_offset = 0; - -		mPositions.clear(); -		mIndices.clear(); - -		//queue up vertex positions and indices -		for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) -		{ -			const LLVolumeFace& face = mdl->getVolumeFace(i); -			if (mPositions.size() + face.mNumVertices > 65535) -			{ -				continue; -			} - -			for (U32 j = 0; j < face.mNumVertices; ++j) -			{ -				mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); -			} - -			for (U32 j = 0; j < face.mNumIndices; ++j) -			{ -				mIndices.push_back(face.mIndices[j]+index_offset); -			} - -			index_offset += face.mNumVertices; -		} -	} -} - -void LLFloaterModelPreview::setStatusMessage(const std::string& msg) -{ -	LLMutexLock lock(mStatusLock); -	mStatusMessage = msg; -} - -S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) -{ -	setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); -	if (LLFloaterModelPreview::sInstance) -	{ -		LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); -	} - -	return mContinue; -} - -void LLFloaterModelPreview::DecompRequest::completed() -{ //called from the main thread -	mModel->setConvexHullDecomposition(mHull); - -	if (sInstance) -	{ -		if (sInstance->mModelPreview) -		{ -			sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; -			sInstance->mModelPreview->mDirty = true; -			LLFloaterModelPreview::sInstance->mModelPreview->refresh(); -		} - -		sInstance->mCurRequest.erase(this); -	} -} +/**
 + * @file llfloatermodelpreview.cpp
 + * @brief LLFloaterModelPreview class implementation
 + *
 + * $LicenseInfo:firstyear=2004&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, Linden Research, Inc.
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation;
 + * version 2.1 of the License only.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 + *
 + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 + * $/LicenseInfo$
 + */
 +
 +#include "llviewerprecompiledheaders.h"
 +
 +#include "dae.h"
 +//#include "dom.h"
 +#include "dom/domAsset.h"
 +#include "dom/domBind_material.h"
 +#include "dom/domCOLLADA.h"
 +#include "dom/domConstants.h"
 +#include "dom/domController.h"
 +#include "dom/domEffect.h"
 +#include "dom/domGeometry.h"
 +#include "dom/domInstance_geometry.h"
 +#include "dom/domInstance_material.h"
 +#include "dom/domInstance_node.h"
 +#include "dom/domInstance_effect.h"
 +#include "dom/domMaterial.h"
 +#include "dom/domMatrix.h"
 +#include "dom/domNode.h"
 +#include "dom/domProfile_COMMON.h"
 +#include "dom/domRotate.h"
 +#include "dom/domScale.h"
 +#include "dom/domTranslate.h"
 +#include "dom/domVisual_scene.h"
 +
 +#include "llfloatermodelpreview.h"
 +
 +#include "llfilepicker.h"
 +#include "llimagebmp.h"
 +#include "llimagetga.h"
 +#include "llimagejpeg.h"
 +#include "llimagepng.h"
 +
 +#include "llagent.h"
 +#include "llbutton.h"
 +#include "llcombobox.h"
 +#include "lldatapacker.h"
 +#include "lldrawable.h"
 +#include "lldrawpoolavatar.h"
 +#include "llrender.h"
 +#include "llface.h"
 +#include "lleconomy.h"
 +#include "llfocusmgr.h"
 +#include "llfloaterperms.h"
 +#include "lliconctrl.h"
 +#include "llmatrix4a.h"
 +#include "llmenubutton.h"
 +#include "llmeshrepository.h"
 +#include "llsdutil_math.h"
 +#include "lltextbox.h"
 +#include "lltoolmgr.h"
 +#include "llui.h"
 +#include "llvector4a.h"
 +#include "llviewercamera.h"
 +#include "llviewerwindow.h"
 +#include "llvoavatar.h"
 +#include "llvoavatarself.h"
 +#include "pipeline.h"
 +#include "lluictrlfactory.h"
 +#include "llviewermenu.h"
 +#include "llviewermenufile.h"
 +#include "llviewerregion.h"
 +#include "llviewertexturelist.h"
 +#include "llstring.h"
 +#include "llbutton.h"
 +#include "llcheckboxctrl.h"
 +#include "llradiogroup.h"
 +#include "llsliderctrl.h"
 +#include "llspinctrl.h"
 +#include "lltoggleablemenu.h"
 +#include "llvfile.h"
 +#include "llvfs.h"
 +#include "llcallbacklist.h"
 +
 +#include "glod/glod.h"
 +
 +//static
 +S32 LLFloaterModelPreview::sUploadAmount = 10;
 +LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL;
 +
 +const S32 PREVIEW_BORDER_WIDTH = 2;
 +const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
 +const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
 +const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16;
 +const S32 PREVIEW_TEXTURE_HEIGHT = 300;
 +
 +void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
 +
 +
 +std::string lod_name[NUM_LOD+1] =
 +{
 +	"lowest",
 +	"low",
 +	"medium",
 +	"high",
 +	"I went off the end of the lod_name array.  Me so smart."
 +};
 +
 +std::string lod_triangles_name[NUM_LOD+1] =
 +{
 +	"lowest_triangles",
 +	"low_triangles",
 +	"medium_triangles",
 +	"high_triangles",
 +	"I went off the end of the lod_triangles_name array.  Me so smart."
 +};
 +
 +std::string lod_vertices_name[NUM_LOD+1] =
 +{
 +	"lowest_vertices",
 +	"low_vertices",
 +	"medium_vertices",
 +	"high_vertices",
 +	"I went off the end of the lod_vertices_name array.  Me so smart."
 +};
 +
 +std::string lod_status_name[NUM_LOD+1] =
 +{
 +	"lowest_status",
 +	"low_status",
 +	"medium_status",
 +	"high_status",
 +	"I went off the end of the lod_status_name array.  Me so smart."
 +};
 +
 +std::string lod_icon_name[NUM_LOD+1] =
 +{
 +	"status_icon_lowest",
 +	"status_icon_low",
 +	"status_icon_medium",
 +	"status_icon_high",
 +	"I went off the end of the lod_status_name array.  Me so smart."
 +};
 +
 +std::string lod_status_image[NUM_LOD+1] =
 +{
 +	"ModelImport_Status_Good",
 +	"ModelImport_Status_Warning",
 +	"ModelImport_Status_Error",
 +	"I went off the end of the lod_status_image array.  Me so smart."
 +};
 +
 +std::string lod_label_name[NUM_LOD+1] =
 +{
 +	"lowest_label",
 +	"low_label",
 +	"medium_label",
 +	"high_label",
 +	"I went off the end of the lod_label_name array.  Me so smart."
 +};
 +
 +
 +bool validate_face(const LLVolumeFace& face)
 +{
 +	for (U32 i = 0; i < face.mNumIndices; ++i)
 +	{
 +		if (face.mIndices[i] >= face.mNumVertices)
 +		{
 +			llwarns << "Face has invalid index." << llendl;
 +			return false;
 +		}
 +	}
 +
 +	return true;
 +}
 +
 +bool validate_model(const LLModel* mdl)
 +{
 +	if (mdl->getNumVolumeFaces() == 0)
 +	{
 +		llwarns << "Model has no faces!" << llendl;
 +		return false;
 +	}
 +
 +	for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
 +	{
 +		if (mdl->getVolumeFace(i).mNumVertices == 0)
 +		{
 +			llwarns << "Face has no vertices." << llendl;
 +			return false;
 +		}
 +
 +		if (mdl->getVolumeFace(i).mNumIndices == 0)
 +		{
 +			llwarns << "Face has no indices." << llendl;
 +			return false;
 +		}
 +
 +		if (!validate_face(mdl->getVolumeFace(i)))
 +		{
 +			return false;
 +		}
 +	}
 +
 +	return true;
 +}
 +
 +BOOL stop_gloderror()
 +{
 +	GLuint error = glodGetError();
 +
 +	if (error != GLOD_NO_ERROR)
 +	{
 +		llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl;
 +		return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +
 +LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod)
 +	: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
 +	{
 +		mMP = mp;
 +		mLOD = lod;
 +	}
 +
 +void LLMeshFilePicker::notify(const std::string& filename)
 +{
 +	mMP->loadModel(mFile, mLOD);
 +}
 +
 +
 +//-----------------------------------------------------------------------------
 +// LLFloaterModelPreview()
 +//-----------------------------------------------------------------------------
 +LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) :
 +LLFloater(key)
 +{
 +	sInstance = this;
 +	mLastMouseX = 0;
 +	mLastMouseY = 0;
 +	mGLName = 0;
 +	mStatusLock = new LLMutex(NULL);
 +
 +	mLODMode[LLModel::LOD_HIGH] = 0;
 +	for (U32 i = 0; i < LLModel::LOD_HIGH; i++)
 +	{
 +		mLODMode[i] = 1;
 +	}
 +}
 +
 +//-----------------------------------------------------------------------------
 +// postBuild()
 +//-----------------------------------------------------------------------------
 +BOOL LLFloaterModelPreview::postBuild()
 +{
 +	if (!LLFloater::postBuild())
 +	{
 +		return FALSE;
 +	}
 +
 +
 +
 +
 +
 +
 +	childSetAction("lod_browse", onBrowseLOD, this);
 +
 +	childSetCommitCallback("cancel_btn", onCancel, this);
 +	childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this);
 +	childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this);
 +
 +	childSetCommitCallback("lod_generate", onAutoFillCommit, this);
 +
 +	childSetCommitCallback("lod_mode", onLODParamCommit, this);
 +	childSetCommitCallback("lod_error_threshold", onLODParamCommit, this);
 +	childSetCommitCallback("lod_triangle_limit", onLODParamCommit, this);
 +	childSetCommitCallback("build_operator", onLODParamCommit, this);
 +	childSetCommitCallback("queue_mode", onLODParamCommit, this);
 +	childSetCommitCallback("border_mode", onLODParamCommit, this);
 +	childSetCommitCallback("share_tolerance", onLODParamCommit, this);
 +
 +	childSetTextArg("status", "[STATUS]", getString("status_idle"));
 +
 +	//childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount));
 +	childSetAction("ok_btn", onUpload, this);
 +	childDisable("ok_btn");
 +
 +	childSetAction("clear_materials", onClearMaterials, this);
 +
 +	childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this);
 +
 +	childSetCommitCallback("upload_skin", onUploadSkinCommit, this);
 +	childSetCommitCallback("upload_joints", onUploadJointsCommit, this);
 +
 +	childSetCommitCallback("import_scale", onImportScaleCommit, this);
 +
 +	childSetCommitCallback("lod_file_or_limit", refresh, this);
 +	childSetCommitCallback("physics_load_radio", refresh, this);
 +	//childSetCommitCallback("physics_optimize", refresh, this);
 +	//childSetCommitCallback("physics_use_hull", refresh, this);
 +
 +	childDisable("upload_skin");
 +	childDisable("upload_joints");
 +	childDisable("ok_btn");
 +
 +	mViewOptionMenuButton = getChild<LLMenuButton>("options_gear_btn");
 +
 +	mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2));
 +	mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2));
 +	mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2));
 +
 +
 +
 +	mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 +	mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT);
 +
 +	initDecompControls();
 +
 +	LLView* preview_panel = getChild<LLView>("preview_panel");
 +
 +	mPreviewRect = preview_panel->getRect();
 +
 +	mModelPreview = new LLModelPreview(512, 512, this);
 +	mModelPreview->setPreviewTarget(16.f);
 +
 +	//set callbacks for left click on line editor rows
 +	for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
 +	{
 +		LLTextBox* text = getChild<LLTextBox>(lod_label_name[i]);
 +		if (text)
 +		{
 +			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
 +		}
 +
 +		text = getChild<LLTextBox>(lod_triangles_name[i]);
 +		if (text)
 +		{
 +			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
 +		}
 +
 +		text = getChild<LLTextBox>(lod_vertices_name[i]);
 +		if (text)
 +		{
 +			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
 +		}
 +
 +		text = getChild<LLTextBox>(lod_status_name[i]);
 +		if (text)
 +		{
 +			text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
 +		}
 +	}
 +
 +	return TRUE;
 +}
 +
 +//-----------------------------------------------------------------------------
 +// LLFloaterModelPreview()
 +//-----------------------------------------------------------------------------
 +LLFloaterModelPreview::~LLFloaterModelPreview()
 +{
 +	sInstance = NULL;
 +
 +	if ( mModelPreview->containsRiggedAsset() )
 +	{
 +		gAgentAvatarp->resetJointPositions();
 +	}
 +
 +	delete mModelPreview;
 +
 +	if (mGLName)
 +	{
 +		LLImageGL::deleteTextures(1, &mGLName );
 +	}
 +
 +	delete mStatusLock;
 +	mStatusLock = NULL;
 +}
 +
 +void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata)
 +{
 +	if (mModelPreview)
 +	{
 +		mModelPreview->mViewOption[userdata.asString()] = !mModelPreview->mViewOption[userdata.asString()];
 +		
 +		mModelPreview->refresh();
 +	}
 +}
 +
 +bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata)
 +{
 +	if (mModelPreview)
 +	{
 +		return mModelPreview->mViewOption[userdata.asString()];
 +	}
 +
 +	return false;
 +}
 +
 +bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata)
 +{
 +	return !mViewOptionDisabled[userdata.asString()];
 +}
 +
 +void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled)
 +{
 +	mViewOptionDisabled[option] = !enabled;
 +}
 +
 +void LLFloaterModelPreview::enableViewOption(const std::string& option)
 +{
 +	setViewOptionEnabled(option, true);
 +}
 +
 +void LLFloaterModelPreview::disableViewOption(const std::string& option)
 +{
 +	setViewOptionEnabled(option, false);
 +}
 +
 +void LLFloaterModelPreview::loadModel(S32 lod)
 +{
 +	mModelPreview->mLoading = true;
 +
 +	(new LLMeshFilePicker(mModelPreview, lod))->getFile();
 +}
 +
 +//static
 +void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata)
 +{
 +	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
 +
 +	if (!fp->mModelPreview)
 +	{
 +		return;
 +	}
 +
 +	fp->mModelPreview->calcResourceCost();
 +	fp->mModelPreview->refresh();
 +}
 +
 +//static
 +void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata)
 +{
 +	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
 +
 +	if (!fp->mModelPreview)
 +	{
 +		return;
 +	}
 +
 +	fp->mModelPreview->refresh();
 +}
 +
 +//static
 +void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata)
 +{
 +	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
 +
 +	if (!fp->mModelPreview)
 +	{
 +		return;
 +	}
 +
 +	fp->mModelPreview->refresh();
 +	fp->mModelPreview->resetPreviewTarget();
 +	fp->mModelPreview->clearBuffers();
 +}
 +
 +//static
 +void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata)
 +{
 +	LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
 +
 +	if (!fp->mModelPreview)
 +	{
 +		return;
 +	}
 +
 +	S32 which_mode = 0;
 +
 +	LLComboBox* combo = (LLComboBox*) ctrl;
 +
 +	which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order
 +
 +	fp->mModelPreview->setPreviewLOD(which_mode);
 +}
 +
 +//static
 +void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata)
 +{
 +	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
 +
 +	fp->mModelPreview->generateNormals();
 +}
 +
 +//static
 +void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata)
 +{
 +	LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance;
 +
 +	fp->mModelPreview->refresh();
 +}
 +
 +//static
 +void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
 +{
 +	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
 +
 +	fp->mModelPreview->genLODs();
 +}
 +
 +//static
 +void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata)
 +{
 +	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
 +	fp->mModelPreview->genLODs(fp->mModelPreview->mPreviewLOD);
 +	fp->mModelPreview->updateStatusMessages();
 +	fp->mModelPreview->refresh();
 +}
 +
 +
 +//-----------------------------------------------------------------------------
 +// draw()
 +//-----------------------------------------------------------------------------
 +void LLFloaterModelPreview::draw()
 +{
 +	LLFloater::draw();
 +	LLRect r = getRect();
 +
 +	mModelPreview->update();
 +
 +	if (!mModelPreview->mLoading)
 +	{
 +		childSetTextArg("status", "[STATUS]", getString("status_idle"));
 +	}
 +
 +	childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost));
 +	childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size()));
 +
 +	if (!mCurRequest.empty())
 +	{
 +		LLMutexLock lock(mStatusLock);
 +		childSetTextArg("status", "[STATUS]", mStatusMessage);
 +	}
 +	else
 +	{
 +		childSetVisible("Simplify", true);
 +		childSetVisible("simplify_cancel", false);
 +		childSetVisible("Decompose", true);
 +		childSetVisible("decompose_cancel", false);
 +	}
 +	
 +	U32 resource_cost = mModelPreview->mResourceCost*10;
 +
 +	if (childGetValue("upload_textures").asBoolean())
 +	{
 +		resource_cost += mModelPreview->mTextureSet.size()*10;
 +	}
 +
 +	childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost));
 +
 +	if (mModelPreview)
 +	{
 +		gGL.color3f(1.f, 1.f, 1.f);
 +
 +		gGL.getTexUnit(0)->bind(mModelPreview);
 +
 +
 +		LLView* preview_panel = getChild<LLView>("preview_panel");
 +
 +		LLRect rect = preview_panel->getRect();
 +		if (rect != mPreviewRect)
 +		{
 +			mModelPreview->refresh();
 +			mPreviewRect = preview_panel->getRect();
 +		}
 +
 +		gGL.begin( LLRender::QUADS );
 +		{
 +			gGL.texCoord2f(0.f, 1.f);
 +			gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop);
 +			gGL.texCoord2f(0.f, 0.f);
 +			gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom);
 +			gGL.texCoord2f(1.f, 0.f);
 +			gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom);
 +			gGL.texCoord2f(1.f, 1.f);
 +			gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop);
 +		}
 +		gGL.end();
 +
 +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 +	}
 +}
 +
 +//-----------------------------------------------------------------------------
 +// handleMouseDown()
 +//-----------------------------------------------------------------------------
 +BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask)
 +{
 +	if (mPreviewRect.pointInRect(x, y))
 +	{
 +		bringToFront( x, y );
 +		gFocusMgr.setMouseCapture(this);
 +		gViewerWindow->hideCursor();
 +		mLastMouseX = x;
 +		mLastMouseY = y;
 +		return TRUE;
 +	}
 +
 +	return LLFloater::handleMouseDown(x, y, mask);
 +}
 +
 +//-----------------------------------------------------------------------------
 +// handleMouseUp()
 +//-----------------------------------------------------------------------------
 +BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask)
 +{
 +	gFocusMgr.setMouseCapture(FALSE);
 +	gViewerWindow->showCursor();
 +	return LLFloater::handleMouseUp(x, y, mask);
 +}
 +
 +//-----------------------------------------------------------------------------
 +// handleHover()
 +//-----------------------------------------------------------------------------
 +BOOL LLFloaterModelPreview::handleHover	(S32 x, S32 y, MASK mask)
 +{
 +	MASK local_mask = mask & ~MASK_ALT;
 +
 +	if (mModelPreview && hasMouseCapture())
 +	{
 +		if (local_mask == MASK_PAN)
 +		{
 +			// pan here
 +			mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f);
 +		}
 +		else if (local_mask == MASK_ORBIT)
 +		{
 +			F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
 +			F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f;
 +
 +			mModelPreview->rotate(yaw_radians, pitch_radians);
 +		}
 +		else
 +		{
 +
 +			F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
 +			F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f;
 +
 +			mModelPreview->rotate(yaw_radians, 0.f);
 +			mModelPreview->zoom(zoom_amt);
 +		}
 +
 +
 +		mModelPreview->refresh();
 +
 +		LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY);
 +	}
 +
 +	if (!mPreviewRect.pointInRect(x, y) || !mModelPreview)
 +	{
 +		return LLFloater::handleHover(x, y, mask);
 +	}
 +	else if (local_mask == MASK_ORBIT)
 +	{
 +		gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA);
 +	}
 +	else if (local_mask == MASK_PAN)
 +	{
 +		gViewerWindow->setCursor(UI_CURSOR_TOOLPAN);
 +	}
 +	else
 +	{
 +		gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN);
 +	}
 +
 +	return TRUE;
 +}
 +
 +//-----------------------------------------------------------------------------
 +// handleScrollWheel()
 +//-----------------------------------------------------------------------------
 +BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
 +{
 +	if (mPreviewRect.pointInRect(x, y) && mModelPreview)
 +	{
 +		mModelPreview->zoom((F32)clicks * -0.2f);
 +		mModelPreview->refresh();
 +	}
 +
 +	return TRUE;
 +}
 +
 +//static
 +void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)
 +{
 +	if (LLConvexDecomposition::getInstance() == NULL)
 +	{
 +		llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl;
 +		return;
 +	}
 +
 +	if (sInstance)
 +	{
 +		LLCDParam* param = (LLCDParam*) data;
 +		std::string name(param->mName);
 +		sInstance->mDecompParams[name] = ctrl->getValue();
 +
 +		if (name == "Simplify Method")
 +		{
 +			 if (ctrl->getValue().asInteger() == 0)
 +			 {
 +				sInstance->childSetVisible("Retain%", true);
 +				sInstance->childSetVisible("Detail Scale", false);
 +			 }
 +			else
 +			{
 +				sInstance->childSetVisible("Retain%", false);
 +				sInstance->childSetVisible("Detail Scale", true);
 +			}
 +		}
 +	}
 +}
 +
 +//static
 +void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data)
 +{
 +	LLCDStageData* stage_data = (LLCDStageData*) data;
 +	std::string stage = stage_data->mName;
 +
 +	if (sInstance)
 +	{
 +		if (!sInstance->mCurRequest.empty())
 +		{
 +			llinfos << "Decomposition request still pending." << llendl;
 +			return;
 +		}
 +
 +		if (sInstance->mModelPreview)
 +		{
 +			for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i)
 +			{
 +				LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i];
 +				DecompRequest* request = new DecompRequest(stage, mdl);
 +				sInstance->mCurRequest.insert(request);
 +				gMeshRepo.mDecompThread->submitRequest(request);
 +			}
 +		}
 +
 +		if (stage == "Decompose")
 +		{
 +			sInstance->childSetVisible("Decompose", false);
 +			sInstance->childSetVisible("decompose_cancel", true);
 +		}
 +		else if (stage == "Simplify")
 +		{
 +			sInstance->childSetVisible("Simplify", false);
 +			sInstance->childSetVisible("simplify_cancel", true);
 +		}
 +	}
 +}
 +
 +//static
 +void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata)
 +{
 +	sInstance->loadModel(LLModel::LOD_PHYSICS);
 +}
 +
 +//static
 +void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata)
 +{
 +	S32 which_mode = 3;
 +	LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo");
 +	if (iface)
 +	{
 +		which_mode = iface->getFirstSelectedIndex();
 +	}
 +
 +	sInstance->mModelPreview->setPhysicsFromLOD(which_mode);
 +}
 +
 +//static 
 +void LLFloaterModelPreview::onCancel(LLUICtrl* ctrl, void* data)
 +{
 +	if (sInstance)
 +	{
 +		sInstance->closeFloater(false);
 +	}
 +}
 +
 +//static
 +void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data)
 +{
 +	if (sInstance)
 +	{
 +		for (std::set<LLPointer<DecompRequest> >::iterator iter = sInstance->mCurRequest.begin();
 +			iter != sInstance->mCurRequest.end(); ++iter)
 +		{
 +		    DecompRequest* req = *iter;
 +		    req->mContinue = 0;
 +		}
 +	}
 +}
 +
 +void LLFloaterModelPreview::initDecompControls()
 +{
 +	LLSD key;
 +
 +	childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL);
 +	childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL);
 +
 +	childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL);
 +	childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL);
 +
 +	static const LLCDStageData* stage = NULL;
 +	static S32 stage_count = 0;
 +
 +	if (!stage && LLConvexDecomposition::getInstance() != NULL)
 +	{
 +		stage_count = LLConvexDecomposition::getInstance()->getStages(&stage);
 +	}
 +
 +	static const LLCDParam* param = NULL;
 +	static S32 param_count = 0;
 +	if (!param && LLConvexDecomposition::getInstance() != NULL)
 +	{
 +		param_count = LLConvexDecomposition::getInstance()->getParameters(¶m);
 +	}
 +
 +	for (S32 j = stage_count-1; j >= 0; --j)
 +	{
 +		LLButton* button = getChild<LLButton>(stage[j].mName);
 +		if (button)
 +		{
 +			button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]);
 +		}
 +
 +		gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j;
 +		// protected against stub by stage_count being 0 for stub above
 +		LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback);
 +
 +		//llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl;
 +		//llinfos << "------------------------------------" << llendl;
 +
 +		for (S32 i = 0; i < param_count; ++i)
 +		{
 +			if (param[i].mStage != j)
 +			{
 +				continue;
 +			}
 +
 +			std::string name(param[i].mName ? param[i].mName : "");
 +			std::string description(param[i].mDescription ? param[i].mDescription : "");
 +
 +			std::string type = "unknown";
 +
 +			llinfos << name << " - " << description << llendl;
 +
 +			if (param[i].mType == LLCDParam::LLCD_FLOAT)
 +			{
 +				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat);
 +				//llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl;
 +
 +				LLSliderCtrl* slider = getChild<LLSliderCtrl>(name);
 +				if (slider)
 +				{
 +					slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat);
 +					slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat);
 +					slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat);
 +					slider->setValue(param[i].mDefault.mFloat);
 +					slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]);
 +				}
 +			}
 +			else if (param[i].mType == LLCDParam::LLCD_INTEGER)
 +			{
 +				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue);
 +				//llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl;
 +
 +				LLSliderCtrl* slider = getChild<LLSliderCtrl>(name);
 +				if (slider)
 +				{
 +					slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue);
 +					slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue);
 +					slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue);
 +					slider->setValue(param[i].mDefault.mIntOrEnumValue);
 +					slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]);
 +				}
 +			}
 +			else if (param[i].mType == LLCDParam::LLCD_BOOLEAN)
 +			{
 +				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool);
 +				//llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl;
 +
 +				LLCheckBoxCtrl* check_box = getChild<LLCheckBoxCtrl>(name);
 +				if (check_box)
 +				{
 +					check_box->setValue(param[i].mDefault.mBool);
 +					check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]);
 +				}
 +			}
 +			else if (param[i].mType == LLCDParam::LLCD_ENUM)
 +			{
 +				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue);
 +				//llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl;
 +
 +				{ //plug into combo box
 +
 +					//llinfos << "Accepted values: " << llendl;
 +					LLComboBox* combo_box = getChild<LLComboBox>(name);
 +					for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k)
 +					{
 +						//llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue
 +						//	<< " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl;
 +
 +						combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName,
 +							LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue));
 +					}
 +					combo_box->setValue(param[i].mDefault.mIntOrEnumValue);
 +					combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]);
 +				}
 +
 +				//llinfos << "----" << llendl;
 +			}
 +			//llinfos << "-----------------------------" << llendl;
 +		}
 +	}
 +
 +	childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this);
 +}
 +
 +//-----------------------------------------------------------------------------
 +// onMouseCaptureLost()
 +//-----------------------------------------------------------------------------
 +// static
 +void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler)
 +{
 +	gViewerWindow->showCursor();
 +}
 +
 +//-----------------------------------------------------------------------------
 +// LLModelLoader
 +//-----------------------------------------------------------------------------
 +LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview)
 +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE)
 +{
 +	mJointMap["mPelvis"] = "mPelvis";
 +	mJointMap["mTorso"] = "mTorso";
 +	mJointMap["mChest"] = "mChest";
 +	mJointMap["mNeck"] = "mNeck";
 +	mJointMap["mHead"] = "mHead";
 +	mJointMap["mSkull"] = "mSkull";
 +	mJointMap["mEyeRight"] = "mEyeRight";
 +	mJointMap["mEyeLeft"] = "mEyeLeft";
 +	mJointMap["mCollarLeft"] = "mCollarLeft";
 +	mJointMap["mShoulderLeft"] = "mShoulderLeft";
 +	mJointMap["mElbowLeft"] = "mElbowLeft";
 +	mJointMap["mWristLeft"] = "mWristLeft";
 +	mJointMap["mCollarRight"] = "mCollarRight";
 +	mJointMap["mShoulderRight"] = "mShoulderRight";
 +	mJointMap["mElbowRight"] = "mElbowRight";
 +	mJointMap["mWristRight"] = "mWristRight";
 +	mJointMap["mHipRight"] = "mHipRight";
 +	mJointMap["mKneeRight"] = "mKneeRight";
 +	mJointMap["mAnkleRight"] = "mAnkleRight";
 +	mJointMap["mFootRight"] = "mFootRight";
 +	mJointMap["mToeRight"] = "mToeRight";
 +	mJointMap["mHipLeft"] = "mHipLeft";
 +	mJointMap["mKneeLeft"] = "mKneeLeft";
 +	mJointMap["mAnkleLeft"] = "mAnkleLeft";
 +	mJointMap["mFootLeft"] = "mFootLeft";
 +	mJointMap["mToeLeft"] = "mToeLeft";
 +
 +	mJointMap["avatar_mPelvis"] = "mPelvis";
 +	mJointMap["avatar_mTorso"] = "mTorso";
 +	mJointMap["avatar_mChest"] = "mChest";
 +	mJointMap["avatar_mNeck"] = "mNeck";
 +	mJointMap["avatar_mHead"] = "mHead";
 +	mJointMap["avatar_mSkull"] = "mSkull";
 +	mJointMap["avatar_mEyeRight"] = "mEyeRight";
 +	mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
 +	mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
 +	mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
 +	mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
 +	mJointMap["avatar_mWristLeft"] = "mWristLeft";
 +	mJointMap["avatar_mCollarRight"] = "mCollarRight";
 +	mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
 +	mJointMap["avatar_mElbowRight"] = "mElbowRight";
 +	mJointMap["avatar_mWristRight"] = "mWristRight";
 +	mJointMap["avatar_mHipRight"] = "mHipRight";
 +	mJointMap["avatar_mKneeRight"] = "mKneeRight";
 +	mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
 +	mJointMap["avatar_mFootRight"] = "mFootRight";
 +	mJointMap["avatar_mToeRight"] = "mToeRight";
 +	mJointMap["avatar_mHipLeft"] = "mHipLeft";
 +	mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
 +	mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
 +	mJointMap["avatar_mFootLeft"] = "mFootLeft";
 +	mJointMap["avatar_mToeLeft"] = "mToeLeft";
 +
 +
 +	mJointMap["hip"] = "mPelvis";
 +	mJointMap["abdomen"] = "mTorso";
 +	mJointMap["chest"] = "mChest";
 +	mJointMap["neck"] = "mNeck";
 +	mJointMap["head"] = "mHead";
 +	mJointMap["figureHair"] = "mSkull";
 +	mJointMap["lCollar"] = "mCollarLeft";
 +	mJointMap["lShldr"] = "mShoulderLeft";
 +	mJointMap["lForeArm"] = "mElbowLeft";
 +	mJointMap["lHand"] = "mWristLeft";
 +	mJointMap["rCollar"] = "mCollarRight";
 +	mJointMap["rShldr"] = "mShoulderRight";
 +	mJointMap["rForeArm"] = "mElbowRight";
 +	mJointMap["rHand"] = "mWristRight";
 +	mJointMap["rThigh"] = "mHipRight";
 +	mJointMap["rShin"] = "mKneeRight";
 +	mJointMap["rFoot"] = "mFootRight";
 +	mJointMap["lThigh"] = "mHipLeft";
 +	mJointMap["lShin"] = "mKneeLeft";
 +	mJointMap["lFoot"] = "mFootLeft";
 +}
 +
 +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform)
 +{
 +	LLVector4a box[] =
 +	{
 +		LLVector4a(-1, 1,-1),
 +		LLVector4a(-1, 1, 1),
 +		LLVector4a(-1,-1,-1),
 +		LLVector4a(-1,-1, 1),
 +		LLVector4a( 1, 1,-1),
 +		LLVector4a( 1, 1, 1),
 +		LLVector4a( 1,-1,-1),
 +		LLVector4a( 1,-1, 1),
 +	};
 +
 +	for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
 +	{
 +		const LLVolumeFace& face = model->getVolumeFace(j);
 +
 +		LLVector4a center;
 +		center.setAdd(face.mExtents[0], face.mExtents[1]);
 +		center.mul(0.5f);
 +		LLVector4a size;
 +		size.setSub(face.mExtents[1],face.mExtents[0]);
 +		size.mul(0.5f);
 +
 +		for (U32 i = 0; i < 8; i++)
 +		{
 +			LLVector4a t;
 +			t.setMul(size, box[i]);
 +			t.add(center);
 +
 +			LLVector4a v;
 +
 +			mat.affineTransform(t, v);
 +
 +			if (first_transform)
 +			{
 +				first_transform = FALSE;
 +				min = max = v;
 +			}
 +			else
 +			{
 +				update_min_max(min, max, v);
 +			}
 +		}
 +	}
 +}
 +
 +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform)
 +{
 +	LLVector4a mina, maxa;
 +	LLMatrix4a mata;
 +
 +	mata.loadu(mat);
 +	mina.load3(min.mV);
 +	maxa.load3(max.mV);
 +
 +	stretch_extents(model, mata, mina, maxa, first_transform);
 +
 +	min.set(mina.getF32ptr());
 +	max.set(maxa.getF32ptr());
 +}
 +
 +void LLModelLoader::run()
 +{
 +	DAE dae;
 +	domCOLLADA* dom = dae.open(mFilename);
 +
 +	if (dom)
 +	{
 +		daeDatabase* db = dae.getDatabase();
 +
 +		daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH);
 +
 +		daeDocument* doc = dae.getDoc(mFilename);
 +		if (!doc)
 +		{
 +			llwarns << "can't find internal doc" << llendl;
 +			return;
 +		}
 +
 +		daeElement* root = doc->getDomRoot();
 +		if (!root)
 +		{
 +			llwarns << "document has no root" << llendl;
 +			return;
 +		}
 +
 +		//get unit scale
 +		mTransform.setIdentity();
 +
 +		domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID())));
 +
 +		if (unit)
 +		{
 +			F32 meter = unit->getMeter();
 +			mTransform.mMatrix[0][0] = meter;
 +			mTransform.mMatrix[1][1] = meter;
 +			mTransform.mMatrix[2][2] = meter;
 +		}
 +
 +		//get up axis rotation
 +		LLMatrix4 rotation;
 +
 +		domUpAxisType up = UPAXISTYPE_Y_UP;  // default is Y_UP
 +		domAsset::domUp_axis* up_axis =
 +		daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID())));
 +
 +		if (up_axis)
 +		{
 +			up = up_axis->getValue();
 +		}
 +
 +		if (up == UPAXISTYPE_X_UP)
 +		{
 +			rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f);
 +		}
 +		else if (up == UPAXISTYPE_Y_UP)
 +		{
 +			rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f);
 +		}
 +
 +		rotation *= mTransform;
 +		mTransform = rotation;
 +
 +
 +		for (daeInt idx = 0; idx < count; ++idx)
 +		{ //build map of domEntities to LLModel
 +			domMesh* mesh = NULL;
 +			db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH);
 +
 +			if (mesh)
 +			{
 +				LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh);
 +
 +				if (model.notNull() && validate_model(model))
 +				{
 +					mModelList.push_back(model);
 +					mModel[mesh] = model;
 +				}
 +			}
 +		}
 +
 +		count = db->getElementCount(NULL, COLLADA_TYPE_SKIN);
 +		for (daeInt idx = 0; idx < count; ++idx)
 +		{ //add skinned meshes as instances
 +			domSkin* skin = NULL;
 +			db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN);
 +
 +			if (skin)
 +			{
 +				domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement());
 +
 +				if (geom)
 +				{
 +					domMesh* mesh = geom->getMesh();
 +					if (mesh)
 +					{
 +						LLModel* model = mModel[mesh];
 +						if (model)
 +						{
 +							LLVector3 mesh_scale_vector;
 +							LLVector3 mesh_translation_vector;
 +							model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
 +
 +							LLMatrix4 normalized_transformation;
 +							normalized_transformation.setTranslation(mesh_translation_vector);
 +
 +							LLMatrix4 mesh_scale;
 +							mesh_scale.initScale(mesh_scale_vector);
 +							mesh_scale *= normalized_transformation;
 +							normalized_transformation = mesh_scale;
 +
 +							glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix);
 +							inv_mat = inv_mat.inverse();
 +							LLMatrix4 inverse_normalized_transformation(inv_mat.m);
 +
 +							domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix();
 +
 +							if (bind_mat)
 +							{ //get bind shape matrix
 +								domFloat4x4& dom_value = bind_mat->getValue();
 +
 +								for (int i = 0; i < 4; i++)
 +								{
 +									for(int j = 0; j < 4; j++)
 +									{
 +										model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
 +									}
 +								}
 +
 +								LLMatrix4 trans = normalized_transformation;
 +								trans *= model->mBindShapeMatrix;
 +								model->mBindShapeMatrix = trans;
 +
 +							}
 +
 +
 +							//The joint transfom map that we'll populate below
 +							std::map<std::string,LLMatrix4> jointTransforms;
 +							jointTransforms.clear();
 +
 +							//Some collada setup for accessing the skeleton
 +							daeElement* pElement = 0;
 +							dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" );
 +
 +							//Try to get at the skeletal instance controller
 +							domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement );
 +							bool missingSkeletonOrScene = false;
 +
 +							//If no skeleton, do a breadth-first search to get at specific joints
 +							if ( !pSkeleton )
 +							{
 +								daeElement* pScene = root->getDescendant("visual_scene");
 +								if ( !pScene )
 +								{
 +									llwarns<<"No visual scene - unable to parse bone offsets "<<llendl;
 +									missingSkeletonOrScene = true;
 +								}
 +								else
 +								{
 +									//Get the children at this level
 +									daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
 +									S32 childCount = children.getCount();
 +
 +									//Process any children that are joints
 +									//Not all children are joints, some code be ambient lights, cameras, geometry etc..
 +									for (S32 i = 0; i < childCount; ++i)
 +									{
 +										domNode* pNode = daeSafeCast<domNode>(children[i]);
 +										if ( isNodeAJoint( pNode ) )
 +										{
 +											processJointNode( pNode, jointTransforms );
 +										}
 +									}
 +								}
 +							}
 +							else
 +							//Has Skeleton
 +							{
 +								//Get the root node of the skeleton
 +								daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
 +								if ( pSkeletonRootNode )
 +								{
 +									//Once we have the root node - start acccessing it's joint components
 +									const int jointCnt = mJointMap.size();
 +									std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin();
 +
 +									//Loop over all the possible joints within the .dae - using the allowed joint list in the ctor.
 +									for ( int i=0; i<jointCnt; ++i, ++jointIt )
 +									{
 +										//Build a joint for the resolver to work with
 +										char str[64]={0};
 +										sprintf(str,"./%s",(*jointIt).second.c_str() );
 +										//llwarns<<"Joint "<< str <<llendl;
 +
 +										//Setup the resolver
 +                                        daeSIDResolver resolver( pSkeletonRootNode, str );
 +
 +                                        //Look for the joint
 +                                        domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() );
 +                                        if ( pJoint )
 +                                        {
 +											//Pull out the translate id and store it in the jointTranslations map
 +											daeSIDResolver jointResolver( pJoint, "./translate" );
 +											domTranslate* pTranslate = daeSafeCast<domTranslate>( jointResolver.getElement() );
 +
 +											LLMatrix4 workingTransform;
 +
 +											//Translation via SID
 +											if ( pTranslate )
 +											{
 +												extractTranslation( pTranslate, workingTransform );
 +											}
 +											else
 +											{
 +												//Translation via child from element
 +												daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" );
 +												if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() )
 +												{
 +													llwarns<< "The found element is not a translate node" <<llendl;
 +													missingSkeletonOrScene = true;
 +												}
 +												else
 +												{
 +													extractTranslationViaElement( pTranslateElement, workingTransform );
 +												}
 +											}
 +
 +											//Store the joint transform w/respect to it's name.
 +											jointTransforms[(*jointIt).second.c_str()] = workingTransform;
 +                                        }
 +									}
 +
 +									//If anything failed in regards to extracting the skeleton, joints or translation id,
 +									//mention it
 +									if ( missingSkeletonOrScene  )
 +									{
 +										llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl;
 +									}
 +								}//got skeleton?
 +							}
 +
 +							if ( !missingSkeletonOrScene )
 +							{
 +								//Set the joint translations on the avatar
 +								//The joints are reset in the dtor
 +								const int jointCnt = mJointMap.size();
 +								std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin();
 +								for ( int i=0; i<jointCnt; ++i, ++jointIt )
 +								{
 +									std::string lookingForJoint = (*jointIt).first.c_str();
 +									if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() )
 +									{
 +										LLMatrix4 jointTransform = jointTransforms[lookingForJoint];
 +										LLJoint* pJoint = gAgentAvatarp->getJoint( lookingForJoint );
 +										if ( pJoint )
 +										{
 +											pJoint->storeCurrentXform( jointTransform.getTranslation() );
 +										}
 +										else
 +										{
 +											//Most likely an error in the asset.
 +											llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl;
 +										}
 +										//Reposition the avatars pelvis (avPos+offset)
 +										//if ( lookingForJoint == "mPelvis" )
 +										//{
 +										//	const LLVector3& pos = gAgentAvatarp->getCharacterPosition();
 +										//	gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() );
 +										//	gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() );
 +										//}
 +									}
 +								}
 +							} //missingSkeletonOrScene
 +
 +							domSkin::domJoints* joints = skin->getJoints();
 +
 +							domInputLocal_Array& joint_input = joints->getInput_array();
 +
 +							for (size_t i = 0; i < joint_input.getCount(); ++i)
 +							{
 +								domInputLocal* input = joint_input.get(i);
 +								xsNMTOKEN semantic = input->getSemantic();
 +
 +								if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0)
 +								{ //found joint source, fill model->mJointMap and model->mJointList
 +									daeElement* elem = input->getSource().getElement();
 +
 +									domSource* source = daeSafeCast<domSource>(elem);
 +									if (source)
 +									{
 +
 +
 +										domName_array* names_source = source->getName_array();
 +
 +										if (names_source)
 +										{
 +											domListOfNames &names = names_source->getValue();
 +
 +											for (size_t j = 0; j < names.getCount(); ++j)
 +											{
 +												std::string name(names.get(j));
 +												if (mJointMap.find(name) != mJointMap.end())
 +												{
 +													name = mJointMap[name];
 +												}
 +												model->mJointList.push_back(name);
 +												model->mJointMap[name] = j;
 +											}
 +										}
 +										else
 +										{
 +											domIDREF_array* names_source = source->getIDREF_array();
 +											if (names_source)
 +											{
 +												xsIDREFS& names = names_source->getValue();
 +
 +												for (size_t j = 0; j < names.getCount(); ++j)
 +												{
 +													std::string name(names.get(j).getID());
 +													if (mJointMap.find(name) != mJointMap.end())
 +													{
 +														name = mJointMap[name];
 +													}
 +													model->mJointList.push_back(name);
 +													model->mJointMap[name] = j;
 +												}
 +											}
 +										}
 +									}
 +								}
 +								else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0)
 +								{ //found inv_bind_matrix array, fill model->mInvBindMatrix
 +									domSource* source = daeSafeCast<domSource>(input->getSource().getElement());
 +									if (source)
 +									{
 +										domFloat_array* t = source->getFloat_array();
 +										if (t)
 +										{
 +											domListOfFloats& transform = t->getValue();
 +											S32 count = transform.getCount()/16;
 +
 +											for (S32 k = 0; k < count; ++k)
 +											{
 +												LLMatrix4 mat;
 +
 +												for (int i = 0; i < 4; i++)
 +												{
 +													for(int j = 0; j < 4; j++)
 +													{
 +														mat.mMatrix[i][j] = transform[k*16 + i + j*4];
 +													}
 +												}
 +
 +												model->mInvBindMatrix.push_back(mat);
 +											}
 +										}
 +									}
 +								}
 +							}
 +
 +							//We need to construct the alternate bind matrix (which contains the new joint positions)
 +							//in the same order as they were stored in the joint buffer. The joints associated
 +							//with the skeleton are not stored in the same order as they are in the exported joint buffer.
 +							//This remaps the skeletal joints to be in the same order as the joints stored in the model.
 +							std::vector<std::string> :: const_iterator jointIt  = model->mJointList.begin();
 +							const int jointCnt = model->mJointList.size();
 +							for ( int i=0; i<jointCnt; ++i, ++jointIt )
 +							{
 +								std::string lookingForJoint = (*jointIt).c_str();
 +								//Look for the joint xform that we extracted from the skeleton, using the jointIt as the key
 +								//and store it in the alternate bind matrix
 +								if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() )
 +								{
 +									LLMatrix4 jointTransform = jointTransforms[lookingForJoint];
 +									LLMatrix4 newInverse = model->mInvBindMatrix[i];
 +									newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() );
 +									model->mAlternateBindMatrix.push_back( newInverse );
 +								}
 +								else
 +								{
 +									llwarns<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<llendl;
 +								}
 +							}
 +
 +							//grab raw position array
 +
 +							domVertices* verts = mesh->getVertices();
 +							if (verts)
 +							{
 +								domInputLocal_Array& inputs = verts->getInput_array();
 +								for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i)
 +								{
 +									if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0)
 +									{
 +										domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
 +										if (pos_source)
 +										{
 +											domFloat_array* pos_array = pos_source->getFloat_array();
 +											if (pos_array)
 +											{
 +												domListOfFloats& pos = pos_array->getValue();
 +
 +												for (size_t j = 0; j < pos.getCount(); j += 3)
 +												{
 +													if (pos.getCount() <= j+2)
 +													{
 +														llerrs << "WTF?" << llendl;
 +													}
 +
 +													LLVector3 v(pos[j], pos[j+1], pos[j+2]);
 +
 +													//transform from COLLADA space to volume space
 +													v = v * inverse_normalized_transformation;
 +
 +													model->mPosition.push_back(v);
 +												}
 +											}
 +										}
 +									}
 +								}
 +							}
 +
 +							//grab skin weights array
 +							domSkin::domVertex_weights* weights = skin->getVertex_weights();
 +							if (weights)
 +							{
 +								domInputLocalOffset_Array& inputs = weights->getInput_array();
 +								domFloat_array* vertex_weights = NULL;
 +								for (size_t i = 0; i < inputs.getCount(); ++i)
 +								{
 +									if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0)
 +									{
 +										domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
 +										if (weight_source)
 +										{
 +											vertex_weights = weight_source->getFloat_array();
 +										}
 +									}
 +								}
 +
 +								if (vertex_weights)
 +								{
 +									domListOfFloats& w = vertex_weights->getValue();
 +									domListOfUInts& vcount = weights->getVcount()->getValue();
 +									domListOfInts& v = weights->getV()->getValue();
 +
 +									U32 c_idx = 0;
 +									for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx)
 +									{ //for each vertex
 +										daeUInt count = vcount[vc_idx];
 +
 +										//create list of weights that influence this vertex
 +										LLModel::weight_list weight_list;
 +
 +										for (daeUInt i = 0; i < count; ++i)
 +										{ //for each weight
 +											daeInt joint_idx = v[c_idx++];
 +											daeInt weight_idx = v[c_idx++];
 +
 +											if (joint_idx == -1)
 +											{
 +												//ignore bindings to bind_shape_matrix
 +												continue;
 +											}
 +
 +											F32 weight_value = w[weight_idx];
 +
 +											weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value));
 +										}
 +
 +										//sort by joint weight
 +										std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater());
 +
 +										std::vector<LLModel::JointWeight> wght;
 +
 +										F32 total = 0.f;
 +
 +										for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i)
 +										{ //take up to 4 most significant weights
 +											if (weight_list[i].mWeight > 0.f)
 +											{
 +												wght.push_back( weight_list[i] );
 +												total += weight_list[i].mWeight;
 +											}
 +										}
 +
 +										F32 scale = 1.f/total;
 +										if (scale != 1.f)
 +										{ //normalize weights
 +											for (U32 i = 0; i < wght.size(); ++i)
 +											{
 +												wght[i].mWeight *= scale;
 +											}
 +										}
 +
 +										model->mSkinWeights[model->mPosition[vc_idx]] = wght;
 +									}
 +
 +									//add instance to scene for this model
 +
 +									LLMatrix4 transformation = mTransform;
 +									// adjust the transformation to compensate for mesh normalization
 +									
 +									LLMatrix4 mesh_translation;
 +									mesh_translation.setTranslation(mesh_translation_vector);
 +									mesh_translation *= transformation;
 +									transformation = mesh_translation;
 +
 +									LLMatrix4 mesh_scale;
 +									mesh_scale.initScale(mesh_scale_vector);
 +									mesh_scale *= transformation;
 +									transformation = mesh_scale;
 +
 +									std::vector<LLImportMaterial> materials;
 +									materials.resize(model->getNumVolumeFaces());
 +									mScene[transformation].push_back(LLModelInstance(model, transformation, materials));
 +									stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
 +								}
 +							}
 +						}
 +					}
 +				}
 +			}
 +		}
 +
 +		daeElement* scene = root->getDescendant("visual_scene");
 +
 +		if (!scene)
 +		{
 +			llwarns << "document has no visual_scene" << llendl;
 +			setLoadState( ERROR_PARSING );
 +			return;
 +		}
 +
 +		processElement(scene);
 +
 +		doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod));
 +	}
 +}
 +
 +//called in the main thread
 +void LLModelLoader::loadTextures()
 +{
 +	BOOL is_paused = isPaused() ;
 +	pause() ; //pause the loader 
 +
 +	for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
 +	{
 +		for(U32 i = 0 ; i < iter->second.size(); i++)
 +		{
 +			for(U32 j = 0 ; j < iter->second[i].mMaterial.size() ; j++)
 +			{
 +				if(!iter->second[i].mMaterial[j].mDiffuseMapFilename.empty())
 +				{
 +					iter->second[i].mMaterial[j].mDiffuseMap = 
 +						LLViewerTextureManager::getFetchedTextureFromUrl("file://" + iter->second[i].mMaterial[j].mDiffuseMapFilename, TRUE, LLViewerTexture::BOOST_PREVIEW);
 +					iter->second[i].mMaterial[j].mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE);
 +					iter->second[i].mMaterial[j].mDiffuseMap->forceToSaveRawImage();
 +				}
 +			}
 +		}
 +	}
 +
 +	if(!is_paused)
 +	{
 +		unpause() ;
 +	}
 +}
 +
 +bool LLModelLoader::isNodeAJoint( domNode* pNode )
 +{
 +	if ( pNode->getName() == NULL)
 +	{
 +		return false;
 +	}
 +
 +	if ( mJointMap.find( pNode->getName() )  != mJointMap.end() )
 +	{
 +		return true;
 +	}
 +
 +	return false;
 +}
 +
 +void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform )
 +{
 +	domFloat3 jointTrans = pTranslate->getValue();
 +	LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] );
 +	transform.setTranslation( singleJointTranslation );
 +}
 +
 +void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform )
 +{
 +	domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement );
 +	domFloat3 translateChild = pTranslateChild->getValue();
 +	LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] );
 +	transform.setTranslation( singleJointTranslation );
 +}
 +
 +void LLModelLoader::processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms )
 +{
 +	if (pNode->getName() == NULL)
 +	{
 +		llwarns << "nameless node, can't process" << llendl;
 +		return;
 +	}
 +
 +	//llwarns<<"ProcessJointNode# Node:" <<pNode->getName()<<llendl;
 +
 +	//1. handle the incoming node - extract out translation via SID or element
 +
 +	LLMatrix4 workingTransform;
 +
 +	//Pull out the translate id and store it in the jointTranslations map
 +	daeSIDResolver jointResolver( pNode, "./translate" );
 +	domTranslate* pTranslate = daeSafeCast<domTranslate>( jointResolver.getElement() );
 +
 +	//Translation via SID was successful
 +	if ( pTranslate )
 +	{
 +		extractTranslation( pTranslate, workingTransform );
 +	}
 +	else
 +	{
 +		//Translation via child from element
 +		daeElement* pTranslateElement = getChildFromElement( pNode, "translate" );
 +		if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() )
 +		{
 +			llwarns<< "The found element is not a translate node" <<llendl;
 +		}
 +		else
 +		{
 +			extractTranslationViaElement( pTranslateElement, workingTransform );
 +		}
 +	}
 +
 +	//Store the working transform relative to the nodes name.
 +	jointTransforms[ pNode->getName() ] = workingTransform;
 +
 +	//2. handle the nodes children
 +
 +	//Gather and handle the incoming nodes children
 +	daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren();
 +	S32 childOfChildCount = childOfChild.getCount();
 +
 +	for (S32 i = 0; i < childOfChildCount; ++i)
 +	{
 +		domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
 +		if ( pChildNode )
 +		{
 +			processJointNode( pChildNode, jointTransforms );
 +		}
 +	}
 +}
 +
 +daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name )
 +{
 +    daeElement* pChildOfElement = pElement->getChild( name.c_str() );
 +	if ( pChildOfElement )
 +	{
 +		return pChildOfElement;
 +	}
 +	llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl;
 +    return NULL;
 +}
 +
 +void LLModelLoader::processElement(daeElement* element)
 +{
 +	LLMatrix4 saved_transform = mTransform;
 +
 +	domTranslate* translate = daeSafeCast<domTranslate>(element);
 +	if (translate)
 +	{
 +		domFloat3 dom_value = translate->getValue();
 +
 +		LLMatrix4 translation;
 +		translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2]));
 +
 +		translation *= mTransform;
 +		mTransform = translation;
 +	}
 +
 +	domRotate* rotate = daeSafeCast<domRotate>(element);
 +	if (rotate)
 +	{
 +		domFloat4 dom_value = rotate->getValue();
 +
 +		LLMatrix4 rotation;
 +		rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0));
 +
 +		rotation *= mTransform;
 +		mTransform = rotation;
 +	}
 +
 +	domScale* scale = daeSafeCast<domScale>(element);
 +	if (scale)
 +	{
 +		domFloat3 dom_value = scale->getValue();
 +
 +		LLMatrix4 scaling;
 +		scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2]));
 +
 +		scaling *= mTransform;
 +		mTransform = scaling;
 +	}
 +
 +	domMatrix* matrix = daeSafeCast<domMatrix>(element);
 +	if (matrix)
 +	{
 +		domFloat4x4 dom_value = matrix->getValue();
 +
 +		LLMatrix4 matrix_transform;
 +
 +		for (int i = 0; i < 4; i++)
 +		{
 +			for(int j = 0; j < 4; j++)
 +			{
 +				matrix_transform.mMatrix[i][j] = dom_value[i + j*4];
 +			}
 +		}
 +
 +		matrix_transform *= mTransform;
 +		mTransform = matrix_transform;
 +	}
 +
 +	domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element);
 +	if (instance_geo)
 +	{
 +		domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement());
 +		if (geo)
 +		{
 +			domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID())));
 +			if (mesh)
 +			{
 +				LLModel* model = mModel[mesh];
 +				if (model)
 +				{
 +					LLMatrix4 transformation = mTransform;
 +
 +					std::vector<LLImportMaterial> materials = getMaterials(model, instance_geo);
 +
 +					// adjust the transformation to compensate for mesh normalization
 +					LLVector3 mesh_scale_vector;
 +					LLVector3 mesh_translation_vector;
 +					model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
 +
 +					LLMatrix4 mesh_translation;
 +					mesh_translation.setTranslation(mesh_translation_vector);
 +					mesh_translation *= transformation;
 +					transformation = mesh_translation;
 +
 +					LLMatrix4 mesh_scale;
 +					mesh_scale.initScale(mesh_scale_vector);
 +					mesh_scale *= transformation;
 +					transformation = mesh_scale;
 +
 +					mScene[transformation].push_back(LLModelInstance(model, transformation, materials));
 +
 +					stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
 +				}
 +			}
 +		}
 +	}
 +
 +	domInstance_node* instance_node = daeSafeCast<domInstance_node>(element);
 +	if (instance_node)
 +	{
 +		daeElement* instance = instance_node->getUrl().getElement();
 +		if (instance)
 +		{
 +			processElement(instance);
 +		}
 +	}
 +
 +	//process children
 +	daeTArray< daeSmartRef<daeElement> > children = element->getChildren();
 +	for (S32 i = 0; i < children.getCount(); i++)
 +	{
 +		processElement(children[i]);
 +	}
 +
 +	domNode* node = daeSafeCast<domNode>(element);
 +	if (node)
 +	{ //this element was a node, restore transform before processiing siblings
 +		mTransform = saved_transform;
 +	}
 +}
 +
 +std::vector<LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo)
 +{
 +	std::vector<LLImportMaterial> materials;
 +	for (int i = 0; i < model->mMaterialList.size(); i++)
 +	{
 +		LLImportMaterial import_material;
 +
 +		domInstance_material* instance_mat = NULL;
 +
 +		domBind_material::domTechnique_common* technique =
 +		daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID())));
 +
 +		if (technique)
 +		{
 +			daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>();
 +			for (int j = 0; j < inst_materials.getCount(); j++)
 +			{
 +				std::string symbol(inst_materials[j]->getSymbol());
 +
 +				if (symbol == model->mMaterialList[i]) // found the binding
 +				{
 +					instance_mat = inst_materials[j];
 +				}
 +			}
 +		}
 +
 +		if (instance_mat)
 +		{
 +			domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement());
 +			if (material)
 +			{
 +				domInstance_effect* instance_effect =
 +				daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID())));
 +				if (instance_effect)
 +				{
 +					domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement());
 +					if (effect)
 +					{
 +						domProfile_COMMON* profile =
 +						daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID())));
 +						if (profile)
 +						{
 +							import_material = profileToMaterial(profile);
 +						}
 +					}
 +				}
 +			}
 +		}
 +
 +		materials.push_back(import_material);
 +	}
 +
 +	return materials;
 +}
 +
 +LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material)
 +{
 +	LLImportMaterial mat;
 +	mat.mFullbright = FALSE;
 +
 +	daeElement* diffuse = material->getDescendant("diffuse");
 +	if (diffuse)
 +	{
 +		domCommon_color_or_texture_type_complexType::domTexture* texture =
 +		daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture"));
 +		if (texture)
 +		{
 +			domCommon_newparam_type_Array newparams = material->getNewparam_array();
 +			for (S32 i = 0; i < newparams.getCount(); i++)
 +			{
 +				domFx_surface_common* surface = newparams[i]->getSurface();
 +				if (surface)
 +				{
 +					domFx_surface_init_common* init = surface->getFx_surface_init_common();
 +					if (init)
 +					{
 +						domFx_surface_init_from_common_Array init_from = init->getInit_from_array();
 +
 +						if (init_from.getCount() > i)
 +						{
 +							domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement());
 +							if (image)
 +							{
 +								// we only support init_from now - embedded data will come later
 +								domImage::domInit_from* init = image->getInit_from();
 +								if (init)
 +								{									
 +									mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str());
 +									mat.mDiffuseMapLabel = getElementLabel(material);
 +								}
 +							}
 +						}
 +					}
 +				}
 +			}
 +		}
 +
 +		domCommon_color_or_texture_type_complexType::domColor* color =
 +		daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color"));
 +		if (color)
 +		{
 +			domFx_color_common domfx_color = color->getValue();
 +			LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
 +			mat.mDiffuseColor = value;
 +		}
 +	}
 +
 +	daeElement* emission = material->getDescendant("emission");
 +	if (emission)
 +	{
 +		LLColor4 emission_color = getDaeColor(emission);
 +		if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25)
 +		{
 +			mat.mFullbright = TRUE;
 +		}
 +	}
 +
 +	return mat;
 +}
 +
 +// try to get a decent label for this element
 +std::string LLModelLoader::getElementLabel(daeElement *element)
 +{
 +	// if we have a name attribute, use it
 +	std::string name = element->getAttribute("name");
 +	if (name.length())
 +	{
 +		return name;
 +	}
 +
 +	// if we have an ID attribute, use it
 +	if (element->getID())
 +	{
 +		return std::string(element->getID());
 +	}
 +
 +	// if we have a parent, use it
 +	daeElement* parent = element->getParent();
 +	if (parent)
 +	{
 +		// if parent has a name, use it
 +		std::string name = parent->getAttribute("name");
 +		if (name.length())
 +		{
 +			return name;
 +		}
 +
 +		// if parent has an ID, use it
 +		if (parent->getID())
 +		{
 +			return std::string(parent->getID());
 +		}
 +	}
 +
 +	// try to use our type
 +	daeString element_name = element->getElementName();
 +	if (element_name)
 +	{
 +		return std::string(element_name);
 +	}
 +
 +	// if all else fails, use "object"
 +	return std::string("object");
 +}
 +
 +LLColor4 LLModelLoader::getDaeColor(daeElement* element)
 +{
 +	LLColor4 value;
 +	domCommon_color_or_texture_type_complexType::domColor* color =
 +	daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color"));
 +	if (color)
 +	{
 +		domFx_color_common domfx_color = color->getValue();
 +		value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
 +	}
 +
 +	return value;
 +}
 +
 +//-----------------------------------------------------------------------------
 +// LLModelPreview
 +//-----------------------------------------------------------------------------
 +
 +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
 +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL)
 +{
 +	mNeedsUpdate = TRUE;
 +	mCameraDistance = 0.f;
 +	mCameraYaw = 0.f;
 +	mCameraPitch = 0.f;
 +	mCameraZoom = 1.f;
 +	mTextureName = 0;
 +	mPreviewLOD = 0;
 +	mModelLoader = NULL;
 +	mMaxTriangleLimit = 0;
 +	mDirty = false;
 +	mGenLOD = false;
 +	mLoading = false;
 +	mGroup = 0;
 +	mBuildShareTolerance = 0.f;
 +	mBuildQueueMode = GLOD_QUEUE_GREEDY;
 +	mBuildBorderMode = GLOD_BORDER_UNLOCK;
 +	mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE;
 +
 +	mViewOption["show_textures"] = false;
 +
 +	mFMP = fmp;
 +
 +	glodInit();
 +}
 +
 +LLModelPreview::~LLModelPreview()
 +{
 +	if (mModelLoader)
 +	{
 +		delete mModelLoader;
 +		mModelLoader = NULL;
 +	}
 +
 +	//*HACK : *TODO : turn this back on when we understand why this crashes
 +	//glodShutdown();
 +}
 +
 +U32 LLModelPreview::calcResourceCost()
 +{
 +	assert_main_thread();
 +
 +	rebuildUploadData();
 +
 +	if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING )
 +	{
 +		mFMP->childEnable("ok_btn");
 +	}
 +
 +	U32 cost = 0;
 +	std::set<LLModel*> accounted;
 +	U32 num_points = 0;
 +	U32 num_hulls = 0;
 +
 +	F32 debug_scale = mFMP->childGetValue("import_scale").asReal();
 +
 +	F32 streaming_cost = 0.f;
 +	F32 physics_cost = 0.f;
 +	for (U32 i = 0; i < mUploadData.size(); ++i)
 +	{
 +		LLModelInstance& instance = mUploadData[i];
 +
 +		if (accounted.find(instance.mModel) == accounted.end())
 +		{
 +			accounted.insert(instance.mModel);
 +
 +			LLModel::convex_hull_decomposition& decomp =
 +			instance.mLOD[LLModel::LOD_PHYSICS] ?
 +			instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp :
 +			instance.mModel->mConvexHullDecomp;
 +
 +			LLSD ret = LLModel::writeModel(
 +										   "",
 +										   instance.mLOD[4],
 +										   instance.mLOD[3],
 +										   instance.mLOD[2],
 +										   instance.mLOD[1],
 +										   instance.mLOD[0],
 +										   decomp,
 +										   mFMP->childGetValue("upload_skin").asBoolean(),
 +										   mFMP->childGetValue("upload_joints").asBoolean(),
 +										   TRUE);
 +			cost += gMeshRepo.calcResourceCost(ret);
 +
 +			num_hulls += decomp.size();
 +			for (U32 i = 0; i < decomp.size(); ++i)
 +			{
 +				num_points += decomp[i].size();
 +			}
 +
 +			//calculate streaming cost
 +			LLMatrix4 transformation = instance.mTransform;
 +
 +			LLVector3 position = LLVector3(0, 0, 0) * transformation;
 +
 +			LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position;
 +			LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position;
 +			LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position;
 +			F32 x_length = x_transformed.normalize();
 +			F32 y_length = y_transformed.normalize();
 +			F32 z_length = z_transformed.normalize();
 +			LLVector3 scale = LLVector3(x_length, y_length, z_length);
 +
 +			F32 radius = scale.length()*debug_scale;
 +
 +			streaming_cost += LLMeshRepository::getStreamingCost(ret, radius);
 +		}
 +	}
 +
 +	//mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls));
 +	//mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points));
 +	mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost));
 +	mFMP->childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost));	
 +	F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f;
 +	mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale));
 +	mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale));
 +	mFMP->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale));
 +
 +	updateStatusMessages();
 +
 +	return cost;
 +}
 +
 +void LLModelPreview::rebuildUploadData()
 +{
 +	assert_main_thread();
 +
 +	mUploadData.clear();
 +	mTextureSet.clear();
 +
 +	//fill uploaddata instance vectors from scene data
 +
 +	std::string requested_name = mFMP->getChild<LLUICtrl>("description_form")->getValue().asString();
 +
 +
 +	LLSpinCtrl* scale_spinner = mFMP->getChild<LLSpinCtrl>("import_scale");
 +
 +	if (!scale_spinner)
 +	{
 +		llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl;
 +	}
 +
 +	F32 scale = scale_spinner->getValue().asReal();
 +
 +	LLMatrix4 scale_mat;
 +	scale_mat.initScale(LLVector3(scale, scale, scale));
 +
 +	F32 max_scale = 0.f;
 +
 +	if ( mBaseScene.size() > 0 )
 +	{
 +		mFMP->childEnable("ok_btn");
 +	}
 +
 +	for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter)
 +	{ //for each transform in scene
 +		LLMatrix4 mat = iter->first;
 +
 +		// compute position
 +		LLVector3 position = LLVector3(0, 0, 0) * mat;
 +
 +		// compute scale
 +		LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position;
 +		LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position;
 +		LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position;
 +		F32 x_length = x_transformed.normalize();
 +		F32 y_length = y_transformed.normalize();
 +		F32 z_length = z_transformed.normalize();
 +
 +		max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length);
 +
 +		mat *= scale_mat;
 +
 +		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
 +		{ //for each instance with said transform applied
 +			LLModelInstance instance = *model_iter;
 +
 +			LLModel* base_model = instance.mModel;
 +			if (base_model)
 +			{
 +				base_model->mRequestedLabel = requested_name;
 +			}
 +
 +			S32 idx = 0;
 +			for (idx = 0; idx < mBaseModel.size(); ++idx)
 +			{  //find reference instance for this model
 +				if (mBaseModel[idx] == base_model)
 +				{
 +					break;
 +				}
 +			}
 +
 +			for (U32 i = 0; i < LLModel::NUM_LODS; i++)
 +			{ //fill LOD slots based on reference model index
 +				if (!mModel[i].empty())
 +				{
 +					instance.mLOD[i] = mModel[i][idx];
 +				}
 +				else
 +				{
 +					instance.mLOD[i] = NULL;
 +				}
 +			}
 +
 +			instance.mTransform = mat;
 +			mUploadData.push_back(instance);
 +		}
 +	}
 +
 +	F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale;
 +
 +	scale_spinner->setMaxValue(max_import_scale);
 +
 +	if (max_import_scale < scale)
 +	{
 +		scale_spinner->setValue(max_import_scale);
 +	}
 +
 +}
 +
 +
 +void LLModelPreview::clearModel(S32 lod)
 +{
 +	if (lod < 0 || lod > LLModel::LOD_PHYSICS)
 +	{
 +		return;
 +	}
 +
 +	mVertexBuffer[lod].clear();
 +	mModel[lod].clear();
 +	mScene[lod].clear();
 +}
 +
 +void LLModelPreview::loadModel(std::string filename, S32 lod)
 +{
 +	assert_main_thread();
 +
 +	LLMutexLock lock(this);
 +
 +	if (mModelLoader)
 +	{
 +		delete mModelLoader;
 +		mModelLoader = NULL;
 +	}
 +
 +	if (filename.empty())
 +	{
 +		if (mBaseModel.empty())
 +		{
 +			// this is the initial file picking. Close the whole floater
 +			// if we don't have a base model to show for high LOD.
 +			mFMP->closeFloater(false);
 +		}
 +
 +		mLoading = false;
 +		return;
 +	}
 +
 +	mLODFile[lod] = filename;
 +
 +	if (lod == LLModel::LOD_HIGH)
 +	{
 +		clearGLODGroup();
 +	}
 +
 +	mModelLoader = new LLModelLoader(filename, lod, this);
 +
 +	mModelLoader->start();
 +
 +	mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file"));
 +
 +	setPreviewLOD(lod);
 +
 +	if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING )
 +	{
 +		mFMP->childDisable("ok_btn");
 +	}
 +
 +	if (lod == mPreviewLOD)
 +	{
 +		mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]);
 +	}
 +	else if (lod == LLModel::LOD_PHYSICS)
 +	{
 +		mFMP->childSetText("physics_file", mLODFile[lod]);
 +	}
 +
 +	mFMP->openFloater();
 +}
 +
 +void LLModelPreview::setPhysicsFromLOD(S32 lod)
 +{
 +	assert_main_thread();
 +
 +	if (lod >= 0 && lod <= 3)
 +	{
 +		mModel[LLModel::LOD_PHYSICS] = mModel[lod];
 +		mScene[LLModel::LOD_PHYSICS] = mScene[lod];
 +		mLODFile[LLModel::LOD_PHYSICS].clear();
 +		mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]);
 +		mVertexBuffer[LLModel::LOD_PHYSICS].clear();
 +		rebuildUploadData();
 +		refresh();
 +		updateStatusMessages();
 +	}
 +}
 +
 +void LLModelPreview::clearIncompatible(S32 lod)
 +{
 +	for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
 +	{ //clear out any entries that aren't compatible with this model
 +		if (i != lod)
 +		{
 +			if (mModel[i].size() != mModel[lod].size())
 +			{
 +				mModel[i].clear();
 +				mScene[i].clear();
 +				mVertexBuffer[i].clear();
 +
 +				if (i == LLModel::LOD_HIGH)
 +				{
 +					mBaseModel = mModel[lod];
 +					clearGLODGroup();
 +					mBaseScene = mScene[lod];
 +					mVertexBuffer[5].clear();
 +				}
 +			}
 +		}
 +	}
 +}
 +
 +void LLModelPreview::clearGLODGroup()
 +{
 +	if (mGroup)
 +	{
 +		for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter)
 +		{
 +			glodDeleteObject(iter->second);
 +			stop_gloderror();
 +		}
 +		mObject.clear();
 +
 +		glodDeleteGroup(mGroup);
 +		stop_gloderror();
 +		mGroup = 0;
 +	}
 +}
 +
 +void LLModelPreview::loadModelCallback(S32 lod)
 +{
 +	assert_main_thread();
 +
 +	LLMutexLock lock(this);
 +	if (!mModelLoader)
 +	{
 +		return;
 +	}
 +
 +	mModelLoader->loadTextures() ;
 +	mModel[lod] = mModelLoader->mModelList;
 +	mScene[lod] = mModelLoader->mScene;
 +	mVertexBuffer[lod].clear();
 +
 +	if (lod == LLModel::LOD_PHYSICS)
 +	{
 +		mPhysicsMesh.clear();
 +	}
 +
 +	setPreviewLOD(lod);
 +
 +
 +	if (lod == LLModel::LOD_HIGH)
 +	{ //save a copy of the highest LOD for automatic LOD manipulation
 +		if (mBaseModel.empty())
 +		{ //first time we've loaded a model, auto-gen LoD
 +			mGenLOD = true;
 +		}
 +
 +		mBaseModel = mModel[lod];
 +		clearGLODGroup();
 +
 +		mBaseScene = mScene[lod];
 +		mVertexBuffer[5].clear();
 +	}
 +
 +	clearIncompatible(lod);
 +
 +	mDirty = true;
 +
 +	if (lod == LLModel::LOD_HIGH)
 +	{
 +		resetPreviewTarget();
 +	}
 +
 +	mLoading = false;
 +	refresh();
 +}
 +
 +void LLModelPreview::resetPreviewTarget()
 +{
 +	mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f;
 +	mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f;
 +	setPreviewTarget(mPreviewScale.magVec()*2.f);
 +}
 +
 +void LLModelPreview::generateNormals()
 +{
 +	assert_main_thread();
 +
 +	S32 which_lod = mPreviewLOD;
 +
 +
 +	if (which_lod > 4 || which_lod < 0 ||
 +		mModel[which_lod].empty())
 +	{
 +		return;
 +	}
 +
 +	F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal();
 +
 +	angle_cutoff *= DEG_TO_RAD;
 +
 +	if (which_lod == 3 && !mBaseModel.empty())
 +	{
 +		for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
 +		{
 +			(*iter)->generateNormals(angle_cutoff);
 +		}
 +
 +		mVertexBuffer[5].clear();
 +	}
 +
 +	for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter)
 +	{
 +		(*iter)->generateNormals(angle_cutoff);
 +	}
 +
 +	mVertexBuffer[which_lod].clear();
 +	refresh();
 +
 +}
 +
 +void LLModelPreview::consolidate()
 +{
 +	std::map<LLImportMaterial, std::vector<LLModelInstance> > composite;
 +
 +	LLMatrix4 identity;
 +
 +	//bake out each node in current scene to composite
 +	for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
 +	{ //for each transform in current scene
 +		LLMatrix4 mat = iter->first;
 +		glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose();
 +		LLMatrix4 norm_mat(inv_trans.m);
 +
 +		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
 +		{ //for each instance with that transform
 +			LLModelInstance& source_instance = *model_iter;
 +			LLModel* source = source_instance.mModel;
 +
 +			if (!validate_model(source))
 +			{
 +				llerrs << "Invalid model found!" << llendl;
 +			}
 +
 +			for (S32 i = 0; i < source->getNumVolumeFaces(); ++i)
 +			{ //for each face in instance
 +				const LLVolumeFace& src_face = source->getVolumeFace(i);
 +				LLImportMaterial& source_material = source_instance.mMaterial[i];
 +
 +				//get model in composite that is composite for this material
 +				LLModel* model = NULL;
 +
 +				if (composite.find(source_material) != composite.end())
 +				{
 +					model = composite[source_material].rbegin()->mModel;
 +					if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535)
 +					{
 +						model = NULL;
 +					}
 +				}
 +
 +				if (model == NULL)
 +				{  //no model found, make new model
 +					std::vector<LLImportMaterial> materials;
 +					materials.push_back(source_material);
 +					LLVolumeParams volume_params;
 +					volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
 +					model = new LLModel(volume_params, 0.f);
 +					model->mLabel = source->mLabel;
 +					model->setNumVolumeFaces(0);
 +					composite[source_material].push_back(LLModelInstance(model, identity, materials));
 +				}
 +
 +				model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat);
 +			}
 +		}
 +	}
 +
 +
 +	//condense composite into as few LLModel instances as possible
 +	LLModelLoader::model_list new_model;
 +	std::vector<LLModelInstance> instance_list;
 +
 +	LLVolumeParams volume_params;
 +	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
 +
 +	std::vector<LLImportMaterial> empty_material;
 +	LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material);
 +	cur_instance.mModel->setNumVolumeFaces(0);
 +
 +	BOOL first_transform = TRUE;
 +
 +	LLModelLoader::scene new_scene;
 +	LLVector3 min,max;
 +
 +	for (std::map<LLImportMaterial, std::vector<LLModelInstance> >::iterator iter = composite.begin();
 +		 iter != composite.end();
 +		 ++iter)
 +	{
 +		std::map<LLImportMaterial, std::vector<LLModelInstance> >::iterator next_iter = iter; ++next_iter;
 +
 +		for (std::vector<LLModelInstance>::iterator instance_iter = iter->second.begin();
 +			 instance_iter != iter->second.end();
 +			 ++instance_iter)
 +		{
 +			LLModel* source = instance_iter->mModel;
 +
 +			if (instance_iter->mMaterial.size() != 1)
 +			{
 +				llerrs << "WTF?" << llendl;
 +			}
 +
 +			if (source->getNumVolumeFaces() != 1)
 +			{
 +				llerrs << "WTF?" << llendl;
 +			}
 +
 +			if (source->mMaterialList.size() != 1)
 +			{
 +				llerrs << "WTF?" << llendl;
 +			}
 +
 +			cur_instance.mModel->addFace(source->getVolumeFace(0));
 +			cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]);
 +			cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]);
 +
 +			BOOL last_model = FALSE;
 +
 +			std::vector<LLModelInstance>::iterator next_instance = instance_iter; ++next_instance;
 +
 +			if (next_iter == composite.end() &&
 +				next_instance == iter->second.end())
 +			{
 +				last_model = TRUE;
 +			}
 +
 +			if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES)
 +			{
 +				cur_instance.mModel->mLabel = source->mLabel;
 +
 +				cur_instance.mModel->optimizeVolumeFaces();
 +				cur_instance.mModel->normalizeVolumeFaces();
 +
 +				if (!validate_model(cur_instance.mModel))
 +				{
 +					llerrs << "Invalid model detected." << llendl;
 +				}
 +
 +				new_model.push_back(cur_instance.mModel);
 +
 +				LLMatrix4 transformation = LLMatrix4();
 +
 +				// adjust the transformation to compensate for mesh normalization
 +				LLVector3 mesh_scale_vector;
 +				LLVector3 mesh_translation_vector;
 +				cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
 +
 +				LLMatrix4 mesh_translation;
 +				mesh_translation.setTranslation(mesh_translation_vector);
 +				mesh_translation *= transformation;
 +				transformation = mesh_translation;
 +
 +				LLMatrix4 mesh_scale;
 +				mesh_scale.initScale(mesh_scale_vector);
 +				mesh_scale *= transformation;
 +				transformation = mesh_scale;
 +
 +				cur_instance.mTransform = transformation;
 +
 +				new_scene[transformation].push_back(cur_instance);
 +				stretch_extents(cur_instance.mModel, transformation, min, max, first_transform);
 +
 +				if (!last_model)
 +				{
 +					cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material);
 +					cur_instance.mModel->setNumVolumeFaces(0);
 +				}
 +			}
 +		}
 +	}
 +
 +	mScene[mPreviewLOD] = new_scene;
 +	mModel[mPreviewLOD] = new_model;
 +	mVertexBuffer[mPreviewLOD].clear();
 +
 +	if (mPreviewLOD == LLModel::LOD_HIGH)
 +	{
 +		mBaseScene = new_scene;
 +		mBaseModel = new_model;
 +		clearGLODGroup();
 +		mVertexBuffer[5].clear();
 +	}
 +
 +	mPreviewTarget = (min+max)*0.5f;
 +	mPreviewScale = (max-min)*0.5f;
 +	setPreviewTarget(mPreviewScale.magVec()*2.f);
 +
 +	clearIncompatible(mPreviewLOD);
 +
 +	mResourceCost = calcResourceCost();
 +	refresh();
 +}
 +
 +void LLModelPreview::clearMaterials()
 +{
 +	for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
 +	{ //for each transform in current scene
 +		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
 +		{ //for each instance with that transform
 +			LLModelInstance& source_instance = *model_iter;
 +			LLModel* source = source_instance.mModel;
 +
 +			for (S32 i = 0; i < source->getNumVolumeFaces(); ++i)
 +			{ //for each face in instance
 +				LLImportMaterial& source_material = source_instance.mMaterial[i];
 +
 +				//clear material info
 +				source_material.mDiffuseColor = LLColor4(1,1,1,1);
 +				source_material.mDiffuseMap = NULL;
 +				source_material.mDiffuseMapFilename.clear();
 +				source_material.mDiffuseMapLabel.clear();
 +				source_material.mFullbright = false;
 +			}
 +		}
 +	}
 +
 +	mVertexBuffer[mPreviewLOD].clear();
 +
 +	if (mPreviewLOD == LLModel::LOD_HIGH)
 +	{
 +		mBaseScene = mScene[mPreviewLOD];
 +		mBaseModel = mModel[mPreviewLOD];
 +		clearGLODGroup();
 +		mVertexBuffer[5].clear();
 +	}
 +
 +	mResourceCost = calcResourceCost();
 +	refresh();
 +}
 +
 +bool LLModelPreview::containsRiggedAsset( void )
 +{
 +	//loop through the models and determine if any of them contained a rigged asset, and if so
 +	//return true.
 +	//This is used to cleanup the joint positions after a preview.
 +	for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
 +	{
 +		LLModel* pModel = *iter;
 +		if ( pModel->mAlternateBindMatrix.size() > 0 )
 +		{
 +			return true;
 +		}
 +	}
 +	return false;
 +}
 +void LLModelPreview::genLODs(S32 which_lod, U32 decimation)
 +{
 +	if (mBaseModel.empty())
 +	{
 +		return;
 +	}
 +
 +	if (which_lod == LLModel::LOD_PHYSICS)
 +	{ //clear physics mesh map
 +		mPhysicsMesh.clear();
 +	}
 +
 +	LLVertexBuffer::unbind();
 +
 +	stop_gloderror();
 +	static U32 cur_name = 1;
 +
 +	S32 limit = -1;
 +
 +	U32 triangle_count = 0;
 +
 +	for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
 +	{
 +		LLModel* mdl = *iter;
 +		for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
 +		{
 +			triangle_count += mdl->getVolumeFace(i).mNumIndices/3;
 +		}
 +	}
 +
 +	U32 base_triangle_count = triangle_count;
 +
 +	U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
 +
 +	U32 lod_mode = 0;
 +
 +	LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode");
 +	if (iface)
 +	{
 +		lod_mode = iface->getFirstSelectedIndex();
 +	}
 +
 +	F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal();
 +
 +	if (lod_mode == 0)
 +	{
 +		lod_mode = GLOD_TRIANGLE_BUDGET;
 +		if (which_lod != -1)
 +		{
 +			//SH-632 take budget as supplied limit+1 to prevent GLOD from creating a smaller
 +			//decimation when the given decimation is possible
 +			limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); //+1;
 +		}
 +	}
 +	else
 +	{
 +		lod_mode = GLOD_ERROR_THRESHOLD;
 +	}
 +
 +	U32 build_operator = 0;
 +
 +	iface = mFMP->childGetSelectionInterface("build_operator");
 +	if (iface)
 +	{
 +		build_operator = iface->getFirstSelectedIndex();
 +	}
 +
 +	if (build_operator == 0)
 +	{
 +		build_operator = GLOD_OPERATOR_EDGE_COLLAPSE;
 +	}
 +	else
 +	{
 +		build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE;
 +	}
 +
 +	U32 queue_mode=0;
 +	iface = mFMP->childGetSelectionInterface("queue_mode");
 +	if (iface)
 +	{
 +		queue_mode = iface->getFirstSelectedIndex();
 +	}
 +
 +	if (queue_mode == 0)
 +	{
 +		queue_mode = GLOD_QUEUE_GREEDY;
 +	}
 +	else if (queue_mode == 1)
 +	{
 +		queue_mode = GLOD_QUEUE_LAZY;
 +	}
 +	else
 +	{
 +		queue_mode = GLOD_QUEUE_INDEPENDENT;
 +	}
 +
 +	U32 border_mode = 0;
 +
 +	iface = mFMP->childGetSelectionInterface("border_mode");
 +	if (iface)
 +	{
 +		border_mode = iface->getFirstSelectedIndex();
 +	}
 +
 +	if (border_mode == 0)
 +	{
 +		border_mode = GLOD_BORDER_UNLOCK;
 +	}
 +	else
 +	{
 +		border_mode = GLOD_BORDER_LOCK;
 +	}
 +
 +	bool object_dirty = false;
 +	if (border_mode != mBuildBorderMode)
 +	{
 +		mBuildBorderMode = border_mode;
 +		object_dirty = true;
 +	}
 +
 +	if (queue_mode != mBuildQueueMode)
 +	{
 +		mBuildQueueMode = queue_mode;
 +		object_dirty = true;
 +	}
 +
 +	if (build_operator != mBuildOperator)
 +	{
 +		mBuildOperator = build_operator;
 +		object_dirty = true;
 +	}
 +
 +	F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal();
 +	if (share_tolerance != mBuildShareTolerance)
 +	{
 +		mBuildShareTolerance = share_tolerance;
 +		object_dirty = true;
 +	}
 +
 +	if (mGroup == 0)
 +	{
 +		object_dirty = true;
 +		mGroup = cur_name++;
 +		glodNewGroup(mGroup);
 +	}
 +
 +	if (object_dirty)
 +	{
 +		for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
 +		{ //build GLOD objects for each model in base model list
 +			LLModel* mdl = *iter;
 +
 +			if (mObject[mdl] != 0)
 +			{
 +				glodDeleteObject(mObject[mdl]);
 +			}
 +
 +			mObject[mdl] = cur_name++;
 +
 +			glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE);
 +			stop_gloderror();
 +
 +			if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty())
 +			{ //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation
 +				mVertexBuffer[5].clear();
 +			}
 +
 +			if (mVertexBuffer[5].empty())
 +			{
 +				genBuffers(5, false);
 +			}
 +
 +			U32 tri_count = 0;
 +			for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i)
 +			{
 +				mVertexBuffer[5][mdl][i]->setBuffer(type_mask);
 +				U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices();
 +				if (num_indices > 2)
 +				{
 +					glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f);
 +				}
 +				tri_count += num_indices/3;
 +				stop_gloderror();
 +			}
 +
 +			glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator);
 +			stop_gloderror();
 +
 +			glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode);
 +			stop_gloderror();
 +
 +			glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode);
 +			stop_gloderror();
 +
 +			glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance);
 +			stop_gloderror();
 +
 +			glodBuildObject(mObject[mdl]);
 +			stop_gloderror();
 +		}
 +	}
 +
 +
 +	S32 start = LLModel::LOD_HIGH;
 +	S32 end = 0;
 +
 +	if (which_lod != -1)
 +	{
 +		start = end = which_lod;
 +	}
 +	else
 +	{
 +		//SH-632 -- incremenet triangle count to avoid removing any triangles from
 +		//highest LoD when auto-generating LoD
 +		triangle_count++;
 +	}
 +
 +
 +	mMaxTriangleLimit = base_triangle_count;
 +
 +	for (S32 lod = start; lod >= end; --lod)
 +	{
 +		if (which_lod == -1)
 +		{
 +			if (lod < start)
 +			{
 +				triangle_count /= decimation;
 +			}
 +		}
 +		else
 +		{
 +			triangle_count = limit;
 +		}
 +
 +		mModel[lod].clear();
 +		mModel[lod].resize(mBaseModel.size());
 +		mVertexBuffer[lod].clear();
 +
 +		U32 actual_tris = 0;
 +		U32 actual_verts = 0;
 +		U32 submeshes = 0;
 +
 +		glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode);
 +		stop_gloderror();
 +
 +		glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR);
 +		stop_gloderror();
 +
 +		glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count);
 +		stop_gloderror();
 +
 +		glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold);
 +		stop_gloderror();
 +
 +		glodAdaptGroup(mGroup);
 +		stop_gloderror();
 +
 +		for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx)
 +		{
 +			LLModel* base = mBaseModel[mdl_idx];
 +
 +			GLint patch_count = 0;
 +			glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count);
 +			stop_gloderror();
 +
 +			LLVolumeParams volume_params;
 +			volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
 +			mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
 +
 +			GLint* sizes = new GLint[patch_count*2];
 +			glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);
 +			stop_gloderror();
 +
 +			GLint* names = new GLint[patch_count];
 +			glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names);
 +			stop_gloderror();
 +
 +			mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count);
 +
 +			LLModel* target_model = mModel[lod][mdl_idx];
 +
 +			for (GLint i = 0; i < patch_count; ++i)
 +			{
 +				LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0);
 +
 +				if (sizes[i*2+1] > 0 && sizes[i*2] > 0)
 +				{
 +					buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true);
 +					buff->setBuffer(type_mask);
 +					glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer());
 +					stop_gloderror();
 +				}
 +				else
 +				{ //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0)
 +					buff->allocateBuffer(1, 3, true);
 +					memset(buff->getMappedData(), 0, buff->getSize());
 +					memset(buff->getIndicesPointer(), 0, buff->getIndicesSize());
 +				}
 +
 +				buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0);
 +
 +				LLStrider<LLVector3> pos;
 +				LLStrider<LLVector3> norm;
 +				LLStrider<LLVector2> tc;
 +				LLStrider<U16> index;
 +
 +				buff->getVertexStrider(pos);
 +				buff->getNormalStrider(norm);
 +				buff->getTexCoord0Strider(tc);
 +				buff->getIndexStrider(index);
 +
 +				target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices());
 +				actual_tris += buff->getNumIndices()/3;
 +				actual_verts += buff->getNumVerts();
 +				++submeshes;
 +
 +				if (!validate_face(target_model->getVolumeFace(names[i])))
 +				{
 +					llerrs << "Invalid face generated during LOD generation." << llendl;
 +				}
 +			}
 +
 +			//blind copy skin weights and just take closest skin weight to point on
 +			//decimated mesh for now (auto-generating LODs with skin weights is still a bit
 +			//of an open problem).
 +			target_model->mPosition = base->mPosition;
 +			target_model->mSkinWeights = base->mSkinWeights;
 +			target_model->mJointMap = base->mJointMap;
 +			target_model->mJointList = base->mJointList;
 +			target_model->mInvBindMatrix = base->mInvBindMatrix;
 +			target_model->mBindShapeMatrix = base->mBindShapeMatrix;
 +			target_model->mAlternateBindMatrix = base->mAlternateBindMatrix;
 +			//copy material list
 +			target_model->mMaterialList = base->mMaterialList;
 +
 +			if (!validate_model(target_model))
 +			{
 +				llerrs << "Invalid model generated when creating LODs" << llendl;
 +			}
 +
 +			delete [] sizes;
 +			delete [] names;
 +		}
 +
 +		//rebuild scene based on mBaseScene
 +		mScene[lod].clear();
 +		mScene[lod] = mBaseScene;
 +
 +		for (U32 i = 0; i < mBaseModel.size(); ++i)
 +		{
 +			LLModel* mdl = mBaseModel[i];
 +			LLModel* target = mModel[lod][i];
 +			if (target)
 +			{
 +				for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter)
 +				{
 +					for (U32 j = 0; j < iter->second.size(); ++j)
 +					{
 +						if (iter->second[j].mModel == mdl)
 +						{
 +							iter->second[j].mModel = target;
 +						}
 +					}
 +				}
 +			}
 +		}
 +	}
 +
 +	mResourceCost = calcResourceCost();
 +
 +	/*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty())
 +	 { //build physics scene
 +	 mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW];
 +	 mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW];
 +
 +	 for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
 +	 {
 +	 mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]);
 +	 }
 +	 }*/
 +}
 +
 +void LLModelPreview::updateStatusMessages()
 +{
 +	assert_main_thread();
 +
 +	//triangle/vertex/submesh count for each mesh asset for each lod
 +	std::vector<S32> tris[LLModel::NUM_LODS];
 +	std::vector<S32> verts[LLModel::NUM_LODS];
 +	std::vector<S32> submeshes[LLModel::NUM_LODS];
 +
 +	//total triangle/vertex/submesh count for each lod
 +	S32 total_tris[LLModel::NUM_LODS];
 +	S32 total_verts[LLModel::NUM_LODS];
 +	S32 total_submeshes[LLModel::NUM_LODS];
 +
 +	for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
 +	{
 +		//initialize total for this lod to 0
 +		total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0;
 +
 +		for (U32 i = 0; i < mModel[lod].size(); ++i)
 +		{ //for each model in the lod
 +			S32 cur_tris = 0;
 +			S32 cur_verts = 0;
 +			S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
 +
 +			for (S32 j = 0; j < cur_submeshes; ++j)
 +			{ //for each submesh (face), add triangles and vertices to current total
 +				const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
 +				cur_tris += face.mNumIndices/3;
 +				cur_verts += face.mNumVertices;
 +			}
 +
 +			//add this model to the lod total
 +			total_tris[lod] += cur_tris;
 +			total_verts[lod] += cur_verts;
 +			total_submeshes[lod] += cur_submeshes;
 +
 +			//store this model's counts to asset data
 +			tris[lod].push_back(cur_tris);
 +			verts[lod].push_back(cur_verts);
 +			submeshes[lod].push_back(cur_submeshes);
 +		}
 +	}
 +
 +	if (mMaxTriangleLimit == 0)
 +	{
 +		mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];
 +	}
 +
 +
 +	mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
 +
 +	std::string mesh_status_na = mFMP->getString("mesh_status_na");
 +
 +	S32 upload_status[LLModel::LOD_HIGH+1];
 +
 +	bool upload_ok = true;
 +
 +	for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod)
 +	{
 +		upload_status[lod] = 0;
 +
 +		std::string message = "mesh_status_good";
 +
 +		if (total_tris[lod] > 0)
 +		{
 +			mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod]));
 +			mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod]));
 +		}
 +		else
 +		{
 +			if (lod == LLModel::LOD_HIGH)
 +			{
 +				upload_status[lod] = 2;
 +				message = "mesh_status_missing_lod";
 +			}
 +			else
 +			{
 +				for (S32 i = lod-1; i >= 0; --i)
 +				{
 +					if (total_tris[i] > 0)
 +					{
 +						upload_status[lod] = 2;
 +						message = "mesh_status_missing_lod";
 +					}
 +				}
 +			}
 +
 +			mFMP->childSetText(lod_triangles_name[lod], mesh_status_na);
 +			mFMP->childSetText(lod_vertices_name[lod], mesh_status_na);
 +		}
 +
 +		const U32 lod_high = LLModel::LOD_HIGH;
 +
 +		if (lod != lod_high)
 +		{
 +			if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high])
 +			{ //number of submeshes is different
 +				message = "mesh_status_submesh_mismatch";
 +				upload_status[lod] = 2;
 +			}
 +			else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size())
 +			{ //number of meshes is different
 +				message = "mesh_status_mesh_mismatch";
 +				upload_status[lod] = 2;
 +			}
 +			else if (!verts[lod].empty())
 +			{
 +				for (U32 i = 0; i < verts[lod].size(); ++i)
 +				{
 +					S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0;
 +
 +					if (max_verts > 0)
 +					{
 +						if (verts[lod][i] > max_verts)
 +						{ //too many vertices in this lod
 +							message = "mesh_status_too_many_vertices";
 +							upload_status[lod] = 2;
 +						}
 +					}
 +				}
 +			}
 +		}
 +
 +		LLIconCtrl* icon = mFMP->getChild<LLIconCtrl>(lod_icon_name[lod]);
 +		LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]);
 +		icon->setVisible(true);
 +		icon->setImage(img);
 +
 +		if (upload_status[lod] >= 2)
 +		{
 +			upload_ok = false;
 +		}
 +
 +		if (lod == mPreviewLOD)
 +		{
 +			mFMP->childSetText("lod_status_message_text", mFMP->getString(message));
 +			icon = mFMP->getChild<LLIconCtrl>("lod_status_message_icon");
 +			icon->setImage(img);
 +		}
 +	}
 +
 +	bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false;
 +
 +	if ( upload_ok && !errorStateFromLoader )
 +	{
 +		mFMP->childEnable("ok_btn");
 +	}
 +	else
 +	{
 +		mFMP->childDisable("ok_btn");
 +	}
 +
 +	//add up physics triangles etc
 +	S32 start = 0;
 +	S32 end = mModel[LLModel::LOD_PHYSICS].size();
 +
 +	S32 phys_tris = 0;
 +	S32 phys_hulls = 0;
 +	S32 phys_points = 0;
 +
 +	for (S32 i = start; i < end; ++i)
 +	{ //add up hulls and points and triangles for selected mesh(es)
 +		LLModel* model = mModel[LLModel::LOD_PHYSICS][i];
 +		S32 cur_submeshes = model->getNumVolumeFaces();
 +
 +		LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp;
 +
 +		if (!decomp.empty())
 +		{
 +			phys_hulls += decomp.size();
 +			for (U32 i = 0; i < decomp.size(); ++i)
 +			{
 +				phys_points += decomp[i].size();
 +			}
 +		}
 +		else
 +		{ //choose physics shape OR decomposition, can't use both
 +			for (S32 j = 0; j < cur_submeshes; ++j)
 +			{ //for each submesh (face), add triangles and vertices to current total
 +				const LLVolumeFace& face = model->getVolumeFace(j);
 +				phys_tris += face.mNumIndices/3;
 +			}
 +		}
 +	}
 +
 +	if (phys_tris > 0)
 +	{
 +		mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris));
 +	}
 +	else
 +	{
 +		mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na);
 +	}
 +
 +	if (phys_hulls > 0)
 +	{
 +		mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls));
 +		mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points));
 +	}
 +	else
 +	{
 +		mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na);
 +		mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na);
 +	}
 +
 +	LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
 +	if (fmp)
 +	{
 +		if (phys_tris > 0 || phys_hulls > 0)
 +		{
 +			if (!fmp->isViewOptionEnabled("show_physics"))
 +			{
 +				fmp->enableViewOption("show_physics");
 +				mViewOption["show_physics"] = true;
 +			}
 +		}
 +		else
 +		{
 +			fmp->disableViewOption("show_physics");
 +			mViewOption["show_physics"] = false;
 +
 +		}
 +
 +		//bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean();
 +
 +		//fmp->childSetEnabled("physics_optimize", !use_hull);
 +
 +		bool enable = phys_tris > 0 || phys_hulls > 0;
 +		//enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean();
 +
 +		//enable/disable "analysis" UI
 +		LLPanel* panel = fmp->getChild<LLPanel>("physics analysis");
 +		LLView* child = panel->getFirstChild();
 +		while (child)
 +		{
 +			child->setEnabled(enable);
 +			child = panel->findNextSibling(child);
 +		}
 +
 +		enable = phys_hulls > 0;
 +		//enable/disable "simplification" UI
 +		panel = fmp->getChild<LLPanel>("physics simplification");
 +		child = panel->getFirstChild();
 +		while (child)
 +		{
 +			child->setEnabled(enable);
 +			child = panel->findNextSibling(child);
 +		}
 +	}
 +
 +	const char* lod_controls[] =
 +	{
 +		"lod_mode",
 +		"lod_triangle_limit",
 +		"lod_error_tolerance",
 +		"build_operator_text",
 +		"queue_mode_text",
 +		"border_mode_text",
 +		"share_tolerance_text",
 +		"build_operator",
 +		"queue_mode",
 +		"border_mode",
 +		"share_tolerance"
 +	};
 +	const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*);
 +
 +	const char* file_controls[] =
 +	{
 +		"lod_browse",
 +		"lod_file"
 +	};
 +	const U32 num_file_controls = sizeof(file_controls)/sizeof(char*);
 +
 +	if (fmp)
 +	{
 +		//enable/disable controls based on radio groups
 +		if (mFMP->childGetValue("lod_from_file").asBoolean())
 +		{ 
 +			fmp->mLODMode[mPreviewLOD] = 0;
 +			for (U32 i = 0; i < num_file_controls; ++i)
 +			{
 +				mFMP->childEnable(file_controls[i]);
 +			}
 +
 +			for (U32 i = 0; i < num_lod_controls; ++i)
 +			{
 +				mFMP->childDisable(lod_controls[i]);
 +			}
 +		}
 +		else if (mFMP->childGetValue("lod_none").asBoolean())
 +		{
 +			fmp->mLODMode[mPreviewLOD] = 2;
 +			for (U32 i = 0; i < num_file_controls; ++i)
 +			{
 +				mFMP->childDisable(file_controls[i]);
 +			}
 +
 +			for (U32 i = 0; i < num_lod_controls; ++i)
 +			{
 +				mFMP->childDisable(lod_controls[i]);
 +			}
 +
 +			if (!mModel[mPreviewLOD].empty())
 +			{
 +				mModel[mPreviewLOD].clear();
 +				mScene[mPreviewLOD].clear();
 +				mVertexBuffer[mPreviewLOD].clear();
 +
 +				//this can cause phasing issues with the UI, so reenter this function and return
 +				updateStatusMessages();
 +				return;
 +			}
 +		}
 +		else
 +		{	// auto generate, also the default case for wizard which has no radio selection
 +			fmp->mLODMode[mPreviewLOD] = 1;
 +
 +			for (U32 i = 0; i < num_file_controls; ++i)
 +			{
 +				mFMP->childDisable(file_controls[i]);
 +			}
 +
 +			for (U32 i = 0; i < num_lod_controls; ++i)
 +			{
 +				mFMP->childEnable(lod_controls[i]);
 +			}
 +
 +			//if (threshold)
 +			{	
 +				U32 lod_mode = 0;
 +				LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode");
 +				if (iface)
 +				{
 +					lod_mode = iface->getFirstSelectedIndex();
 +				}
 +
 +				LLSpinCtrl* threshold = mFMP->getChild<LLSpinCtrl>("lod_error_threshold");
 +				LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit");
 +
 +				limit->setMaxValue(mMaxTriangleLimit);
 +				limit->setValue(total_tris[mPreviewLOD]);
 +
 +				if (lod_mode == 0)
 +				{
 +					limit->setVisible(true);
 +					threshold->setVisible(false);
 +
 +					limit->setMaxValue(mMaxTriangleLimit);
 +				}
 +				else
 +				{
 +					limit->setVisible(false);
 +					threshold->setVisible(true);
 +				}
 +			}
 +		}
 +	}
 +
 +	if (mFMP->childGetValue("physics_load_from_file").asBoolean())
 +	{
 +		mFMP->childDisable("physics_lod_combo");
 +		mFMP->childEnable("physics_file");
 +		mFMP->childEnable("physics_browse");
 +	}
 +	else
 +	{
 +		mFMP->childEnable("physics_lod_combo");
 +		mFMP->childDisable("physics_file");
 +		mFMP->childDisable("physics_browse");
 +	}
 +}
 +
 +void LLModelPreview::setPreviewTarget(F32 distance)
 +{
 +	mCameraDistance = distance;
 +	mCameraZoom = 1.f;
 +	mCameraPitch = 0.f;
 +	mCameraYaw = 0.f;
 +	mCameraOffset.clearVec();
 +}
 +
 +void LLModelPreview::clearBuffers()
 +{
 +	for (U32 i = 0; i < 6; i++)
 +	{
 +		mVertexBuffer[i].clear();
 +	}
 +}
 +
 +void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
 +{
 +	U32 tri_count = 0;
 +	U32 vertex_count = 0;
 +	U32 mesh_count = 0;
 +
 +	LLModelLoader::model_list* model = NULL;
 +
 +	if (lod < 0 || lod > 4)
 +	{
 +		model = &mBaseModel;
 +		lod = 5;
 +	}
 +	else
 +	{
 +		model = &(mModel[lod]);
 +	}
 +
 +	if (!mVertexBuffer[lod].empty())
 +	{
 +		mVertexBuffer[lod].clear();
 +	}
 +
 +	mVertexBuffer[lod].clear();
 +
 +	LLModelLoader::model_list::iterator base_iter = mBaseModel.begin();
 +
 +	for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter)
 +	{
 +		LLModel* mdl = *iter;
 +		if (!mdl)
 +		{
 +			continue;
 +		}
 +
 +		LLModel* base_mdl = *base_iter;
 +		base_iter++;
 +
 +		for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
 +		{
 +			const LLVolumeFace &vf = mdl->getVolumeFace(i);
 +			U32 num_vertices = vf.mNumVertices;
 +			U32 num_indices = vf.mNumIndices;
 +
 +			if (!num_vertices || ! num_indices)
 +			{
 +				continue;
 +			}
 +
 +			LLVertexBuffer* vb = NULL;
 +
 +			bool skinned = include_skin_weights && !mdl->mSkinWeights.empty();
 +
 +			U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
 +
 +			if (skinned)
 +			{
 +				mask |= LLVertexBuffer::MAP_WEIGHT4;
 +			}
 +
 +			vb = new LLVertexBuffer(mask, 0);
 +
 +			vb->allocateBuffer(num_vertices, num_indices, TRUE);
 +
 +			LLStrider<LLVector3> vertex_strider;
 +			LLStrider<LLVector3> normal_strider;
 +			LLStrider<LLVector2> tc_strider;
 +			LLStrider<U16> index_strider;
 +			LLStrider<LLVector4> weights_strider;
 +
 +			vb->getVertexStrider(vertex_strider);
 +			vb->getNormalStrider(normal_strider);
 +			vb->getTexCoord0Strider(tc_strider);
 +			vb->getIndexStrider(index_strider);
 +
 +			if (skinned)
 +			{
 +				vb->getWeight4Strider(weights_strider);
 +			}
 +
 +			LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32));
 +			LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32));
 +			LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32));
 +
 +			if (skinned)
 +			{
 +				for (U32 i = 0; i < num_vertices; i++)
 +				{
 +					//find closest weight to vf.mVertices[i].mPosition
 +					LLVector3 pos(vf.mPositions[i].getF32ptr());
 +
 +					const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos);
 +
 +					LLVector4 w(0,0,0,0);
 +					if (weight_list.size() > 4)
 +					{
 +						llerrs << "WTF?" << llendl;
 +					}
 +
 +					for (U32 i = 0; i < weight_list.size(); ++i)
 +					{
 +						F32 wght = llmin(weight_list[i].mWeight, 0.999999f);
 +						F32 joint = (F32) weight_list[i].mJointIdx;
 +						w.mV[i] = joint + wght;
 +					}
 +
 +					*(weights_strider++) = w;
 +				}
 +			}
 +
 +			// build indices
 +			for (U32 i = 0; i < num_indices; i++)
 +			{
 +				*(index_strider++) = vf.mIndices[i];
 +			}
 +
 +			mVertexBuffer[lod][mdl].push_back(vb);
 +
 +			vertex_count += num_vertices;
 +			tri_count += num_indices/3;
 +			++mesh_count;
 +
 +		}
 +	}
 +}
 +
 +void LLModelPreview::update()
 +{
 +	if (mDirty)
 +	{
 +		mDirty = false;
 +		mResourceCost = calcResourceCost();
 +		refresh();
 +		updateStatusMessages();
 +	}
 +
 +	if (mGenLOD)
 +	{
 +		mGenLOD = false;
 +		genLODs();
 +		refresh();
 +		updateStatusMessages();
 +	}
 +
 +}
 +
 +//-----------------------------------------------------------------------------
 +// render()
 +//-----------------------------------------------------------------------------
 +BOOL LLModelPreview::render()
 +{
 +	assert_main_thread();
 +
 +	LLMutexLock lock(this);
 +	mNeedsUpdate = FALSE;
 +
 +	bool edges = mViewOption["show_edges"];
 +	bool joint_positions = mViewOption["show_joint_positions"];
 +	bool skin_weight = mViewOption["show_skin_weight"];
 +	bool textures = mViewOption["show_textures"];
 +	bool physics = mViewOption["show_physics"];
 +
 +	S32 width = getWidth();
 +	S32 height = getHeight();
 +
 +	LLGLSUIDefault def;
 +	LLGLDisable no_blend(GL_BLEND);
 +	LLGLEnable cull(GL_CULL_FACE);
 +	LLGLDepthTest depth(GL_TRUE);
 +	LLGLDisable fog(GL_FOG);
 +
 +	{
 +		//clear background to blue
 +		glMatrixMode(GL_PROJECTION);
 +		gGL.pushMatrix();
 +		glLoadIdentity();
 +		glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f);
 +
 +		glMatrixMode(GL_MODELVIEW);
 +		gGL.pushMatrix();
 +		glLoadIdentity();
 +
 +		gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
 +
 +		gl_rect_2d_simple( width, height );
 +
 +		glMatrixMode(GL_PROJECTION);
 +		gGL.popMatrix();
 +
 +		glMatrixMode(GL_MODELVIEW);
 +		gGL.popMatrix();
 +	}
 +
 +	LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
 +	
 +	bool has_skin_weights = false;
 +	bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean();
 +	bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean();
 +
 +	for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
 +	{
 +		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
 +		{
 +			LLModelInstance& instance = *model_iter;
 +			LLModel* model = instance.mModel;
 +			if (!model->mSkinWeights.empty())
 +			{
 +				has_skin_weights = true;
 +			}
 +		}
 +	}
 +
 +	if (has_skin_weights)
 +	{ //model has skin weights, enable view options for skin weights and joint positions
 +		if (fmp)
 +		{
 +			fmp->enableViewOption("show_skin_weight");
 +			fmp->setViewOptionEnabled("show_joint_positions", skin_weight);
 +		}
 +		mFMP->childEnable("upload_skin");
 +	}
 +	else
 +	{
 +		mFMP->childDisable("upload_skin");
 +		if (fmp)
 +		{
 +			mViewOption["show_skin_weight"] = false;
 +			fmp->disableViewOption("show_skin_weight");
 +			fmp->disableViewOption("show_joint_positions");
 +		}
 +		skin_weight = false;
 +	}
 +
 +	if (upload_skin && !has_skin_weights)
 +	{ //can't upload skin weights if model has no skin weights
 +		mFMP->childSetValue("upload_skin", false);
 +		upload_skin = false;
 +	}
 +
 +	if (!upload_skin && upload_joints)
 +	{ //can't upload joints if not uploading skin weights
 +		mFMP->childSetValue("upload_joints", false);
 +		upload_joints = false;
 +	}
 +
 +	mFMP->childSetEnabled("upload_joints", upload_skin);
 +
 +	F32 explode = mFMP->childGetValue("physics_explode").asReal();
 +
 +	glClear(GL_DEPTH_BUFFER_BIT);
 +
 +	LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect();
 +	F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight();
 +
 +	LLViewerCamera::getInstance()->setAspect(aspect);
 +
 +	LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
 +
 +	LLVector3 offset = mCameraOffset;
 +	LLVector3 target_pos = mPreviewTarget+offset;
 +
 +	F32 z_near = 0.001f;
 +	F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec();
 +
 +	if (skin_weight)
 +	{
 +		target_pos = gAgentAvatarp->getPositionAgent();
 +		z_near = 0.01f;
 +		z_far = 1024.f;
 +		mCameraDistance = 16.f;
 +
 +		//render avatar previews every frame
 +		refresh();
 +	}
 +
 +	glLoadIdentity();
 +	gPipeline.enableLightsPreview();
 +
 +	LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) *
 +	LLQuaternion(mCameraYaw, LLVector3::z_axis);
 +
 +	LLQuaternion av_rot = camera_rot;
 +	LLViewerCamera::getInstance()->setOriginAndLookAt(
 +													  target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot),		// camera
 +													  LLVector3::z_axis,																	// up
 +													  target_pos);											// point of interest
 +
 +
 +	LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far);
 +
 +	stop_glerror();
 +
 +	gGL.pushMatrix();
 +	const F32 BRIGHTNESS = 0.9f;
 +	gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
 +
 +	LLGLEnable normalize(GL_NORMALIZE);
 +
 +	if (!mBaseModel.empty() && mVertexBuffer[5].empty())
 +	{
 +		genBuffers(-1, skin_weight);
 +		//genBuffers(3);
 +		//genLODs();
 +	}
 +
 +	if (!mModel[mPreviewLOD].empty())
 +	{
 +		bool regen = mVertexBuffer[mPreviewLOD].empty();
 +		if (!regen)
 +		{
 +			const std::vector<LLPointer<LLVertexBuffer> >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second;
 +			if (!vb_vec.empty())
 +			{
 +				const LLVertexBuffer* buff = vb_vec[0];
 +				regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight;
 +			}
 +		}
 +
 +		if (regen)
 +		{
 +			genBuffers(mPreviewLOD, skin_weight);
 +		}
 +
 +		if (!skin_weight)
 +		{
 +			for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
 +			{
 +				LLModelInstance& instance = *iter;
 +
 +				LLModel* model = instance.mLOD[mPreviewLOD];
 +
 +				if (!model)
 +				{
 +					continue;
 +				}
 +
 +				gGL.pushMatrix();
 +				LLMatrix4 mat = instance.mTransform;
 +
 +				glMultMatrixf((GLfloat*) mat.mMatrix);
 +
 +				for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i)
 +				{
 +					LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
 +
 +					buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
 +
 +					if (textures)
 +					{
 +						glColor4fv(instance.mMaterial[i].mDiffuseColor.mV);
 +						if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull())
 +						{
 +							gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true);
 +							if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1)
 +							{
 +								mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get());
 +							}
 +						}
 +					}
 +					else
 +					{
 +						glColor4f(1,1,1,1);
 +					}
 +
 +					buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 +					gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 +					glColor3f(0.4f, 0.4f, 0.4f);
 +
 +					if (edges)
 +					{
 +						glLineWidth(3.f);
 +						glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 +						buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 +						glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +						glLineWidth(1.f);
 +					}
 +				}
 +				gGL.popMatrix();
 +			}
 +
 +			if (physics)
 +			{
 +				glClear(GL_DEPTH_BUFFER_BIT);
 +				LLGLEnable blend(GL_BLEND);
 +				gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO);
 +
 +				for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
 +				{
 +					LLModelInstance& instance = *iter;
 +
 +					LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
 +
 +					if (!model)
 +					{
 +						continue;
 +					}
 +
 +					gGL.pushMatrix();
 +					LLMatrix4 mat = instance.mTransform;
 +
 +					glMultMatrixf((GLfloat*) mat.mMatrix);
 +
 +
 +					bool render_mesh = true;
 +
 +					LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
 +					if (decomp)
 +					{
 +						LLMutexLock(decomp->mMutex);
 +
 +						std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > >::iterator iter =
 +							mPhysicsMesh.find(model);
 +						if (iter != mPhysicsMesh.end())
 +						{ //render hull instead of mesh
 +							render_mesh = false;
 +							for (U32 i = 0; i < iter->second.size(); ++i)
 +							{
 +								if (explode > 0.f)
 +								{
 +									gGL.pushMatrix();
 +
 +									LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
 +									offset *= explode;
 +
 +									gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
 +								}
 +
 +								static std::vector<LLColor4U> hull_colors;
 +
 +								if (i+1 >= hull_colors.size())
 +								{
 +									hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255));
 +								}
 +
 +								LLVertexBuffer* buff = iter->second[i];
 +								if (buff)
 +								{
 +									buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL);
 +
 +									glColor4ubv(hull_colors[i].mV);
 +									buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
 +								}
 +
 +								if (explode > 0.f)
 +								{
 +									gGL.popMatrix();
 +								}
 +							}
 +						}
 +					}
 +
 +					if (render_mesh)
 +					{
 +						if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
 +						{
 +							genBuffers(LLModel::LOD_PHYSICS, false);
 +						}
 +						for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i)
 +						{
 +							LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
 +
 +							buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
 +
 +							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 +							gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 +							glColor4f(0.4f, 0.4f, 0.0f, 0.4f);
 +
 +							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 +
 +							glColor3f(1.f, 1.f, 0.f);
 +
 +							glLineWidth(3.f);
 +							glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 +							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 +							glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +							glLineWidth(1.f);
 +						}
 +					}
 +
 +					gGL.popMatrix();
 +				}
 +
 +				gGL.setSceneBlendType(LLRender::BT_ALPHA);
 +			}
 +		}
 +		else
 +		{
 +			LLVOAvatarSelf* avatar = gAgentAvatarp;
 +			target_pos = avatar->getPositionAgent();
 +
 +			LLViewerCamera::getInstance()->setOriginAndLookAt(
 +															  target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot),		// camera
 +															  LLVector3::z_axis,																	// up
 +															  target_pos);											// point of interest
 +
 +			if (joint_positions)
 +			{
 +				avatar->renderCollisionVolumes();
 +			}
 +
 +			for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
 +			{
 +				for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
 +				{
 +					LLModelInstance& instance = *model_iter;
 +					LLModel* model = instance.mModel;
 +
 +					if (!model->mSkinWeights.empty())
 +					{
 +						for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i)
 +						{
 +							LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
 +
 +							const LLVolumeFace& face = model->getVolumeFace(i);
 +
 +							LLStrider<LLVector3> position;
 +							buffer->getVertexStrider(position);
 +
 +							LLStrider<LLVector4> weight;
 +							buffer->getWeight4Strider(weight);
 +
 +							//quick 'n dirty software vertex skinning
 +
 +							//build matrix palette
 +							LLMatrix4 mat[64];
 +							for (U32 j = 0; j < model->mJointList.size(); ++j)
 +							{
 +								LLJoint* joint = avatar->getJoint(model->mJointList[j]);
 +								if (joint)
 +								{
 +									mat[j] = model->mInvBindMatrix[j];
 +									mat[j] *= joint->getWorldMatrix();
 +								}
 +							}
 +
 +							for (U32 j = 0; j < buffer->getRequestedVerts(); ++j)
 +							{
 +								LLMatrix4 final_mat;
 +								final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f;
 +
 +								LLVector4 wght;
 +								S32 idx[4];
 +
 +								F32 scale = 0.f;
 +								for (U32 k = 0; k < 4; k++)
 +								{
 +									F32 w = weight[j].mV[k];
 +
 +									idx[k] = (S32) floorf(w);
 +									wght.mV[k] = w - floorf(w);
 +									scale += wght.mV[k];
 +								}
 +
 +								wght *= 1.f/scale;
 +
 +								for (U32 k = 0; k < 4; k++)
 +								{
 +									F32* src = (F32*) mat[idx[k]].mMatrix;
 +									F32* dst = (F32*) final_mat.mMatrix;
 +
 +									F32 w = wght.mV[k];
 +
 +									for (U32 l = 0; l < 16; l++)
 +									{
 +										dst[l] += src[l]*w;
 +									}
 +								}
 +
 +								//VECTORIZE THIS
 +								LLVector3 v(face.mPositions[j].getF32ptr());
 +
 +								v = v * model->mBindShapeMatrix;
 +								v = v * final_mat;
 +
 +								position[j] = v;
 +							}
 +
 +							buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
 +							glColor4fv(instance.mMaterial[i].mDiffuseColor.mV);
 +							gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 +							buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
 +							glColor3f(0.4f, 0.4f, 0.4f);
 +
 +							if (edges)
 +							{
 +								glLineWidth(3.f);
 +								glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 +								buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
 +								glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +								glLineWidth(1.f);
 +							}
 +						}
 +					}
 +				}
 +			}
 +		}
 +	}
 +
 +	gGL.popMatrix();
 +
 +	return TRUE;
 +}
 +
 +//-----------------------------------------------------------------------------
 +// refresh()
 +//-----------------------------------------------------------------------------
 +void LLModelPreview::refresh()
 +{
 +	mNeedsUpdate = TRUE;
 +}
 +
 +//-----------------------------------------------------------------------------
 +// rotate()
 +//-----------------------------------------------------------------------------
 +void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians)
 +{
 +	mCameraYaw = mCameraYaw + yaw_radians;
 +
 +	mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f);
 +}
 +
 +//-----------------------------------------------------------------------------
 +// zoom()
 +//-----------------------------------------------------------------------------
 +void LLModelPreview::zoom(F32 zoom_amt)
 +{
 +	F32 new_zoom = mCameraZoom+zoom_amt;
 +
 +	mCameraZoom	= llclamp(new_zoom, 1.f, 10.f);
 +}
 +
 +void LLModelPreview::pan(F32 right, F32 up)
 +{
 +	mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f);
 +	mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f);
 +}
 +
 +void LLModelPreview::setPreviewLOD(S32 lod)
 +{
 +	lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH);
 +
 +	if (lod != mPreviewLOD)
 +	{
 +		mPreviewLOD = lod;
 +
 +		LLComboBox* combo_box = mFMP->getChild<LLComboBox>("preview_lod_combo");
 +		combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order
 +		mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD]));
 +		mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]);
 +
 +		LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor");
 +		LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor");
 +
 +		for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i)
 +		{
 +			const LLColor4& color = (i == lod) ? highlight_color : normal_color;
 +
 +			mFMP->childSetColor(lod_status_name[i], color);
 +			mFMP->childSetColor(lod_label_name[i], color);
 +			mFMP->childSetColor(lod_triangles_name[i], color);
 +			mFMP->childSetColor(lod_vertices_name[i], color);
 +		}
 +
 +		LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
 +		if (fmp)
 +		{
 +			LLRadioGroup* radio = fmp->getChild<LLRadioGroup>("lod_file_or_limit");
 +			radio->selectNthItem(fmp->mLODMode[mPreviewLOD]);
 +		}
 +	}
 +	refresh();
 +	updateStatusMessages();
 +}
 +
 +//static
 +void LLFloaterModelPreview::onBrowseLOD(void* data)
 +{
 +	assert_main_thread();
 +
 +	LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data;
 +	mp->loadModel(mp->mModelPreview->mPreviewLOD);
 +}
 +
 +//static
 +void LLFloaterModelPreview::onUpload(void* user_data)
 +{
 +	assert_main_thread();
 +
 +	LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data;
 +
 +	mp->mModelPreview->rebuildUploadData();
 +
 +	gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale,
 +						  mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints"));
 +
 +	mp->closeFloater(false);
 +}
 +
 +
 +//static
 +void LLFloaterModelPreview::onClearMaterials(void* user_data)
 +{
 +	LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data;
 +	mp->mModelPreview->clearMaterials();
 +}
 +
 +//static
 +void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data)
 +{
 +	sInstance->mModelPreview->mDirty = true;
 +}
 +
 +void LLFloaterModelPreview::updateResourceCost()
 +{
 +	U32 cost = mModelPreview->mResourceCost;
 +	childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost));
 +}
 +
 +//static
 +void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata )
 +{
 +	LLModelPreview* preview = (LLModelPreview*) userdata;
 +	preview->refresh();
 +}
 +
 +LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl)
 +{
 +	mStage = stage;
 +	mContinue = 1;
 +	mModel = mdl;
 +	mDecompID = &mdl->mDecompID;
 +	mParams = sInstance->mDecompParams;
 +
 +	//copy out positions and indices
 +	if (mdl)
 +	{
 +		U16 index_offset = 0;
 +
 +		mPositions.clear();
 +		mIndices.clear();
 +
 +		//queue up vertex positions and indices
 +		for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
 +		{
 +			const LLVolumeFace& face = mdl->getVolumeFace(i);
 +			if (mPositions.size() + face.mNumVertices > 65535)
 +			{
 +				continue;
 +			}
 +
 +			for (U32 j = 0; j < face.mNumVertices; ++j)
 +			{
 +				mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr()));
 +			}
 +
 +			for (U32 j = 0; j < face.mNumIndices; ++j)
 +			{
 +				mIndices.push_back(face.mIndices[j]+index_offset);
 +			}
 +
 +			index_offset += face.mNumVertices;
 +		}
 +	}
 +}
 +
 +void LLFloaterModelPreview::setStatusMessage(const std::string& msg)
 +{
 +	LLMutexLock lock(mStatusLock);
 +	mStatusMessage = msg;
 +}
 +
 +S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)
 +{
 +	setStatusMessage(llformat("%s: %d/%d", status, p1, p2));
 +	if (LLFloaterModelPreview::sInstance)
 +	{
 +		LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage);
 +	}
 +
 +	return mContinue;
 +}
 +
 +void LLFloaterModelPreview::DecompRequest::completed()
 +{ //called from the main thread
 +	mModel->setConvexHullDecomposition(mHull);
 +
 +	if (sInstance)
 +	{
 +		if (mContinue)
 +		{
 +			if (sInstance->mModelPreview)
 +			{
 +				sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh;
 +				sInstance->mModelPreview->mDirty = true;
 +				LLFloaterModelPreview::sInstance->mModelPreview->refresh();
 +			}
 +		}
 +
 +		sInstance->mCurRequest.erase(this);
 +	}
 +}
 diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 19984a00bd..9dceb9c145 100644..100755 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -30,6 +30,7 @@  #include "llfloaternamedesc.h"  #include "lldynamictexture.h" +#include "llfloatermodelwizard.h"  #include "llquaternion.h"  #include "llmeshrepository.h"  #include "llmodel.h" @@ -96,6 +97,7 @@ public:  	virtual void run(); +	void loadTextures() ; //called in the main thread.  	void processElement(daeElement* element);  	std::vector<LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo);  	LLImportMaterial profileToMaterial(domProfile_COMMON* material); @@ -151,7 +153,6 @@ public:  	static void onUpload(void* data);  	static void onClearMaterials(void* data); -	static void onModelDecompositionComplete(LLModel* model, std::vector<LLPointer<LLVertexBuffer> >& physics_mesh);  	static void refresh(LLUICtrl* ctrl, void* data); @@ -165,7 +166,6 @@ public:  	void setViewOptionEnabled(const std::string& option, bool enabled);  	void enableViewOption(const std::string& option);  	void disableViewOption(const std::string& option); -	void setViewOption(const std::string& option, bool value);  protected:  	friend class LLModelPreview; @@ -187,6 +187,7 @@ protected:  	static void onPhysicsParamCommit(LLUICtrl* ctrl, void* userdata);  	static void onPhysicsStageExecute(LLUICtrl* ctrl, void* userdata); +	static void onCancel(LLUICtrl* ctrl, void* userdata);  	static void onPhysicsStageCancel(LLUICtrl* ctrl, void* userdata);  	static void onPhysicsBrowse(LLUICtrl* ctrl, void* userdata); @@ -214,8 +215,6 @@ protected:  	std::set<LLPointer<DecompRequest> > mCurRequest;  	std::string mStatusMessage; -	std::map<std::string, bool> mViewOption; -  	//use "disabled" as false by default  	std::map<std::string, bool> mViewOptionDisabled; @@ -285,6 +284,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex  	friend class LLFloaterModelPreview;  	friend class LLFloaterModelWizard;  	friend class LLFloaterModelPreview::DecompRequest; +	friend class LLFloaterModelWizard::DecompRequest;  	friend class LLPhysicsDecomp;  	LLFloater*  mFMP; @@ -305,16 +305,16 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex  	std::string mLODFile[LLModel::NUM_LODS];  	bool		mLoading; +	std::map<std::string, bool> mViewOption; +  	//GLOD object parameters (must rebuild object if these change)  	F32 mBuildShareTolerance;  	U32 mBuildQueueMode;  	U32 mBuildOperator;  	U32 mBuildBorderMode; -  	LLModelLoader* mModelLoader; -  	LLModelLoader::scene mScene[LLModel::NUM_LODS];  	LLModelLoader::scene mBaseScene; @@ -327,7 +327,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex  	std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > > mPhysicsMesh;  	LLMeshUploadThread::instance_list mUploadData; -	std::set<LLPointer<LLViewerFetchedTexture> > mTextureSet; +	std::set<LLViewerFetchedTexture* > mTextureSet;  	//map of vertex buffers to models (one vertex buffer in vector per face in model  	std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1]; diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp index aca5d67e60..fe53eafa40 100644 --- a/indra/newview/llfloatermodelwizard.cpp +++ b/indra/newview/llfloatermodelwizard.cpp @@ -35,10 +35,11 @@  #include "llfloatermodelwizard.h"  #include "llfloatermodelpreview.h"  #include "llfloaterreg.h" -#include "llslider.h" +#include "llsliderctrl.h"  #include "lltoolmgr.h"  #include "llviewerwindow.h" +LLFloaterModelWizard* LLFloaterModelWizard::sInstance = NULL;  static	const std::string stateNames[]={  	"choose_file", @@ -50,8 +51,12 @@ static	const std::string stateNames[]={  LLFloaterModelWizard::LLFloaterModelWizard(const LLSD& key)  	: LLFloater(key)  { +	sInstance = this; +} +LLFloaterModelWizard::~LLFloaterModelWizard() +{ +	sInstance = NULL;  } -  void LLFloaterModelWizard::setState(int state)  {  	mState = state; @@ -69,6 +74,34 @@ void LLFloaterModelWizard::setState(int state)  	if (state == OPTIMIZE)  	{  		mModelPreview->genLODs(-1); +		mModelPreview->mViewOption["show_physics"] = false; +	} + +	if (state == PHYSICS) +	{ +		mModelPreview->setPhysicsFromLOD(1); +		mModelPreview->mViewOption["show_physics"] = true; + +		getChild<LLView>("next")->setVisible(true); +		getChild<LLView>("upload")->setVisible(false); +	} + +	if (state == REVIEW) +	{ +		executePhysicsStage("Decompose"); +		getChild<LLView>("close")->setVisible(false); +		getChild<LLView>("next")->setVisible(false); +		getChild<LLView>("back")->setVisible(true); +		getChild<LLView>("upload")->setVisible(true); +		getChild<LLView>("cancel")->setVisible(true); +	} + +	if (state == UPLOAD) +	{ +		getChild<LLView>("close")->setVisible(true); +		getChild<LLView>("back")->setVisible(false); +		getChild<LLView>("upload")->setVisible(false); +		getChild<LLView>("cancel")->setVisible(false);  	}  } @@ -227,6 +260,161 @@ BOOL LLFloaterModelWizard::handleScrollWheel(S32 x, S32 y, S32 clicks)  	return TRUE;  } +void LLFloaterModelWizard::initDecompControls() +{ +	LLSD key; + +	static const LLCDStageData* stage = NULL; +	static S32 stage_count = 0; + +	if (!stage && LLConvexDecomposition::getInstance() != NULL) +	{ +		stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); +	} + +	static const LLCDParam* param = NULL; +	static S32 param_count = 0; +	if (!param && LLConvexDecomposition::getInstance() != NULL) +	{ +		param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); +	} + +	for (S32 j = stage_count-1; j >= 0; --j) +	{ +		gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; +		// protected against stub by stage_count being 0 for stub above +		LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); + +		for (S32 i = 0; i < param_count; ++i) +		{ +			if (param[i].mStage != j) +			{ +				continue; +			} + +			std::string name(param[i].mName ? param[i].mName : ""); +			std::string description(param[i].mDescription ? param[i].mDescription : ""); + +			if (param[i].mType == LLCDParam::LLCD_FLOAT) +			{ +				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); +			} +			else if (param[i].mType == LLCDParam::LLCD_INTEGER) +			{ +				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); +			} +			else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) +			{ +				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); +			} +			else if (param[i].mType == LLCDParam::LLCD_ENUM) +			{ +				mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); +			} +		} +	} + +	mDecompParams["Simplify Method"] = 0; // set it to retain % +} + +//static +void LLFloaterModelWizard::executePhysicsStage(std::string stage_name) +{ +	if (sInstance) +	{ +		F64 physics_accuracy = sInstance->getChild<LLSliderCtrl>("physics_slider")->getValue().asReal(); + +		sInstance->mDecompParams["Retain%"] = physics_accuracy; + +		if (!sInstance->mCurRequest.empty()) +		{ +			llinfos << "Decomposition request still pending." << llendl; +			return; +		} + +		if (sInstance->mModelPreview) +		{ +			for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) +			{ +				LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; +				DecompRequest* request = new DecompRequest(stage_name, mdl); +				sInstance->mCurRequest.insert(request); +				gMeshRepo.mDecompThread->submitRequest(request); +			} +		} +	} +} + +LLFloaterModelWizard::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) +{ +	mStage = stage; +	mContinue = 1; +	mModel = mdl; +	mDecompID = &mdl->mDecompID; +	mParams = sInstance->mDecompParams; + +	//copy out positions and indices +	if (mdl) +	{ +		U16 index_offset = 0; + +		mPositions.clear(); +		mIndices.clear(); + +		//queue up vertex positions and indices +		for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) +		{ +			const LLVolumeFace& face = mdl->getVolumeFace(i); +			if (mPositions.size() + face.mNumVertices > 65535) +			{ +				continue; +			} + +			for (U32 j = 0; j < face.mNumVertices; ++j) +			{ +				mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); +			} + +			for (U32 j = 0; j < face.mNumIndices; ++j) +			{ +				mIndices.push_back(face.mIndices[j]+index_offset); +			} + +			index_offset += face.mNumVertices; +		} +	} +} + + +S32 LLFloaterModelWizard::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) +{ +	setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + +	return mContinue; +} + +void LLFloaterModelWizard::DecompRequest::completed() +{ //called from the main thread +	mModel->setConvexHullDecomposition(mHull); + +	if (sInstance) +	{ +		if (sInstance->mModelPreview) +		{ +			sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; +			sInstance->mModelPreview->mDirty = true; +			LLFloaterModelWizard::sInstance->mModelPreview->refresh(); +		} + +		sInstance->mCurRequest.erase(this); +	} + +	if (mStage == "Decompose") +	{ +		executePhysicsStage("Simplify"); +	} +} +  BOOL LLFloaterModelWizard::postBuild()  { @@ -236,13 +424,13 @@ BOOL LLFloaterModelWizard::postBuild()  	getChild<LLUICtrl>("browse")->setCommitCallback(boost::bind(&LLFloaterModelWizard::loadModel, this));  	getChild<LLUICtrl>("cancel")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickCancel, this)); +	getChild<LLUICtrl>("close")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickCancel, this));  	getChild<LLUICtrl>("back")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickBack, this));  	getChild<LLUICtrl>("next")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickNext, this)); -	childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); +	getChild<LLUICtrl>("preview_lod_combo")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1));  	getChild<LLUICtrl>("accuracy_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onAccuracyPerformance, this, _2)); - -	childSetAction("ok_btn", onUpload, this); - +	getChild<LLUICtrl>("upload")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onUpload, this)); +	  	LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;  	enable_registrar.add("Next.OnEnable", boost::bind(&LLFloaterModelWizard::onEnableNext, this)); @@ -262,19 +450,20 @@ BOOL LLFloaterModelWizard::postBuild()  	childSetTextArg("import_dimensions", "[Y]", LLStringUtil::null);  	childSetTextArg("import_dimensions", "[Z]", LLStringUtil::null); +	initDecompControls(); +  	return TRUE;  } -void LLFloaterModelWizard::onUpload(void* user_data) -{ -	LLFloaterModelWizard* mp = (LLFloaterModelWizard*) user_data; +void LLFloaterModelWizard::onUpload() +{	 +	mModelPreview->rebuildUploadData(); -	mp->mModelPreview->rebuildUploadData(); +	gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale,  +						  childGetValue("upload_textures").asBoolean(), childGetValue("upload_skin"), childGetValue("upload_joints")); -	gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale,  -						  mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); +	setState(UPLOAD); -	mp->closeFloater(false);  } @@ -287,11 +476,9 @@ void LLFloaterModelWizard::onAccuracyPerformance(const LLSD& data)  	mModelPreview->refresh();  } -void LLFloaterModelWizard::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) +void LLFloaterModelWizard::onPreviewLODCommit(LLUICtrl* ctrl)  { -	LLFloaterModelWizard *fp =(LLFloaterModelWizard *)userdata; -	 -	if (!fp->mModelPreview) +	if (!mModelPreview)  	{  		return;  	} @@ -302,7 +489,7 @@ void LLFloaterModelWizard::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata)  	which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order -	fp->mModelPreview->setPreviewLOD(which_mode); +	mModelPreview->setPreviewLOD(which_mode);  }  void LLFloaterModelWizard::draw() diff --git a/indra/newview/llfloatermodelwizard.h b/indra/newview/llfloatermodelwizard.h index b7fd28aa9d..eaf188ed40 100644 --- a/indra/newview/llfloatermodelwizard.h +++ b/indra/newview/llfloatermodelwizard.h @@ -26,13 +26,35 @@  #ifndef LLFLOATERMODELWIZARD_H  #define LLFLOATERMODELWIZARD_H + +#include "llmeshrepository.h" +#include "llmodel.h" +#include "llthread.h" + +  class LLModelPreview; +  class LLFloaterModelWizard : public LLFloater  {  public: +	 +	class DecompRequest : public LLPhysicsDecomp::Request +	{ +	public: +		S32 mContinue; +		LLPointer<LLModel> mModel; +		 +		DecompRequest(const std::string& stage, LLModel* mdl); +		virtual S32 statusCallback(const char* status, S32 p1, S32 p2); +		virtual void completed(); +		 +	}; +	 +	static LLFloaterModelWizard* sInstance; +  	LLFloaterModelWizard(const LLSD& key); -	virtual ~LLFloaterModelWizard() {}; +	virtual ~LLFloaterModelWizard();  	/*virtual*/	BOOL	postBuild();  	void			draw(); @@ -41,6 +63,14 @@ public:  	BOOL handleHover(S32 x, S32 y, MASK mask);  	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);  +	 +	void initDecompControls(); +	 +	LLPhysicsDecomp::decomp_params mDecompParams; +	std::set<LLPointer<DecompRequest> > mCurRequest; +	std::string mStatusMessage; +	static void executePhysicsStage(std::string stage_name); +  private:  	enum EWizardState  	{ @@ -59,9 +89,9 @@ private:  	bool onEnableNext();  	bool onEnableBack();  	void loadModel(); -	static void	onPreviewLODCommit(LLUICtrl*,void*); +	void onPreviewLODCommit(LLUICtrl*);  	void onAccuracyPerformance(const LLSD& data); -	static void onUpload(void* data); +	void onUpload();  	LLModelPreview*	mModelPreview;  	LLRect			mPreviewRect; diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 3ed4aec89a..2041fac8d8 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -200,5 +200,5 @@ void LLFloaterSearch::search(const LLSD &key)  	url = LLWeb::expandURLSubstitutions(url, subs);  	// and load the URL in the web view -	mBrowser->navigateTo(url); +	mBrowser->navigateTo(url, "text/html");  } diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp new file mode 100644 index 0000000000..51726112a0 --- /dev/null +++ b/indra/newview/llfloaterwebcontent.cpp @@ -0,0 +1,402 @@ +/**
 + * @file llfloaterwebcontent.cpp
 + * @brief floater for displaying web content - e.g. profiles and search (eventually)
 + *
 + * $LicenseInfo:firstyear=2006&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, Linden Research, Inc.
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation;
 + * version 2.1 of the License only.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 + *
 + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 + * $/LicenseInfo$
 + */
 +
 +#include "llviewerprecompiledheaders.h"
 +
 +#include "llcombobox.h"
 +#include "lliconctrl.h"
 +#include "llfloaterreg.h"
 +#include "lllayoutstack.h"
 +#include "llpluginclassmedia.h"
 +#include "llprogressbar.h"
 +#include "lltextbox.h"
 +#include "llurlhistory.h"
 +#include "llviewercontrol.h"
 +#include "llweb.h"
 +#include "llwindow.h"
 +
 +#include "llfloaterwebcontent.h"
 +
 +LLFloaterWebContent::LLFloaterWebContent( const LLSD& key )
 +	: LLFloater( key )
 +{
 +	mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this ));
 +}
 +
 +BOOL LLFloaterWebContent::postBuild()
 +{
 +	// these are used in a bunch of places so cache them
 +	mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" );
 +	mAddressCombo = getChild< LLComboBox >( "address" );
 +	mStatusBarText = getChild< LLTextBox >( "statusbartext" );
 +	mStatusBarProgress = getChild<LLProgressBar>("statusbarprogress" );
 +
 +	// observe browser events
 +	mWebBrowser->addObserver( this );
 +
 +	// these buttons are always enabled
 +	getChildView("reload")->setEnabled( true );
 +	getChildView("popexternal")->setEnabled( true );
 +
 +	// cache image for secure browsing
 +	mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
 +
 +	// initialize the URL history using the system URL History manager
 +	initializeURLHistory();
 +
 +	return TRUE;
 +}
 +
 +void LLFloaterWebContent::initializeURLHistory()
 +{
 +	// start with an empty list
 +	LLCtrlListInterface* url_list = childGetListInterface("address");
 +	if (url_list)
 +	{
 +		url_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
 +	}
 +
 +	// Get all of the entries in the "browser" collection
 +	LLSD browser_history = LLURLHistory::getURLHistory("browser");
 +	LLSD::array_iterator iter_history =
 +		browser_history.beginArray();
 +	LLSD::array_iterator end_history =
 +		browser_history.endArray();
 +	for(; iter_history != end_history; ++iter_history)
 +	{
 +		std::string url = (*iter_history).asString();
 +		if(! url.empty())
 +			url_list->addSimpleElement(url);
 +	}
 +}
 +
 +//static
 +void LLFloaterWebContent::create( const std::string &url, const std::string& target, const std::string& uuid )
 +{
 +	lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl;
 +
 +	std::string tag = target;
 +
 +	if(target.empty() || target == "_blank")
 +	{
 +		if(!uuid.empty())
 +		{
 +			tag = uuid;
 +		}
 +		else
 +		{
 +			// create a unique tag for this instance
 +			LLUUID id;
 +			id.generate();
 +			tag = id.asString();
 +		}
 +	}
 +
 +	S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit");
 +
 +	if(LLFloaterReg::findInstance("web_content", tag) != NULL)
 +	{
 +		// There's already a web browser for this tag, so we won't be opening a new window.
 +	}
 +	else if(browser_window_limit != 0)
 +	{
 +		// showInstance will open a new window.  Figure out how many web browsers are already open,
 +		// and close the least recently opened one if this will put us over the limit.
 +
 +		LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content");
 +		lldebugs << "total instance count is " << instances.size() << llendl;
 +
 +		for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
 +		{
 +			lldebugs << "    " << (*iter)->getKey() << llendl;
 +		}
 +
 +		if(instances.size() >= (size_t)browser_window_limit)
 +		{
 +			// Destroy the least recently opened instance
 +			(*instances.begin())->closeFloater();
 +		}
 +	}
 +
 +	LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::showInstance("web_content", tag));
 +	llassert(browser);
 +	if(browser)
 +	{
 +		browser->mUUID = uuid;
 +
 +		// tell the browser instance to load the specified URL
 +		browser->open_media(url, target);
 +		LLViewerMedia::proxyWindowOpened(target, uuid);
 +	}
 +}
 +
 +//static
 +void LLFloaterWebContent::closeRequest(const std::string &uuid)
 +{
 +	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
 +	lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
 +	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
 +	{
 +		LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
 +		lldebugs << "    " << i->mUUID << llendl;
 +		if (i && i->mUUID == uuid)
 +		{
 +			i->closeFloater(false);
 +			return;
 + 		}
 + 	}
 +}
 +
 +//static
 +void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
 +{
 +	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
 +	lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
 +	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
 +	{
 +		LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
 +		lldebugs << "    " << i->mUUID << llendl;
 +		if (i && i->mUUID == uuid)
 +		{
 +			i->geometryChanged(x, y, width, height);
 +			return;
 +		}
 +	}
 +}
 +
 +void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
 +{
 +	// Make sure the layout of the browser control is updated, so this calculation is correct.
 +	LLLayoutStack::updateClass();
 +
 +	// TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
 +	LLCoordWindow window_size;
 +	getWindow()->getSize(&window_size);
 +
 +	// Adjust width and height for the size of the chrome on the web Browser window.
 +	width += getRect().getWidth() - mWebBrowser->getRect().getWidth();
 +	height += getRect().getHeight() - mWebBrowser->getRect().getHeight();
 +
 +	LLRect geom;
 +	geom.setOriginAndSize(x, window_size.mY - (y + height), width, height);
 +
 +	lldebugs << "geometry change: " << geom << llendl;
 +
 +	handleReshape(geom,false);
 +}
 +
 +void LLFloaterWebContent::open_media(const std::string& web_url, const std::string& target)
 +{
 +	// Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
 +	mWebBrowser->setHomePageUrl(web_url, "text/html");
 +	mWebBrowser->setTarget(target);
 +	mWebBrowser->navigateTo(web_url, "text/html");
 +	set_current_url(web_url);
 +}
 +
 +//virtual
 +void LLFloaterWebContent::onClose(bool app_quitting)
 +{
 +	LLViewerMedia::proxyWindowClosed(mUUID);
 +	destroy();
 +}
 +
 +// virtual
 +void LLFloaterWebContent::draw()
 +{
 +	// this is asychronous so we need to keep checking
 +	getChildView( "back" )->setEnabled( mWebBrowser->canNavigateBack() );
 +	getChildView( "forward" )->setEnabled( mWebBrowser->canNavigateForward() );
 +
 +	LLFloater::draw();
 +}
 +
 +// virtual
 +void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 +{
 +	if(event == MEDIA_EVENT_LOCATION_CHANGED)
 +	{
 +		const std::string url = self->getLocation();
 +
 +		if ( url.length() )
 +			mStatusBarText->setText( url );
 +
 +		set_current_url( url );
 +	}
 +	else if(event == MEDIA_EVENT_NAVIGATE_BEGIN)
 +	{
 +		// flags are sent with this event
 +		getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
 +		getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
 +
 +		// toggle visibility of these buttons based on browser state
 +		getChildView("reload")->setVisible( false );
 +		getChildView("stop")->setVisible( true );
 +
 +		// turn "on" progress bar now we're about to start loading
 +		mStatusBarProgress->setVisible( true );
 +	}
 +	else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
 +	{
 +		// flags are sent with this event
 +		getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
 +		getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
 +
 +		// toggle visibility of these buttons based on browser state
 +		getChildView("reload")->setVisible( true );
 +		getChildView("stop")->setVisible( false );
 +
 +		// turn "off" progress bar now we're loaded
 +		mStatusBarProgress->setVisible( false );
 +
 +		// we populate the status bar with URLs as they change so clear it now we're done
 +		const std::string end_str = "";
 +		mStatusBarText->setText( end_str );
 +
 +		// decide if secure browsing icon should be displayed
 +		std::string prefix =  std::string("https://");
 +		std::string test_prefix = mCurrentURL.substr(0, prefix.length());
 +		LLStringUtil::toLower(test_prefix);
 +		if(test_prefix == prefix)
 +		{
 +			mSecureLockIcon->setVisible(true);
 +		}
 +		else
 +		{
 +			mSecureLockIcon->setVisible(false);
 +		}
 +	}
 +	else if(event == MEDIA_EVENT_CLOSE_REQUEST)
 +	{
 +		// The browser instance wants its window closed.
 +		closeFloater();
 +	}
 +	else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
 +	{
 +		geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
 +	}
 +	else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED )
 +	{
 +		const std::string text = self->getStatusText();
 +		if ( text.length() )
 +			mStatusBarText->setText( text );
 +	}
 +	else if(event == MEDIA_EVENT_PROGRESS_UPDATED )
 +	{
 +		int percent = (int)self->getProgressPercent();
 +		mStatusBarProgress->setValue( percent );
 +	}
 +	else if(event == MEDIA_EVENT_NAME_CHANGED )
 +	{
 +		std::string page_title = self->getMediaName();
 +		// simulate browser behavior - title is empty, use the current URL
 +		if ( page_title.length() > 0 )
 +			setTitle( page_title );
 +		else
 +			setTitle( mCurrentURL );
 +	}
 +	else if(event == MEDIA_EVENT_LINK_HOVERED )
 +	{
 +		const std::string link = self->getHoverLink();
 +		mStatusBarText->setText( link );
 +	}
 +}
 +
 +void LLFloaterWebContent::set_current_url(const std::string& url)
 +{
 +	mCurrentURL = url;
 +
 +	// serialize url history into the system URL History manager
 +	LLURLHistory::removeURL("browser", mCurrentURL);
 +	LLURLHistory::addURL("browser", mCurrentURL);
 +
 +	mAddressCombo->remove( mCurrentURL );
 +	mAddressCombo->add( mCurrentURL );
 +	mAddressCombo->selectByValue( mCurrentURL );
 +}
 +
 +void LLFloaterWebContent::onClickForward()
 +{
 +	mWebBrowser->navigateForward();
 +}
 +
 +void LLFloaterWebContent::onClickBack()
 +{
 +	mWebBrowser->navigateBack();
 +}
 +
 +void LLFloaterWebContent::onClickReload()
 +{
 +
 +	if( mWebBrowser->getMediaPlugin() )
 +	{
 +		bool ignore_cache = true;
 +		mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache );
 +	}
 +	else
 +	{
 +		mWebBrowser->navigateTo(mCurrentURL);
 +	}
 +}
 +
 +void LLFloaterWebContent::onClickStop()
 +{
 +	if( mWebBrowser->getMediaPlugin() )
 +		mWebBrowser->getMediaPlugin()->browse_stop();
 +
 +	// still should happen when we catch the navigate complete event
 +	// but sometimes (don't know why) that event isn't sent from Qt
 +	// and we getto a point where the stop button stays active.
 +	getChildView("reload")->setVisible( true );
 +	getChildView("stop")->setVisible( false );
 +}
 +
 +void LLFloaterWebContent::onEnterAddress()
 +{
 +	// make sure there is at least something there.
 +	// (perhaps this test should be for minimum length of a URL)
 +	std::string url = mAddressCombo->getValue().asString();
 +	if ( url.length() > 0 )
 +	{
 +		mWebBrowser->navigateTo( url, "text/html");
 +	};
 +}
 +
 +void LLFloaterWebContent::onPopExternal()
 +{
 +	// make sure there is at least something there.
 +	// (perhaps this test should be for minimum length of a URL)
 +	std::string url = mAddressCombo->getValue().asString();
 +	if ( url.length() > 0 )
 +	{
 +		LLWeb::loadURLExternal( url );
 +	};
 +}
 diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h new file mode 100644 index 0000000000..001d822ada --- /dev/null +++ b/indra/newview/llfloaterwebcontent.h @@ -0,0 +1,82 @@ +/**
 + * @file llfloaterwebcontent.h
 + * @brief floater for displaying web content - e.g. profiles and search (eventually)
 + *
 + * $LicenseInfo:firstyear=2006&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_LLFLOATERWEBCONTENT_H
 +#define LL_LLFLOATERWEBCONTENT_H
 +
 +#include "llfloater.h"
 +#include "llmediactrl.h"
 +
 +class LLMediaCtrl;
 +class LLComboBox;
 +class LLTextBox;
 +class LLProgressBar;
 +class LLIconCtrl;
 +
 +class LLFloaterWebContent :
 +	public LLFloater,
 +	public LLViewerMediaObserver
 +{
 +public:
 +    LOG_CLASS(LLFloaterWebContent);
 +	LLFloaterWebContent(const LLSD& key);
 +
 +	void initializeURLHistory(); +
 +	static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null);
 +
 +	static void closeRequest(const std::string &uuid);
 +	static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height);
 +	void geometryChanged(S32 x, S32 y, S32 width, S32 height);
 +
 +	/* virtual */ BOOL postBuild();
 +	/* virtual */ void onClose(bool app_quitting);
 +	/* virtual */ void draw();
 +
 +	// inherited from LLViewerMediaObserver
 +	/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
 +
 +	void onClickBack();
 +	void onClickForward();
 +	void onClickReload();
 +	void onClickStop();
 +	void onEnterAddress();
 +	void onPopExternal();
 +
 +private:
 +	void open_media(const std::string& media_url, const std::string& target);
 +	void set_current_url(const std::string& url);
 +
 +	LLMediaCtrl* mWebBrowser;
 +	LLComboBox* mAddressCombo;
 +	LLIconCtrl *mSecureLockIcon;
 +	LLTextBox* mStatusBarText;
 +	LLProgressBar* mStatusBarProgress;
 +	std::string mCurrentURL;
 +	std::string mUUID;
 +};
 +
 +#endif  // LL_LLFLOATERWEBCONTENT_H
 diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index bdc0dfa7e2..f74ae92a7b 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -470,7 +470,7 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)  }  //static -bool LLIMFloater::resetAllowedRectPadding(const LLSD& newvalue) +bool LLIMFloater::resetAllowedRectPadding()  {  	//reset allowed rect right padding if "SidebarCameraMovement" option   	//or sidebar state changed @@ -482,10 +482,10 @@ void LLIMFloater::getAllowedRect(LLRect& rect)  {  	if (sAllowedRectRightPadding == RECT_PADDING_NOT_INIT) //wasn't initialized  	{ -		gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2)); +		gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLIMFloater::resetAllowedRectPadding));  		LLSideTray*	side_bar = LLSideTray::getInstance(); -		side_bar->getCollapseSignal().connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2)); +		side_bar->setVisibleWidthChangeCallback(boost::bind(&LLIMFloater::resetAllowedRectPadding));  		sAllowedRectRightPadding = RECT_PADDING_NEED_RECALC;  	} @@ -500,10 +500,7 @@ void LLIMFloater::getAllowedRect(LLRect& rect)  		if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE)  		{ -			LLSideTray*	side_bar = LLSideTray::getInstance(); - -			if (side_bar->getVisible() && !side_bar->getCollapsed()) -				sAllowedRectRightPadding += side_bar->getRect().getWidth(); +			sAllowedRectRightPadding += LLSideTray::getInstance()->getVisibleWidth();  		}  	}  	rect.mRight -= sAllowedRectRightPadding; diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index e80e45e64a..5158f6c1f7 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -156,7 +156,7 @@ private:  	static void closeHiddenIMToasts(); -	static bool resetAllowedRectPadding(const LLSD& newvalue); +	static bool resetAllowedRectPadding();  	//need to keep this static for performance issues  	static S32 sAllowedRectRightPadding; diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 0546803784..d866db1829 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -49,18 +49,421 @@  #include "llnotifications.h"  #include "llwindow.h"  #include "llviewerwindow.h" +#include "llprogressview.h"  #if LL_LINUX || LL_SOLARIS  #include "lltrans.h"  #endif  #include "llsecapi.h"  #include "llstartup.h"  #include "llmachineid.h" +#include "llupdaterservice.h" +#include "llevents.h" +#include "llnotificationsutil.h" +#include "llappviewer.h" + +#include <boost/scoped_ptr.hpp> +#include <sstream> + +class LLLoginInstance::Disposable { +public: +	virtual ~Disposable() {} +}; + +namespace { +	class MandatoryUpdateMachine: +		public LLLoginInstance::Disposable +	{ +	public: +		MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService); +		 +		void start(void); +		 +	private: +		class State; +		class CheckingForUpdate; +		class Error; +		class ReadyToInstall;  +		class StartingUpdaterService; +		class WaitingForDownload; +		 +		LLLoginInstance & mLoginInstance; +		boost::scoped_ptr<State> mState; +		LLUpdaterService & mUpdaterService; +		 +		void setCurrentState(State * newState); +	}; + +	 +	class MandatoryUpdateMachine::State { +	public: +		virtual ~State() {} +		virtual void enter(void) {} +		virtual void exit(void) {} +	}; +	 +	 +	class MandatoryUpdateMachine::CheckingForUpdate: +	public MandatoryUpdateMachine::State +	{ +	public: +		CheckingForUpdate(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		 +	private: +		LLTempBoundListener mConnection; +		MandatoryUpdateMachine & mMachine; +		LLProgressView * mProgressView; +		 +		bool onEvent(LLSD const & event); +	}; +	 +	 +	class MandatoryUpdateMachine::Error: +	public MandatoryUpdateMachine::State +	{ +	public: +		Error(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		void onButtonClicked(const LLSD &, const LLSD &); +		 +	private: +		MandatoryUpdateMachine & mMachine; +	}; +	 +	 +	class MandatoryUpdateMachine::ReadyToInstall: +	public MandatoryUpdateMachine::State +	{ +	public: +		ReadyToInstall(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		 +	private: +		MandatoryUpdateMachine & mMachine; +	}; +	 +	 +	class MandatoryUpdateMachine::StartingUpdaterService: +	public MandatoryUpdateMachine::State +	{ +	public: +		StartingUpdaterService(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		void onButtonClicked(const LLSD & uiform, const LLSD & result); +	private: +		MandatoryUpdateMachine & mMachine; +	}; +	 +	 +	class MandatoryUpdateMachine::WaitingForDownload: +		public MandatoryUpdateMachine::State +	{ +	public: +		WaitingForDownload(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		 +	private: +		LLTempBoundListener mConnection; +		MandatoryUpdateMachine & mMachine; +		LLProgressView * mProgressView; +		 +		bool onEvent(LLSD const & event); +	}; +}  static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";  static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";  std::string construct_start_string(); + + +// MandatoryUpdateMachine +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService): +	mLoginInstance(loginInstance), +	mUpdaterService(updaterService) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::start(void) +{ +	llinfos << "starting manditory update machine" << llendl; +	 +	if(mUpdaterService.isChecking()) { +		switch(mUpdaterService.getState()) { +			case LLUpdaterService::UP_TO_DATE: +				mUpdaterService.stopChecking(); +				mUpdaterService.startChecking(); +				// Fall through. +			case LLUpdaterService::INITIAL: +			case LLUpdaterService::CHECKING_FOR_UPDATE: +				setCurrentState(new CheckingForUpdate(*this)); +				break; +			case LLUpdaterService::DOWNLOADING: +				setCurrentState(new WaitingForDownload(*this)); +				break; +			case LLUpdaterService::TERMINAL: +				if(LLUpdaterService::updateReadyToInstall()) { +					setCurrentState(new ReadyToInstall(*this)); +				} else { +					setCurrentState(new Error(*this)); +				} +				break; +			case LLUpdaterService::FAILURE: +				setCurrentState(new Error(*this)); +				break; +			default: +				llassert(!"unpossible case"); +				break; +		} +	} else { +		setCurrentState(new StartingUpdaterService(*this)); +	} +} + + +void MandatoryUpdateMachine::setCurrentState(State * newStatePointer) +{ +	{ +		boost::scoped_ptr<State> newState(newStatePointer); +		if(mState != 0) mState->exit(); +		mState.swap(newState); +		 +		// Old state will be deleted on exit from this block before the new state +		// is entered. +	} +	if(mState != 0) mState->enter(); +} + + + +// MandatoryUpdateMachine::CheckingForUpdate +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::CheckingForUpdate::CheckingForUpdate(MandatoryUpdateMachine & machine): +	mMachine(machine) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::CheckingForUpdate::enter(void) +{ +	llinfos << "entering checking for update" << llendl; +	 +	mProgressView = gViewerWindow->getProgressView(); +	mProgressView->setMessage("Looking for update..."); +	mProgressView->setText("There is a required update for your Second Life installation."); +	mProgressView->setPercent(0); +	mProgressView->setVisible(true); +	mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()). +		listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::CheckingForUpdate::onEvent, this, _1)); +} + + +void MandatoryUpdateMachine::CheckingForUpdate::exit(void) +{ +} + + +bool MandatoryUpdateMachine::CheckingForUpdate::onEvent(LLSD const & event) +{ +	if(event["type"].asInteger() == LLUpdaterService::STATE_CHANGE) { +		switch(event["state"].asInteger()) { +			case LLUpdaterService::DOWNLOADING: +				mMachine.setCurrentState(new WaitingForDownload(mMachine)); +				break; +			case LLUpdaterService::UP_TO_DATE: +			case LLUpdaterService::TERMINAL: +			case LLUpdaterService::FAILURE: +				mProgressView->setVisible(false); +				mMachine.setCurrentState(new Error(mMachine)); +				break; +			case LLUpdaterService::INSTALLING: +				llassert(!"can't possibly be installing"); +				break; +			default: +				break; +		} +	} else { +		; // Ignore. +	} +	 +	return false; +} + + + +// MandatoryUpdateMachine::Error +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::Error::Error(MandatoryUpdateMachine & machine): +	mMachine(machine) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::Error::enter(void) +{ +	llinfos << "entering error" << llendl; +	LLNotificationsUtil::add("FailedUpdateInstall", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::Error::onButtonClicked, this, _1, _2)); +} + + +void MandatoryUpdateMachine::Error::exit(void) +{ +	LLAppViewer::instance()->forceQuit(); +} + + +void MandatoryUpdateMachine::Error::onButtonClicked(const LLSD &, const LLSD &) +{ +	mMachine.setCurrentState(0); +} + + + +// MandatoryUpdateMachine::ReadyToInstall +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::ReadyToInstall::ReadyToInstall(MandatoryUpdateMachine & machine): +	mMachine(machine) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::ReadyToInstall::enter(void) +{ +	llinfos << "entering ready to install" << llendl; +	// Open update ready dialog. +} + + +void MandatoryUpdateMachine::ReadyToInstall::exit(void) +{ +	// Restart viewer. +} + + + +// MandatoryUpdateMachine::StartingUpdaterService +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::StartingUpdaterService::StartingUpdaterService(MandatoryUpdateMachine & machine): +	mMachine(machine) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::StartingUpdaterService::enter(void) +{ +	llinfos << "entering start update service" << llendl; +	LLNotificationsUtil::add("UpdaterServiceNotRunning", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked, this, _1, _2)); +} + + +void MandatoryUpdateMachine::StartingUpdaterService::exit(void) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked(const LLSD & uiform, const LLSD & result) +{ +	if(result["OK_okcancelbuttons"].asBoolean()) { +		mMachine.mUpdaterService.startChecking(false); +		mMachine.setCurrentState(new CheckingForUpdate(mMachine)); +	} else { +		LLAppViewer::instance()->forceQuit(); +	} +} + + + +// MandatoryUpdateMachine::WaitingForDownload +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::WaitingForDownload::WaitingForDownload(MandatoryUpdateMachine & machine): +	mMachine(machine), +	mProgressView(0) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::WaitingForDownload::enter(void) +{ +	llinfos << "entering waiting for download" << llendl; +	mProgressView = gViewerWindow->getProgressView(); +	mProgressView->setMessage("Downloading update..."); +	std::ostringstream stream; +	stream << "There is a required update for your Second Life installation." << std::endl << +		"Version " << mMachine.mUpdaterService.updatedVersion(); +	mProgressView->setText(stream.str()); +	mProgressView->setPercent(0); +	mProgressView->setVisible(true); +	mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()). +		listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::WaitingForDownload::onEvent, this, _1)); +} + + +void MandatoryUpdateMachine::WaitingForDownload::exit(void) +{ +	mProgressView->setVisible(false); +} + + +bool MandatoryUpdateMachine::WaitingForDownload::onEvent(LLSD const & event) +{ +	switch(event["type"].asInteger()) { +		case LLUpdaterService::DOWNLOAD_COMPLETE: +			mMachine.setCurrentState(new ReadyToInstall(mMachine)); +			break; +		case LLUpdaterService::DOWNLOAD_ERROR: +			mMachine.setCurrentState(new Error(mMachine)); +			break; +		case LLUpdaterService::PROGRESS: { +			double downloadSize = event["download_size"].asReal(); +			double bytesDownloaded = event["bytes_downloaded"].asReal(); +			mProgressView->setPercent(100. * bytesDownloaded / downloadSize); +			break; +		} +		default: +			break; +	} + +	return false; +} + + + +// LLLoginInstance +//----------------------------------------------------------------------------- + +  LLLoginInstance::LLLoginInstance() :  	mLoginModule(new LLLogin()),  	mNotifications(NULL), @@ -69,7 +472,8 @@ LLLoginInstance::LLLoginInstance() :  	mSkipOptionalUpdate(false),  	mAttemptComplete(false),  	mTransferRate(0.0f), -	mDispatcher("LLLoginInstance", "change") +	mDispatcher("LLLoginInstance", "change"), +	mUpdaterService(0)  {  	mLoginModule->getEventPump().listen("lllogininstance",   		boost::bind(&LLLoginInstance::handleLoginEvent, this, _1)); @@ -354,6 +758,15 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)  void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg)  { +	if(mandatory) +	{ +		gViewerWindow->setShowProgress(false); +		MandatoryUpdateMachine * machine = new MandatoryUpdateMachine(*this, *mUpdaterService); +		mUpdateStateMachine.reset(machine); +		machine->start(); +		return; +	} +	  	// store off config state, as we might quit soon  	gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);	  	LLUIColorTable::instance().saveUserSettings(); diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index 159e05046c..b872d7d1b1 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -34,12 +34,15 @@  class LLLogin;  class LLEventStream;  class LLNotificationsInterface; +class LLUpdaterService;  // This class hosts the login module and is used to   // negotiate user authentication attempts.  class LLLoginInstance : public LLSingleton<LLLoginInstance>  {  public: +	class Disposable; +  	LLLoginInstance();  	~LLLoginInstance(); @@ -75,6 +78,7 @@ public:  	typedef boost::function<void()> UpdaterLauncherCallback;  	void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; } +	void setUpdaterService(LLUpdaterService * updaterService) { mUpdaterService = updaterService; }  private:  	void constructAuthParams(LLPointer<LLCredential> user_credentials);  	void updateApp(bool mandatory, const std::string& message); @@ -104,6 +108,8 @@ private:  	int mLastExecEvent;  	UpdaterLauncherCallback mUpdaterLauncher;  	LLEventDispatcher mDispatcher; +	LLUpdaterService * mUpdaterService;	 +	boost::scoped_ptr<Disposable> mUpdateStateMachine;  };  #endif diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 0f66713ab0..9493fddf50 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -25,7 +25,7 @@   */  #include "llviewerprecompiledheaders.h" - +#include "lltooltip.h"  #include "llmediactrl.h" @@ -54,6 +54,10 @@  #include "llbutton.h"  #include "llcheckboxctrl.h"  #include "llnotifications.h" +#include "lllineeditor.h" +#include "llfloatermediabrowser.h" +#include "llfloaterwebcontent.h" +#include "llwindowshade.h"  extern BOOL gRestoreGL; @@ -98,7 +102,9 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  	mTextureHeight ( 1024 ),  	mClearCache(false),  	mHomePageMimeType(p.initial_mime_type), -	mTrusted(p.trusted_content) +	mTrusted(p.trusted_content), +	mWindowShade(NULL), +	mHoverTextChanged(false)  {  	{  		LLColor4 color = p.caret_color().get(); @@ -127,7 +133,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  		setTextureSize(screen_width, screen_height);  	} -	mMediaTextureID.generate(); +	mMediaTextureID = getKey();  	// We don't need to create the media source up front anymore unless we have a non-empty home URL to navigate to.  	if(!mHomePageUrl.empty()) @@ -141,8 +147,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  //	addChild( mBorder );  } -//////////////////////////////////////////////////////////////////////////////// -// note: this is now a singleton and destruction happens via initClass() now  LLMediaCtrl::~LLMediaCtrl()  { @@ -182,6 +186,13 @@ BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask )  		mMediaSource->mouseMove(x, y, mask);  		gViewerWindow->setCursor(mMediaSource->getLastSetCursor());  	} +	 +	// TODO: Is this the right way to handle hover text changes driven by the plugin? +	if(mHoverTextChanged) +	{ +		mHoverTextChanged = false; +		handleToolTip(x, y, mask); +	}  	return TRUE;  } @@ -198,6 +209,35 @@ BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks )  }  //////////////////////////////////////////////////////////////////////////////// +//	virtual  +BOOL LLMediaCtrl::handleToolTip(S32 x, S32 y, MASK mask) +{ +	std::string hover_text; +	 +	if (mMediaSource && mMediaSource->hasMedia()) +		hover_text = mMediaSource->getMediaPlugin()->getHoverText(); +	 +	if(hover_text.empty()) +	{ +		return FALSE; +	} +	else +	{ +		S32 screen_x, screen_y; + +		localPointToScreen(x, y, &screen_x, &screen_y); +		LLRect sticky_rect_screen; +		sticky_rect_screen.setCenterAndSize(screen_x, screen_y, 20, 20); + +		LLToolTipMgr::instance().show(LLToolTip::Params() +			.message(hover_text) +			.sticky_rect(sticky_rect_screen));		 +	} + +	return TRUE; +} + +////////////////////////////////////////////////////////////////////////////////  //  BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask )  { @@ -338,85 +378,6 @@ void LLMediaCtrl::onFocusLost()  //  BOOL LLMediaCtrl::postBuild ()  { -	LLLayoutStack::Params layout_p; -	layout_p.name = "notification_stack"; -	layout_p.rect = LLRect(0,getLocalRect().mTop,getLocalRect().mRight, 30); -	layout_p.follows.flags = FOLLOWS_ALL; -	layout_p.mouse_opaque = false; -	layout_p.orientation = "vertical"; - -	LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); -	addChild(stackp); - -	LLLayoutPanel::Params panel_p; -	panel_p.rect = LLRect(0, 30, 800, 0); -	panel_p.min_height = 30; -	panel_p.name = "notification_area"; -	panel_p.visible = false; -	panel_p.user_resize = false; -	panel_p.background_visible = true; -	panel_p.bg_alpha_image.name = "Yellow_Gradient"; -	panel_p.auto_resize = false; -	LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(notification_panel); - -	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); -	panel_p.auto_resize = true; -	panel_p.mouse_opaque = false; -	LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(dummy_panel); - -	layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>(); -	layout_p.rect = LLRect(0, 30, 800, 0); -	layout_p.follows.flags = FOLLOWS_ALL; -	layout_p.orientation = "horizontal"; -	stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); -	notification_panel->addChild(stackp); - -	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); -	panel_p.rect.height = 30; -	LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(panel); - -	LLIconCtrl::Params icon_p; -	icon_p.name = "notification_icon"; -	icon_p.rect = LLRect(5, 23, 21, 8); -	panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); - -	LLTextBox::Params text_p; -	text_p.rect = LLRect(31, 20, 430, 0); -	text_p.text_color = LLColor4::black; -	text_p.font = LLFontGL::getFontSansSerif(); -	text_p.font.style = "BOLD"; -	text_p.name = "notification_text"; -	text_p.use_ellipses = true; -	panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); - -	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); -	panel_p.auto_resize = false; -	panel_p.user_resize = false; -	panel_p.name="form_elements"; -	panel_p.rect = LLRect(0, 30, 130, 0); -	LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(form_elements_panel); - -	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); -	panel_p.auto_resize = false; -	panel_p.user_resize = false; -	panel_p.rect = LLRect(0, 30, 25, 0); -	LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(close_panel); - -	LLButton::Params button_p; -	button_p.name = "close_notification"; -	button_p.rect = LLRect(5, 23, 21, 7); -	button_p.image_color=LLUIColorTable::instance().getColor("DkGray_66"); -    button_p.image_unselected.name="Icon_Close_Foreground"; -	button_p.image_selected.name="Icon_Close_Press"; -	button_p.click_callback.function = boost::bind(&LLMediaCtrl::onCloseNotification, this); - -	close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); -  	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2));  	return TRUE;  } @@ -425,13 +386,15 @@ BOOL LLMediaCtrl::postBuild ()  //  BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )  { -	if (LLPanel::handleKeyHere(key, mask)) return TRUE;  	BOOL result = FALSE;  	if (mMediaSource)  	{  		result = mMediaSource->handleKeyHere(key, mask);  	} +	 +	if ( ! result ) +		result = LLPanel::handleKeyHere(key, mask);  	return result;  } @@ -451,7 +414,6 @@ void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility )  //  BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)  { -	if (LLPanel::handleUnicodeCharHere(uni_char)) return TRUE;  	BOOL result = FALSE;  	if (mMediaSource) @@ -459,6 +421,9 @@ BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)  		result = mMediaSource->handleUnicodeCharHere(uni_char);  	} +	if ( ! result ) +		result = LLPanel::handleUnicodeCharHere(uni_char); +  	return result;  } @@ -914,11 +879,6 @@ void LLMediaCtrl::draw()  	if ( mBorder && mBorder->getVisible() )  		mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) ); -	if (mCurNotification && !mCurNotification->isActive()) -	{ -		hideNotification(); -	} -	  	LLPanel::draw();  	// Restore the previous values @@ -1026,7 +986,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  			LLNotification::Params notify_params;  			notify_params.name = "PopupAttempt"; -			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", getKey()); +			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID);  			notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2);  			if (mTrusted) @@ -1081,6 +1041,31 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;  		}  		break; + +		case MEDIA_EVENT_AUTH_REQUEST: +		{ +			LLNotification::Params auth_request_params; +			auth_request_params.name = "AuthRequest"; + +			// pass in host name and realm for site (may be zero length but will always exist) +			LLSD args; +			LLURL raw_url( self->getAuthURL().c_str() ); +			args["HOST_NAME"] = raw_url.getAuthority(); +			args["REALM"] = self->getAuthRealm(); +			auth_request_params.substitutions = args; + +			auth_request_params.payload = LLSD().with("media_id", mMediaTextureID); +			auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); +			LLNotifications::instance().add(auth_request_params); +		}; +		break; + +		case MEDIA_EVENT_LINK_HOVERED: +		{ +			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL; +			mHoverTextChanged = true; +		}; +		break;  	};  	// chain all events to any potential observers of this object. @@ -1098,109 +1083,85 @@ void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response)  {  	if (response["open"])  	{ -		LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]); +		// name of default floater to open +		std::string floater_name = "media_browser"; + +		// look for parent floater name +		if ( gFloaterView ) +		{ +			if ( gFloaterView->getParentFloater(this) ) +			{ +				floater_name = gFloaterView->getParentFloater(this)->getInstanceName(); +			} +			else +			{ +				lldebugs << "No gFloaterView->getParentFloater(this) for onPopuup()" << llendl; +			}; +		} +		else +		{ +			lldebugs << "No gFloaterView for onPopuup()" << llendl; +		}; + +		// (for now) open web content floater if that's our parent, otherwise, open the current media floater +		// (this will change soon) +		if ( floater_name == "web_content" ) +		{ +			LLWeb::loadWebURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]); +		} +		else +		{ +			LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]); +		}  	}  	else  	{  		// Make sure the opening instance knows its window open request was denied, so it can clean things up.  		LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]);  	} -  } -void LLMediaCtrl::onCloseNotification() -{ -	LLNotifications::instance().cancel(mCurNotification); -} - -void LLMediaCtrl::onClickIgnore(LLUICtrl* ctrl) +void LLMediaCtrl::showNotification(LLNotificationPtr notify)  { -	bool check = ctrl->getValue().asBoolean(); -	if (mCurNotification && mCurNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) +	delete mWindowShade; + +	LLWindowShade::Params params; +	params.name = "notification_shade"; +	params.rect = getLocalRect(); +	params.follows.flags = FOLLOWS_ALL; +	params.notification = notify; +	params.modal = true; +	//HACK: don't hardcode this +	if (notify->getIcon() == "Popup_Caution")  	{ -		// question was "show again" so invert value to get "ignore" -		check = !check; +		params.bg_image.name = "Yellow_Gradient"; +		params.text_color = LLColor4::black;  	} -	mCurNotification->setIgnored(check); -} - -void LLMediaCtrl::onClickNotificationButton(const std::string& name) -{ -	if (!mCurNotification) return; - -	LLSD response = mCurNotification->getResponseTemplate(); -	response[name] = true; - -	mCurNotification->respond(response);  -} - -void LLMediaCtrl::showNotification(LLNotificationPtr notify) -{ -	mCurNotification = notify; - -	// add popup here -	LLSD payload = notify->getPayload(); - -	LLNotificationFormPtr formp = notify->getForm(); -	LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); -	panel.setVisible(true); -	panel.getChild<LLUICtrl>("notification_icon")->setValue(notify->getIcon()); -	panel.getChild<LLUICtrl>("notification_text")->setValue(notify->getMessage()); -	panel.getChild<LLUICtrl>("notification_text")->setToolTip(notify->getMessage()); -	LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType();  -	LLLayoutPanel& form_elements = panel.getChildRef<LLLayoutPanel>("form_elements"); -	form_elements.deleteAllChildren(); - -	const S32 FORM_PADDING_HORIZONTAL = 10; -	const S32 FORM_PADDING_VERTICAL = 3; -	S32 cur_x = FORM_PADDING_HORIZONTAL; - -	if (ignore_type != LLNotificationForm::IGNORE_NO) +	else +	//HACK: another one since XUI doesn't support what we need right now +	if (notify->getName() == "AuthRequest")  	{ -		LLCheckBoxCtrl::Params checkbox_p; -		checkbox_p.name = "ignore_check"; -		checkbox_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); -		checkbox_p.label = formp->getIgnoreMessage(); -		checkbox_p.label_text.text_color = LLColor4::black; -		checkbox_p.commit_callback.function = boost::bind(&LLMediaCtrl::onClickIgnore, this, _1); -		checkbox_p.initial_value = formp->getIgnored(); - -		LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); -		check->setRect(check->getBoundingRect()); -		form_elements.addChild(check); -		cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL; +		params.bg_image.name = "Yellow_Gradient"; +		params.text_color = LLColor4::black; +		params.can_close = false;  	} - -	for (S32 i = 0; i < formp->getNumElements(); i++) +	else  	{ -		LLSD form_element = formp->getElement(i); -		if (form_element["type"].asString() == "button") -		{ -			LLButton::Params button_p; -			button_p.name = form_element["name"]; -			button_p.label = form_element["text"]; -			button_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); -			button_p.click_callback.function = boost::bind(&LLMediaCtrl::onClickNotificationButton, this, form_element["name"].asString()); -			button_p.auto_resize = true; - -			LLButton* button = LLUICtrlFactory::create<LLButton>(button_p); -			button->autoResize(); -			form_elements.addChild(button); - -			cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL; -		} +		//HACK: make this a property of the notification itself, "cancellable" +		params.can_close = false; +		params.text_color.control = "LabelTextColor";  	} +	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params); -	form_elements.reshape(cur_x, form_elements.getRect().getHeight()); - -	//LLWeb::loadURL(payload["url"], payload["target"]); +	addChild(mWindowShade); +	mWindowShade->show();  }  void LLMediaCtrl::hideNotification()  { -	LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); -	panel.setVisible(FALSE); - -	mCurNotification.reset(); +	if (mWindowShade) +	{ +		mWindowShade->hide(); +	}  } diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 96bb0c1df5..38a74f90d3 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -90,6 +90,7 @@ public:  		virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);  		virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask );  		virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); +		virtual BOOL handleToolTip(S32 x, S32 y, MASK mask);  		// navigation  		void navigateTo( std::string url_in, std::string mime_type = ""); @@ -168,9 +169,6 @@ public:  	private:  		void onVisibilityChange ( const LLSD& new_visibility );  		void onPopup(const LLSD& notification, const LLSD& response); -		void onCloseNotification(); -		void onClickNotificationButton(const std::string& name); -		void onClickIgnore(LLUICtrl* ctrl);  		const S32 mTextureDepthBytes;  		LLUUID mMediaTextureID; @@ -194,7 +192,8 @@ public:  		S32 mTextureWidth;  		S32 mTextureHeight;  		bool mClearCache; -		boost::shared_ptr<class LLNotification> mCurNotification; +		class LLWindowShade* mWindowShade; +		bool mHoverTextChanged;  };  #endif // LL_LLMediaCtrl_H diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index dd2dcffc28..d2f76eceb0 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1450,17 +1450,21 @@ void LLMeshUploadThread::DecompRequest::completed()  	mThread->mHullMap[mBaseModel] = mHull[0];  } -void LLMeshUploadThread::run() +//called in the main thread. +void LLMeshUploadThread::preStart()  { -	mCurlRequest = new LLCurlRequest(); -  	//build map of LLModel refs to instances for callbacks  	for (instance_list::iterator iter = mInstanceList.begin(); iter != mInstanceList.end(); ++iter)  	{  		mInstance[iter->mModel].push_back(*iter);  	} +} + +void LLMeshUploadThread::run() +{ +	mCurlRequest = new LLCurlRequest();	 -	std::set<LLPointer<LLViewerTexture> > textures; +	std::set<LLViewerTexture* > textures;  	//populate upload queue with relevant models  	for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) @@ -1483,9 +1487,9 @@ void LLMeshUploadThread::run()  				material_iter != instance.mMaterial.end(); ++material_iter)  			{ -				if (textures.find(material_iter->mDiffuseMap) == textures.end()) +				if (textures.find(material_iter->mDiffuseMap.get()) == textures.end())  				{ -					textures.insert(material_iter->mDiffuseMap); +					textures.insert(material_iter->mDiffuseMap.get());  					LLTextureUploadData data(material_iter->mDiffuseMap.get(), material_iter->mDiffuseMapLabel);  					uploadTexture(data); @@ -2148,6 +2152,7 @@ S32 LLMeshRepository::update()  	for (S32 i = 0; i < size; ++i)  	{  		mUploads.push_back(mUploadWaitList[i]); +		mUploadWaitList[i]->preStart() ;  		mUploadWaitList[i]->start() ;  	}  	mUploadWaitList.clear() ; diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 8c9892b28f..eccb82b661 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -431,6 +431,7 @@ public:  	bool finished() { return mFinished; }  	virtual void run(); +	void preStart();  }; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 2e4be78be1..5f89097c17 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -73,7 +73,6 @@  #endif  // LL_WINDOWS  #include "llsdserialize.h" -#define USE_VIEWER_AUTH 0  const S32 BLACK_BORDER_HEIGHT = 160;  const S32 MAX_PASSWORD = 16; @@ -190,10 +189,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  	buildFromFile( "panel_login.xml"); -#if USE_VIEWER_AUTH -	//leave room for the login menu bar -	setRect(LLRect(0, rect.getHeight()-18, rect.getWidth(), 0));  -#endif  	// Legacy login web page is hidden under the menu bar.  	// Adjust reg-in-client web browser widget to not be hidden.  	if (gSavedSettings.getBOOL("RegInClient")) @@ -205,16 +200,12 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  		reshape(rect.getWidth(), rect.getHeight());  	} -#if !USE_VIEWER_AUTH  	getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);  	// change z sort of clickable text to be behind buttons  	//sendChildToBack(getChildView("channel_text"));  	sendChildToBack(getChildView("forgot_password_text")); -	LLLineEditor* edit = getChild<LLLineEditor>("password_edit"); -	if (edit) edit->setDrawAsterixes(TRUE); -  	if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION)  	{  		LLSLURL slurl(gSavedSettings.getString("LoginLocation")); @@ -248,7 +239,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  	LLTextBox* need_help_text = getChild<LLTextBox>("login_help");  	need_help_text->setClickedCallback(onClickHelp, NULL); -#endif      	// get the web browser control  	LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html"); @@ -275,15 +265,9 @@ void LLPanelLogin::reshapeBrowser()  	LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");  	LLRect rect = gViewerWindow->getWindowRectScaled();  	LLRect html_rect; -#if USE_VIEWER_AUTH -	html_rect.setCenterAndSize(  -		rect.getCenterX() - 2, rect.getCenterY(),  -		rect.getWidth() + 6, rect.getHeight()); -#else  	html_rect.setCenterAndSize(  		rect.getCenterX() - 2, rect.getCenterY() + 40,  		rect.getWidth() + 6, rect.getHeight() - 78 ); -#endif  	web_browser->setRect( html_rect );  	web_browser->reshape( html_rect.getWidth(), html_rect.getHeight(), TRUE );  	reshape( rect.getWidth(), rect.getHeight(), 1 ); @@ -306,7 +290,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive )  	else  	// the site is not available (missing page, server down, other badness)  	{ -#if !USE_VIEWER_AUTH  		if ( web_browser )  		{  			// hide browser control (revealing default one) @@ -315,16 +298,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive )  			// mark as unavailable  			mHtmlAvailable = FALSE;  		} -#else - -		if ( web_browser ) -		{	 -			web_browser->navigateToLocalPage( "loading-error" , "index.html" ); - -			// mark as available -			mHtmlAvailable = TRUE; -		} -#endif  	}  } @@ -364,7 +337,6 @@ void LLPanelLogin::draw()  		if ( mHtmlAvailable )  		{ -#if !USE_VIEWER_AUTH  			if (getChild<LLView>("login_widgets")->getVisible())  			{  				// draw a background box in black @@ -373,7 +345,6 @@ void LLPanelLogin::draw()  				// just the blue background to the native client UI  				mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight());  			} -#endif  		}  		else  		{ @@ -419,12 +390,6 @@ void LLPanelLogin::setFocus(BOOL b)  // static  void LLPanelLogin::giveFocus()  { -#if USE_VIEWER_AUTH -	if (sInstance) -	{ -		sInstance->setFocus(TRUE); -	} -#else  	if( sInstance )  	{  		// Grab focus and move cursor to first blank input field @@ -453,17 +418,18 @@ void LLPanelLogin::giveFocus()  			edit->selectAll();  		}  	} -#endif  }  // static  void LLPanelLogin::showLoginWidgets()  { +	// *NOTE: Mani - This may or may not be obselete code. +	// It seems to be part of the defunct? reg-in-client project.  	sInstance->getChildView("login_widgets")->setVisible( true);  	LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");  	sInstance->reshapeBrowser();  	// *TODO: Append all the usual login parameters, like first_login=Y etc. -	std::string splash_screen_url = sInstance->getString("real_url"); +	std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage();  	web_browser->navigateTo( splash_screen_url, "text/html" );  	LLUICtrl* username_edit = sInstance->getChild<LLUICtrl>("username_edit");  	username_edit->setFocus(TRUE); @@ -833,73 +799,6 @@ void LLPanelLogin::loadLoginPage()  	curl_free(curl_grid);  	gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());  	gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor()); - - -#if USE_VIEWER_AUTH -	LLURLSimString::sInstance.parse(); - -	std::string location; -	std::string region; -	std::string password; -	 -	if (LLURLSimString::parse()) -	{ -		std::ostringstream oRegionStr; -		location = "specify"; -		oRegionStr << LLURLSimString::sInstance.mSimName << "/" << LLURLSimString::sInstance.mX << "/" -			 << LLURLSimString::sInstance.mY << "/" -			 << LLURLSimString::sInstance.mZ; -		region = oRegionStr.str(); -	} -	else -	{ -		location = gSavedSettings.getString("LoginLocation"); -	} -	 -	std::string username; - -    if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3) -    { -        LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo"); -		username = cmd_line_login[0].asString() + " " + cmd_line_login[1]; -        password = cmd_line_login[2].asString(); -    } -    	 -	 -	char* curl_region = curl_escape(region.c_str(), 0); - -	oStr <<"username=" << username << -		 "&location=" << location <<	"®ion=" << curl_region; -	 -	curl_free(curl_region); - -	if (!password.empty()) -	{ -		oStr << "&password=" << password; -	} -	else if (!(password = load_password_from_disk()).empty()) -	{ -		oStr << "&password=$1$" << password; -	} -	if (gAutoLogin) -	{ -		oStr << "&auto_login=TRUE"; -	} -	if (gSavedSettings.getBOOL("ShowStartLocation")) -	{ -		oStr << "&show_start_location=TRUE"; -	}	 -	if (gSavedSettings.getBOOL("RememberPassword")) -	{ -		oStr << "&remember_password=TRUE"; -	}	 -#ifndef	LL_RELEASE_FOR_DOWNLOAD -	oStr << "&show_grid=TRUE"; -#else -	if (gSavedSettings.getBOOL("ForceShowGrid")) -		oStr << "&show_grid=TRUE"; -#endif -#endif  	LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 1869e92c8c..00ac34efa5 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -753,6 +753,11 @@ void LLPanelPlaces::onOverflowButtonClicked()  		// there is no landmark already pointing to that parcel in agent's inventory.  		menu->getChild<LLMenuItemCallGL>("landmark")->setEnabled(is_agent_place_info_visible &&  																 !LLLandmarkActions::landmarkAlreadyExists()); +		// STORM-411 +		// Creating landmarks for remote locations is impossible. +		// So hide menu item "Make a Landmark" in "Teleport History Profile" panel. +		menu->setItemVisible("landmark", mPlaceInfoType != TELEPORT_HISTORY_INFO_TYPE); +		menu->arrangeAndClear();  	}  	else if (mPlaceInfoType == LANDMARK_INFO_TYPE && mLandmarkMenu != NULL)  	{ diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index b5fd4145f2..68f50148f9 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -59,6 +59,7 @@  #include "llvovolume.h"  #include "llweb.h"  #include "llwindow.h" +#include "llwindowshade.h"  #include "llfloatertools.h"  // to enable hide if build tools are up  #include "llvector4a.h" @@ -91,7 +92,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :  	mTargetObjectNormal(LLVector3::zero),  	mZoomObjectID(LLUUID::null),  	mZoomObjectFace(0), -	mVolumeSliderVisible(0) +	mVolumeSliderVisible(0), +	mWindowShade(NULL)  {  	mCommitCallbackRegistrar.add("MediaCtrl.Close",		boost::bind(&LLPanelPrimMediaControls::onClickClose, this));  	mCommitCallbackRegistrar.add("MediaCtrl.Back",		boost::bind(&LLPanelPrimMediaControls::onClickBack, this)); @@ -206,6 +208,9 @@ BOOL LLPanelPrimMediaControls::postBuild()  	mMediaAddress->setFocusReceivedCallback(boost::bind(&LLPanelPrimMediaControls::onInputURL, _1, this )); +	LLWindowShade::Params window_shade_params; +	window_shade_params.name = "window_shade"; +  	mCurrentZoom = ZOOM_NONE;  	// clicks on buttons do not remove keyboard focus from media  	setIsChrome(TRUE); @@ -701,6 +706,24 @@ void LLPanelPrimMediaControls::updateShape()  /*virtual*/  void LLPanelPrimMediaControls::draw()  { +	LLViewerMediaImpl* impl = getTargetMediaImpl(); +	if (impl) +	{ +		LLNotificationPtr notification = impl->getCurrentNotification(); +		if (notification != mActiveNotification) +		{ +			mActiveNotification = notification; +			if (notification) +			{ +				showNotification(notification); +			} +			else +			{ +				hideNotification(); +			} +		} +	} +  	F32 alpha = getDrawContext().mAlpha;  	if(mFadeTimer.getStarted())  	{ @@ -1298,3 +1321,38 @@ bool LLPanelPrimMediaControls::shouldVolumeSliderBeVisible()  {  	return mVolumeSliderVisible > 0;  } + +void LLPanelPrimMediaControls::showNotification(LLNotificationPtr notify) +{ +	delete mWindowShade; +	LLWindowShade::Params params; +	params.rect = mMediaRegion->getLocalRect(); +	params.follows.flags = FOLLOWS_ALL; +	params.notification = notify; + +	//HACK: don't hardcode this +	if (notify->getIcon() == "Popup_Caution") +	{ +		params.bg_image.name = "Yellow_Gradient"; +		params.text_color = LLColor4::black; +	} +	else +	{ +		//HACK: make this a property of the notification itself, "cancellable" +		params.can_close = false; +		params.text_color.control = "LabelTextColor"; +	} + +	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params); + +	mMediaRegion->addChild(mWindowShade); +	mWindowShade->show(); +} + +void LLPanelPrimMediaControls::hideNotification() +{ +	if (mWindowShade) +	{ +		mWindowShade->hide(); +	} +} diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h index 3ec24f0e24..0b9664359c 100644 --- a/indra/newview/llpanelprimmediacontrols.h +++ b/indra/newview/llpanelprimmediacontrols.h @@ -29,6 +29,7 @@  #include "llpanel.h"  #include "llviewermedia.h" +#include "llnotificationptr.h"  class LLButton;  class LLCoordWindow; @@ -37,6 +38,7 @@ class LLLayoutStack;  class LLProgressBar;  class LLSliderCtrl;  class LLViewerMediaImpl; +class LLWindowShade;  class LLPanelPrimMediaControls : public LLPanel  { @@ -54,6 +56,9 @@ public:  	void updateShape();  	bool isMouseOver(); +	void showNotification(LLNotificationPtr notify); +	void hideNotification(); +  	enum EZoomLevel  	{  		ZOOM_NONE = 0, @@ -162,6 +167,7 @@ private:  	LLUICtrl *mRightBookend;  	LLUIImage* mBackgroundImage;  	LLUIImage* mVolumeSliderBackgroundImage; +	LLWindowShade* mWindowShade;  	F32 mSkipStep;  	S32 mMinWidth;  	S32 mMinHeight; @@ -204,6 +210,8 @@ private:  	S32 mZoomObjectFace;  	S32 mVolumeSliderVisible; + +	LLNotificationPtr mActiveNotification;  };  #endif // LL_PANELPRIMMEDIACONTROLS_H diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index db02d76139..31fde5d58a 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -133,13 +133,13 @@ void LLProgressView::setVisible(BOOL visible)  		mFadeTimer.start();  	}  	// showing progress view -	else if (!getVisible() && visible) +	else if (visible && (!getVisible() || mFadeTimer.getStarted()))  	{  		setFocus(TRUE);  		mFadeTimer.stop();  		mProgressTimer.start();  		LLPanel::setVisible(TRUE); -	} +	}   } diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 0eeb89792b..e3bc67a414 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -83,11 +83,10 @@ bool  LLScreenChannelBase::isHovering()  	return mHoveredToast->isHovered();  } -bool LLScreenChannelBase::resetPositionAndSize(const LLSD& newvalue) +void LLScreenChannelBase::resetPositionAndSize()  {  	LLRect rc = gViewerWindow->getWorldViewRectScaled();  	updatePositionAndSize(rc, rc); -	return true;  }  void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect) @@ -99,10 +98,7 @@ void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect ne  	if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE  		&& LLSideTray::instanceCreated	())  	{ -		LLSideTray*	side_bar = LLSideTray::getInstance(); - -		if (side_bar->getVisible() && !side_bar->getCollapsed()) -			world_rect_padding += side_bar->getRect().getWidth(); +		world_rect_padding += LLSideTray::getInstance()->getVisibleWidth();  	} @@ -133,7 +129,7 @@ void LLScreenChannelBase::init(S32 channel_left, S32 channel_right)  	if(LLSideTray::instanceCreated())  	{  		LLSideTray*	side_bar = LLSideTray::getInstance(); -		side_bar->getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, this, _2)); +		side_bar->setVisibleWidthChangeCallback(boost::bind(&LLScreenChannelBase::resetPositionAndSize, this));  	}  	// top and bottom set by updateBottom() @@ -214,10 +210,7 @@ void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_wo  	if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE   		&& LLSideTray::instanceCreated	())  	{ -		LLSideTray*	side_bar = LLSideTray::getInstance(); - -		if (side_bar->getVisible() && !side_bar->getCollapsed()) -			world_rect_padding += side_bar->getRect().getWidth(); +		world_rect_padding += LLSideTray::getInstance()->getVisibleWidth();  	} @@ -495,7 +488,7 @@ void LLScreenChannel::modifyToastByNotificationID(LLUUID id, LLPanel* panel)  //--------------------------------------------------------------------------  void LLScreenChannel::redrawToasts()  { -	if(mToastList.size() == 0 || isHovering()) +	if(mToastList.size() == 0)  		return;  	switch(mToastAlignment) @@ -841,8 +834,7 @@ void LLScreenChannel::onToastHover(LLToast* toast, bool mouse_enter)  		}  	} -	if(!isHovering()) -		redrawToasts(); +	redrawToasts();  }  //-------------------------------------------------------------------------- diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h index c536a21779..d207d13981 100644 --- a/indra/newview/llscreenchannel.h +++ b/indra/newview/llscreenchannel.h @@ -59,8 +59,8 @@ public:  	// Channel's outfit-functions  	// update channel's size and position in the World View  	virtual void		updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect); +	void				resetPositionAndSize(); -	bool resetPositionAndSize(const LLSD& newvalue);  	// initialization of channel's shape and position  	virtual void		init(S32 channel_left, S32 channel_right); diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 3bc3959e0b..aef665a35c 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -561,7 +561,7 @@ BOOL LLSideTray::postBuild()  	{  		if ((*it).channel)  		{ -			getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, (*it).channel, _2)); +			setVisibleWidthChangeCallback(boost::bind(&LLScreenChannelBase::resetPositionAndSize, (*it).channel));  		}  	} @@ -980,9 +980,6 @@ void LLSideTray::reflectCollapseChange()  	}  	gFloaterView->refresh(); -	 -	LLSD new_value = mCollapsed; -	mCollapseSignal(this,new_value);  }  void LLSideTray::arrange() @@ -1262,9 +1259,29 @@ bool		LLSideTray::isPanelActive(const std::string& panel_name)  void	LLSideTray::updateSidetrayVisibility()  {  	// set visibility of parent container based on collapsed state -	if (getParent()) +	LLView* parent = getParent(); +	if (parent)  	{ -		getParent()->setVisible(!mCollapsed && !gAgentCamera.cameraMouselook()); +		bool old_visibility = parent->getVisible(); +		bool new_visibility = !mCollapsed && !gAgentCamera.cameraMouselook(); + +		if (old_visibility != new_visibility) +		{ +			parent->setVisible(new_visibility); + +			// Signal change of visible width. +			llinfos << "Visible: " << new_visibility << llendl; +			mVisibleWidthChangeSignal(this, new_visibility); +		}  	}  } +S32 LLSideTray::getVisibleWidth() +{ +	return (isInVisibleChain() && !mCollapsed) ? getRect().getWidth() : 0; +} + +void LLSideTray::setVisibleWidthChangeCallback(const commit_signal_t::slot_type& cb) +{ +	mVisibleWidthChangeSignal.connect(cb); +} diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h index 3c572dde95..184d78845f 100644 --- a/indra/newview/llsidetray.h +++ b/indra/newview/llsidetray.h @@ -165,9 +165,18 @@ public:  	void		reshape			(S32 width, S32 height, BOOL called_from_parent = TRUE); -	void		updateSidetrayVisibility(); +	/** +	 * @return side tray width if it's visible and expanded, 0 otherwise. +	 * +	 * Not that width of the tab buttons is not included. +	 * +	 * @see setVisibleWidthChangeCallback() +	 */ +	S32			getVisibleWidth(); + +	void		setVisibleWidthChangeCallback(const commit_signal_t::slot_type& cb); -	commit_signal_t& getCollapseSignal() { return mCollapseSignal; } +	void		updateSidetrayVisibility();  	void		handleLoginComplete(); @@ -216,7 +225,7 @@ private:  	tab_order_vector_t				mOriginalTabOrder;  	LLSideTrayTab*					mActiveTab;	 -	commit_signal_t					mCollapseSignal; +	commit_signal_t					mVisibleWidthChangeSignal;  	LLButton*						mCollapseButton;  	bool							mCollapsed; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index cc54f21a7e..cb72f35eee 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -222,7 +222,17 @@ static U8 sOcclusionIndices[] =  		b000, b110, b100, b101, b001, b011, b010, b110,  }; -U8* get_box_fan_indices(LLCamera* camera, const LLVector4a& center) +U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center) +{ +	LLVector4a origin; +	origin.load3(camera->getOrigin().mV); + +	S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; +	 +	return cypher*8; +} + +U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)  {  	LLVector4a origin;  	origin.load3(camera->getOrigin().mV); @@ -231,12 +241,21 @@ U8* get_box_fan_indices(LLCamera* camera, const LLVector4a& center)  	return sOcclusionIndices+cypher*8;  } -						 + +  void LLSpatialGroup::buildOcclusion()  { -	if (!mOcclusionVerts) +	if (mOcclusionVerts.isNull())  	{ -		mOcclusionVerts = new LLVector4a[8]; +		mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, GL_DYNAMIC_DRAW_ARB); +		mOcclusionVerts->allocateBuffer(8, 64, true); +	 +		LLStrider<U16> idx; +		mOcclusionVerts->getIndexStrider(idx); +		for (U32 i = 0; i < 64; i++) +		{ +			*idx++ = sOcclusionIndices[i]; +		}  	}  	LLVector4a fudge; @@ -251,7 +270,12 @@ void LLSpatialGroup::buildOcclusion()  	r.setMin(r, r2); -	LLVector4a* v = mOcclusionVerts; +	LLStrider<LLVector3> pos; +	 +	mOcclusionVerts->getVertexStrider(pos); + +	LLVector4a* v = (LLVector4a*) pos.get(); +  	const LLVector4a& c = mBounds[0];  	const LLVector4a& s = r; @@ -275,10 +299,13 @@ void LLSpatialGroup::buildOcclusion()  	for (S32 i = 0; i < 8; ++i)  	{ -		v[i] = s; -		v[i].mul(octant[i]); -		v[i].add(c); +		LLVector4a p; +		p.setMul(s, octant[i]); +		p.add(c); +		v[i] = p;  	} +	 +	mOcclusionVerts->setBuffer(0);  	clearState(LLSpatialGroup::OCCLUSION_DIRTY);  } @@ -339,7 +366,6 @@ LLSpatialGroup::~LLSpatialGroup()  		sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);  	} -	delete [] mOcclusionVerts;  	mOcclusionVerts = NULL;  	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); @@ -881,12 +907,9 @@ void LLSpatialGroup::shift(const LLVector4a &offset)  		gPipeline.markRebuild(this, TRUE);  	} -	if (mOcclusionVerts) +	if (mOcclusionVerts.notNull())  	{ -		for (U32 i = 0; i < 8; i++) -		{ -			mOcclusionVerts[i].add(offset); -		} +		setState(OCCLUSION_DIRTY);  	}  } @@ -1423,7 +1446,6 @@ void LLSpatialGroup::destroyGL()  		}  	} -	delete [] mOcclusionVerts;  	mOcclusionVerts = NULL;  	for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i) @@ -1516,31 +1538,37 @@ void LLSpatialGroup::checkOcclusion()  		}  		else if (isOcclusionState(QUERY_PENDING))  		{	//otherwise, if a query is pending, read it back -			GLuint res = 1; -			if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) -			{ -				glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);	 -			} -			if (isOcclusionState(DISCARD_QUERY)) -			{ -				res = 2; -			} +			GLuint available = 0; +			glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); +			if (available) +			{ //result is available, read it back, otherwise wait until next frame +				GLuint res = 1; +				if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) +				{ +					glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);	 +				} -			if (res > 0) -			{ -				assert_states_valid(this); -				clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); -				assert_states_valid(this); -			} -			else -			{ -				assert_states_valid(this); -				setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); -				assert_states_valid(this); -			} +				if (isOcclusionState(DISCARD_QUERY)) +				{ +					res = 2; +				} -			clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); +				if (res > 0) +				{ +					assert_states_valid(this); +					clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); +					assert_states_valid(this); +				} +				else +				{ +					assert_states_valid(this); +					setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); +					assert_states_valid(this); +				} + +				clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); +			}  		}  		else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED))  		{	//check occlusion has been issued for occluded node that has not had a query issued @@ -1566,54 +1594,59 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)  		}  		else  		{ +			if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))  			{ -				LLFastTimer t(FTM_RENDER_OCCLUSION); +				{ //no query pending, or previous query to be discarded +					LLFastTimer t(FTM_RENDER_OCCLUSION); -				if (!mOcclusionQuery[LLViewerCamera::sCurCameraID]) -				{ -					mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate(); -				} +					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID]) +					{ +						mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate(); +					} -				if (!mOcclusionVerts || isState(LLSpatialGroup::OCCLUSION_DIRTY)) -				{ -					buildOcclusion(); -				} -				 -				// Depth clamp all water to avoid it being culled as a result of being -				// behind the far clip plane, and in the case of edge water to avoid -				// it being culled while still visible. -				bool const use_depth_clamp = gGLManager.mHasDepthClamp && -											(mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER || -											mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER); -				if (use_depth_clamp) -				{ -					glEnable(GL_DEPTH_CLAMP); -				} -				 -				glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					 -				glVertexPointer(3, GL_FLOAT, 16, mOcclusionVerts); -				if (camera->getOrigin().isExactlyZero()) -				{ //origin is invalid, draw entire box -					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, -												GL_UNSIGNED_BYTE, sOcclusionIndices); -					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, -							GL_UNSIGNED_BYTE, sOcclusionIndices+b111*8); -				} -				else -				{ -					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, -								GL_UNSIGNED_BYTE, get_box_fan_indices(camera, mBounds[0])); -				} -				glEndQueryARB(GL_SAMPLES_PASSED_ARB); -				 -				if (use_depth_clamp) -				{ -					glDisable(GL_DEPTH_CLAMP); +					if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY)) +					{ +						buildOcclusion(); +					} +					 +					// Depth clamp all water to avoid it being culled as a result of being +					// behind the far clip plane, and in the case of edge water to avoid +					// it being culled while still visible. +					bool const use_depth_clamp = gGLManager.mHasDepthClamp && +												(mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER || +												mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER); +					if (use_depth_clamp) +					{ +						glEnable(GL_DEPTH_CLAMP); +					} +					 +					U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB; + +					glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					 +					 +					mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); + +					if (camera->getOrigin().isExactlyZero()) +					{ //origin is invalid, draw entire box +						mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); +						mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				 +					} +					else +					{ +						mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); +					} + +					glEndQueryARB(mode); +					 +					if (use_depth_clamp) +					{ +						glDisable(GL_DEPTH_CLAMP); +					}  				} -			} -			setOcclusionState(LLSpatialGroup::QUERY_PENDING); -			clearOcclusionState(LLSpatialGroup::DISCARD_QUERY); +				setOcclusionState(LLSpatialGroup::QUERY_PENDING); +				clearOcclusionState(LLSpatialGroup::DISCARD_QUERY); +			}  		}  	}  } @@ -2607,17 +2640,17 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)  			gGL.color4f(0.f, 0.75f, 0.f, 0.5f);  			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);  		} -		else if (camera && group->mOcclusionVerts) +		else if (camera && group->mOcclusionVerts.notNull())  		{  			LLVertexBuffer::unbind(); -			glVertexPointer(3, GL_FLOAT, 16, group->mOcclusionVerts); - +			group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); +			  			glColor4f(1.0f, 0.f, 0.f, 0.5f); -			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0])); +			group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));  			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  			glColor4f(1.0f, 1.f, 1.f, 1.0f); -			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0])); +			group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));  			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);  		}  	} diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 16ec9f780b..85fd66b297 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -59,7 +59,8 @@ S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVe  void pushVerts(LLFace* face, U32 mask);  // get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera -U8* get_box_fan_indices(LLCamera* camera, const LLVector4a& center); +U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center); +U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center);  class LLDrawInfo : public LLRefCount   { @@ -393,7 +394,7 @@ public:  	LLSpatialPartition* mSpatialPartition;  	LLPointer<LLVertexBuffer> mVertexBuffer; -	LLVector4a*				mOcclusionVerts; +	LLPointer<LLVertexBuffer> mOcclusionVerts;  	GLuint					mOcclusionQuery[LLViewerCamera::NUM_CAMERAS];  	U32 mBufferUsage; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index ac3aedb16e..5dcbf079a4 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3100,7 +3100,16 @@ bool process_login_success_response()  	std::string map_server_url = response["map-server-url"];  	if(!map_server_url.empty())  	{ -		gSavedSettings.setString("MapServerURL", map_server_url);  +		// We got an answer from the grid -> use that for map for the current session +		gSavedSettings.setString("CurrentMapServerURL", map_server_url);  +		LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; +	} +	else +	{ +		// No answer from the grid -> use the default setting for current session  +		map_server_url = gSavedSettings.getString("MapServerURL");  +		gSavedSettings.setString("CurrentMapServerURL", map_server_url);  +		LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL;  	}  	// Default male and female avatars allowing the user to choose their avatar on first login. diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index e9fc25404a..1b8be7a5b2 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -115,6 +115,7 @@ LLStatusBar::LLStatusBar(const LLRect& rect)  	mSGBandwidth(NULL),  	mSGPacketLoss(NULL),  	mBtnVolume(NULL), +	mBoxBalance(NULL),  	mBalance(0),  	mHealth(100),  	mSquareMetersCredit(0), @@ -168,6 +169,9 @@ BOOL LLStatusBar::postBuild()  	getChild<LLUICtrl>("buyL")->setCommitCallback(  		boost::bind(&LLStatusBar::onClickBuyCurrency, this)); +	mBoxBalance = getChild<LLTextBox>("balance"); +	mBoxBalance->setClickedCallback( &LLStatusBar::onClickBalance, this ); +  	mBtnVolume = getChild<LLButton>( "volume_btn" );  	mBtnVolume->setClickedCallback( onClickVolume, this );  	mBtnVolume->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterVolume, this)); @@ -304,6 +308,7 @@ void LLStatusBar::setVisibleForMouselook(bool visible)  {  	mTextTime->setVisible(visible);  	getChild<LLUICtrl>("balance_bg")->setVisible(visible); +	mBoxBalance->setVisible(visible);  	mBtnVolume->setVisible(visible);  	mMediaToggle->setVisible(visible);  	mSGBandwidth->setVisible(visible); @@ -330,16 +335,15 @@ void LLStatusBar::setBalance(S32 balance)  	std::string money_str = LLResMgr::getInstance()->getMonetaryString( balance ); -	LLTextBox* balance_box = getChild<LLTextBox>("balance");  	LLStringUtil::format_map_t string_args;  	string_args["[AMT]"] = llformat("%s", money_str.c_str());  	std::string label_str = getString("buycurrencylabel", string_args); -	balance_box->setValue(label_str); +	mBoxBalance->setValue(label_str);  	// Resize the L$ balance background to be wide enough for your balance plus the buy button  	{  		const S32 HPAD = 24; -		LLRect balance_rect = balance_box->getTextBoundingRect(); +		LLRect balance_rect = mBoxBalance->getTextBoundingRect();  		LLRect buy_rect = getChildView("buyL")->getRect();  		LLView* balance_bg_view = getChildView("balance_bg");  		LLRect balance_bg_rect = balance_bg_view->getRect(); @@ -506,6 +510,14 @@ static void onClickVolume(void* data)  }  //static  +void LLStatusBar::onClickBalance(void* ) +{ +	// Force a balance request message: +	LLStatusBar::sendMoneyBalanceRequest(); +	// The refresh of the display (call to setBalance()) will be done by process_money_balance_reply() +} + +//static   void LLStatusBar::onClickMediaToggle(void* data)  {  	LLStatusBar *status_bar = (LLStatusBar*)data; diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 2388aeb0c8..4ea3183d18 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -94,6 +94,7 @@ private:  	void onClickScreen(S32 x, S32 y);  	static void onClickMediaToggle(void* data); +	static void onClickBalance(void* data);  private:  	LLTextBox	*mTextTime; @@ -102,6 +103,7 @@ private:  	LLStatGraph *mSGPacketLoss;  	LLButton	*mBtnVolume; +	LLTextBox	*mBoxBalance;  	LLButton	*mMediaToggle;  	LLView*		mScriptOut;  	LLFrameTimer	mClockUpdateTimer; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index dadda29416..444d5cb902 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -544,9 +544,10 @@ bool toggle_show_object_render_cost(const LLSD& newvalue)  void toggle_updater_service_active(LLControlVariable* control, const LLSD& new_value)  { -    if(new_value.asBoolean()) +    if(new_value.asInteger())      { -        LLUpdaterService().startChecking(); +		LLUpdaterService update_service; +		if(!update_service.isChecking()) update_service.startChecking();      }      else      { @@ -701,7 +702,7 @@ void settings_setup_listeners()  	gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2));  	gSavedSettings.getControl("ShowMiniLocationPanel")->getSignal()->connect(boost::bind(&toggle_show_mini_location_panel, _2));  	gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2)); -	gSavedSettings.getControl("UpdaterServiceActive")->getSignal()->connect(&toggle_updater_service_active); +	gSavedSettings.getControl("UpdaterServiceSetting")->getSignal()->connect(&toggle_updater_service_active);  	gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2));  	gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2));  } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 8c06eb7f5d..11686740f7 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -60,6 +60,7 @@  #include "llfloaterhardwaresettings.h"  #include "llfloaterhelpbrowser.h"  #include "llfloatermediabrowser.h" +#include "llfloaterwebcontent.h"  #include "llfloatermediasettings.h"  #include "llfloaterhud.h"  #include "llfloaterimagepreview.h" @@ -281,6 +282,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>);  	LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>); +	LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWebContent>);	  	LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>);	  	LLFloaterWindowSizeUtil::registerFloater();  	LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>);	 diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 0cccea7f37..cd72e69055 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -52,6 +52,7 @@  #include "llviewerregion.h"  #include "llwebsharing.h"	// For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this!  #include "llfilepicker.h" +#include "llnotifications.h"  #include "llevent.h"		// LLSimpleListener  #include "llnotificationsutil.h" @@ -62,6 +63,7 @@  #include "llwindow.h"  #include "llfloatermediabrowser.h"	// for handling window close requests and geometry change requests in media browser windows. +#include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows.  #include <boost/bind.hpp>	// for SkinFolder listener  #include <boost/signals2.hpp> @@ -293,6 +295,7 @@ public:  LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;  LLURL LLViewerMedia::sOpenIDURL;  std::string LLViewerMedia::sOpenIDCookie; +LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL;  static LLViewerMedia::impl_list sViewerMediaImplList;  static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap;  static LLTimer sMediaCreateTimer; @@ -742,6 +745,9 @@ void LLViewerMedia::updateMedia(void *dummy_arg)  	// Enable/disable the plugin read thread  	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); +	// HACK: we always try to keep a spare running webkit plugin around to improve launch times. +	createSpareBrowserMediaSource(); +	  	sAnyMediaShowing = false;  	sUpdatedCookies = getCookieStore()->getChangedCookies();  	if(!sUpdatedCookies.empty()) @@ -759,6 +765,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg)  		pimpl->update();  		pimpl->calculateInterest();  	} +	 +	// Let the spare media source actually launch +	if(sSpareBrowserMediaSource) +	{ +		sSpareBrowserMediaSource->idle(); +	}  	// Sort the static instance list using our interest criteria  	sViewerMediaImplList.sort(priorityComparitor); @@ -1034,6 +1046,26 @@ bool LLViewerMedia::isParcelAudioPlaying()  	return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying());  } +void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) +{ +	LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]); +	if(impl) +	{ +		LLPluginClassMedia* media = impl->getMediaPlugin(); +		if(media) +		{ +			if (response["ok"]) +			{ +				media->sendAuthResponse(true, response["username"], response["password"]); +			} +			else +			{ +				media->sendAuthResponse(false, "", ""); +			} +		} +	} +} +  /////////////////////////////////////////////////////////////////////////////////////////  // static  void LLViewerMedia::clearAllCookies() @@ -1400,6 +1432,29 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid)  	}  } +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::createSpareBrowserMediaSource() +{ +	if(!sSpareBrowserMediaSource) +	{ +		// If we don't have a spare browser media source, create one. +		// The null owner will keep the browser plugin from fully initializing  +		// (specifically, it keeps LLPluginClassMedia from negotiating a size change,  +		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) +		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); +	} +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource()  +{ +	LLPluginClassMedia* result = sSpareBrowserMediaSource; +	sSpareBrowserMediaSource = NULL; +	return result;  +}; +  bool LLViewerMedia::hasInWorldMedia()  {  	if (sInWorldMediaDisabled) return false; @@ -1636,6 +1691,21 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)  LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target)  {  	std::string plugin_basename = LLMIMETypes::implType(media_type); +	LLPluginClassMedia* media_source = NULL; +	 +	// HACK: we always try to keep a spare running webkit plugin around to improve launch times. +	if(plugin_basename == "media_plugin_webkit") +	{ +		media_source = LLViewerMedia::getSpareBrowserMediaSource(); +		if(media_source) +		{ +			media_source->setOwner(owner); +			media_source->setTarget(target); +			media_source->setSize(default_width, default_height); +						 +			return media_source; +		} +	}  	if(plugin_basename.empty())  	{ @@ -1673,7 +1743,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_  		}  		else  		{ -			LLPluginClassMedia* media_source = new LLPluginClassMedia(owner); +			media_source = new LLPluginClassMedia(owner);  			media_source->setSize(default_width, default_height);  			media_source->setUserDataPath(user_data_path);  			media_source->setLanguageCode(LLUI::getLanguage()); @@ -1753,6 +1823,22 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)  		media_source->focus(mHasFocus);  		media_source->setBackgroundColor(mBackgroundColor); +		if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors")) +		{ +			media_source->ignore_ssl_cert_errors(true); +		} + +		// start by assuming the default CA file will be used +		std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "lindenlab.pem" ); +	 +		// default turned off so pick up the user specified path +		if( ! gSavedSettings.getBOOL("BrowserUseDefaultCAFile")) +		{ +			ca_path = gSavedSettings.getString("BrowserCAFilePath"); +		} +		// set the path to the CA.pem file +		media_source->addCertificateFilePath( ca_path ); +  		media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));  		if(mClearCache) @@ -1849,6 +1935,18 @@ void LLViewerMediaImpl::setSize(int width, int height)  }  ////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::showNotification(LLNotificationPtr notify) +{ +	mNotification = notify; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::hideNotification() +{ +	mNotification.reset(); +} + +//////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::play()  {  	// If the media source isn't there, try to initialize it and load an URL. @@ -2850,7 +2948,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  			LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL;   			std::string url = plugin->getClickURL();  			LLURLDispatcher::dispatch(url, NULL, mTrustedBrowser); -  		}  		break;  		case MEDIA_EVENT_CLICK_LINK_HREF: @@ -2913,6 +3010,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN:  		{  			LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; +			hideNotification();  			if(getNavState() == MEDIANAVSTATE_SERVER_SENT)  			{ @@ -3003,7 +3101,26 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  			plugin->sendPickFileResponse(response);  		}  		break; -		 + + +		case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST: +		{ +			LLNotification::Params auth_request_params; +			auth_request_params.name = "AuthRequest"; + +			// pass in host name and realm for site (may be zero length but will always exist) +			LLSD args; +			LLURL raw_url( plugin->getAuthURL().c_str() ); +			args["HOST_NAME"] = raw_url.getAuthority(); +			args["REALM"] = plugin->getAuthRealm(); +			auth_request_params.substitutions = args; + +			auth_request_params.payload = LLSD().with("media_id", mTextureId); +			auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); +			LLNotifications::instance().add(auth_request_params); +		}; +		break; +  		case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST:  		{  			std::string uuid = plugin->getClickUUID(); @@ -3019,6 +3136,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  				// This close request is directed at another instance  				pass_through = false;  				LLFloaterMediaBrowser::closeRequest(uuid); +				LLFloaterWebContent::closeRequest(uuid);  			}  		}  		break; @@ -3038,6 +3156,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  				// This request is directed at another instance  				pass_through = false;  				LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); +				LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight());  			}  		}  		break; @@ -3521,6 +3640,11 @@ bool LLViewerMediaImpl::isInAgentParcel() const  	return result;  } +LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const +{ +	return mNotification; +} +  //////////////////////////////////////////////////////////////////////////////////////////  //  // static diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 4025a4484f..e2e342cc45 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -37,6 +37,7 @@  #include "llpluginclassmedia.h"  #include "v4color.h" +#include "llnotificationptr.h"  #include "llurl.h" @@ -130,6 +131,8 @@ public:  	static bool isParcelMediaPlaying();  	static bool isParcelAudioPlaying(); +	static void onAuthSubmit(const LLSD& notification, const LLSD& response); +  	// Clear all cookies for all plugins  	static void clearAllCookies(); @@ -155,6 +158,9 @@ public:  	static void proxyWindowOpened(const std::string &target, const std::string &uuid);  	static void proxyWindowClosed(const std::string &uuid); +	static void createSpareBrowserMediaSource(); +	static LLPluginClassMedia* getSpareBrowserMediaSource(); +	  private:  	static void setOpenIDCookie();  	static void onTeleportFinished(); @@ -162,6 +168,7 @@ private:  	static LLPluginCookieStore *sCookieStore;  	static LLURL sOpenIDURL;  	static std::string sOpenIDCookie; +	static LLPluginClassMedia* sSpareBrowserMediaSource;  };  // Implementation functions not exported into header file @@ -195,6 +202,9 @@ public:  	LLPluginClassMedia* getMediaPlugin() { return mMediaSource; }  	void setSize(int width, int height); +	void showNotification(LLNotificationPtr notify); +	void hideNotification(); +  	void play();  	void stop();  	void pause(); @@ -387,6 +397,9 @@ public:  	// Is this media in the agent's parcel?  	bool isInAgentParcel() const; +	// get currently active notification associated with this media instance +	LLNotificationPtr getCurrentNotification() const; +  private:  	bool isAutoPlayable() const;  	bool shouldShowBasedOnClass() const; @@ -444,7 +457,8 @@ private:  	bool mNavigateSuspendedDeferred;  	bool mTrustedBrowser;  	std::string mTarget; -	 +	LLNotificationPtr mNotification; +  private:  	BOOL mIsUpdated ;  	std::list< LLVOVolume* > mObjectList ; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 6d2d2fee91..75531cef8d 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7230,6 +7230,12 @@ void handle_web_browser_test(const LLSD& param)  	LLWeb::loadURLInternal(url);  } +void handle_web_content_test(const LLSD& param) +{ +	std::string url = param.asString(); +	LLWeb::loadWebURLInternal(url); +} +  void handle_buy_currency_test(void*)  {  	std::string url = @@ -7980,7 +7986,8 @@ void initialize_menus()  	view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache");  	// Advanced > UI -	commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); +	commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test,	_2));	// sigh! this one opens the MEDIA browser +	commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2));	// this one opens the Web Content floater  	view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");  	view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");  	view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 965c24c634..a4b5143a02 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -171,6 +171,31 @@ const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] =  	FALSE	// ControlYourCamera  }; +// Extract channel and version from a string like "SL Web Viewer Beta 10.11.29.215604". +// (channel: "SL Web Viewer Beta", version: "10.11.29.215604") +static bool parse_version_info(const std::string& version_info, std::string& channel, std::string& ver) +{ +	size_t last_space = version_info.rfind(" "); +	channel = version_info; + +	if (last_space != std::string::npos) +	{ +		try +		{ +			ver = version_info.substr(last_space + 1); +			channel.replace(last_space, ver.length() + 1, ""); // strip version +		} +		catch (std::out_of_range) +		{ +			return false; +		} + +		return true; +	} + +	return false; +} +  bool friendship_offer_callback(const LLSD& notification, const LLSD& response)  {  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -3825,28 +3850,22 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)  	if (!gLastVersionChannel.empty())  	{ -		// work out the URL for this server's Release Notes -		std::string url ="http://wiki.secondlife.com/wiki/Release_Notes/"; -		std::string server_version = version_channel; -		std::vector<std::string> s_vect; -		boost::algorithm::split(s_vect, server_version, isspace); -		for(U32 i = 0; i < s_vect.size(); i++) +		std::string url = regionp->getCapability("ServerReleaseNotes"); +		if (url.empty())  		{ -			if (i != (s_vect.size() - 1)) -			{ -				if(i != (s_vect.size() - 2)) -				{ -				   url += s_vect[i] + "_"; -				} -				else -				{ -					url += s_vect[i] + "/"; -				} -			} -			else +			// The capability hasn't arrived yet or is not supported, +			// fall back to parsing server version channel. +			std::string channel, ver; +			if (!parse_version_info(version_channel, channel, ver))  			{ -				url += s_vect[i].substr(0,4); +				llwarns << "Failed to parse server version channel (" << version_channel << ")" << llendl;  			} + +			url = gSavedSettings.getString("ReleaseNotesURL"); +			LLSD args; +			args["CHANNEL"] = LLWeb::escapeURL(channel); +			args["VERSION"] = LLWeb::escapeURL(ver); +			LLStringUtil::format(url, args);  		}  		LLSD args; diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 99e869dafc..40f0b43313 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -586,6 +586,18 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent  			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;  		}  		break; + +		case MEDIA_EVENT_AUTH_REQUEST: +		{ +			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() << ", realm " << self->getAuthRealm() << LL_ENDL; +		} +		break; + +		case MEDIA_EVENT_LINK_HOVERED: +		{ +			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL; +		}; +		break;  	};  } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 10126219f8..b5eadb6d25 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -834,7 +834,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)  	for (entries_list_t::iterator iter3 = entries.begin();  		 iter3 != entries.end(); )  	{ -		LLPointer<LLViewerFetchedTexture> imagep = *iter3++; +		LLViewerFetchedTexture* imagep = *iter3++;  		bool fetching = imagep->updateFetch();  		if (fetching) diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 348cdbeb4c..62822c0b34 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -186,11 +186,6 @@ public:  	/*virtual*/ std::string translateString(const char* tag,  					const std::map<std::string, std::string>& args); -	// signal on bottom tray width changed -	typedef boost::function<void (void)> bottom_tray_callback_t; -	typedef boost::signals2::signal<void (void)> bottom_tray_signal_t; -	bottom_tray_signal_t mOnBottomTrayWidthChanged; -	boost::signals2::connection setOnBottomTrayWidthChanged(bottom_tray_callback_t cb) { return mOnBottomTrayWidthChanged.connect(cb); }  	// signal on update of WorldView rect  	typedef boost::function<void (LLRect old_world_rect, LLRect new_world_rect)> world_rect_callback_t;  	typedef boost::signals2::signal<void (LLRect old_world_rect, LLRect new_world_rect)> world_rect_signal_t; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index fa0f48fce6..471df30bfe 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2905,12 +2905,21 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const  {
  	// base cost of each prim should be 10 points
  	static const U32 ARC_PRIM_COST = 10;
 -	
 -	// get access to params we'll need at various points
 -	LLVolumeParams volume_params = getVolume()->getParams();
 -	LLPathParams path_params = volume_params.getPathParams();
 -	LLProfileParams profile_params = volume_params.getProfileParams();
 +	// Get access to params we'll need at various points.  
 +	// Skip if this is object doesn't have a volume (e.g. is an avatar).
 +	const BOOL has_volume = (getVolume() != NULL);
 +	LLVolumeParams volume_params;
 +	LLPathParams path_params;
 +	LLProfileParams profile_params;
 +
 +	if (has_volume)
 +	{
 +		volume_params = getVolume()->getParams();
 +		path_params = volume_params.getPathParams();
 +		profile_params = volume_params.getProfileParams();
 +	}
 +	
  	// per-prim costs
  	static const U32 ARC_INVISI_COST = 1;
  	static const U32 ARC_PARTICLE_COST = 100;
 @@ -4375,12 +4384,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)  			LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
  			LLDrawable* drawablep = *drawable_iter;
 -			if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
 -			{
 -				continue;
 -			}
 -
 -			if (drawablep->isState(LLDrawable::REBUILD_ALL))
 +			if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) )
  			{
  				LLVOVolume* vobj = drawablep->getVOVolume();
  				vobj->preRebuild();
 diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 6028a8fbea..b73017a51a 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -35,6 +35,7 @@  #include "llagent.h"  #include "llappviewer.h"  #include "llfloatermediabrowser.h" +#include "llfloaterwebcontent.h"  #include "llfloaterreg.h"  #include "lllogininstance.h"  #include "llparcel.h" @@ -95,6 +96,23 @@ void LLWeb::loadURL(const std::string& url, const std::string& target, const std  	}  } +// static +void LLWeb::loadWebURL(const std::string& url, const std::string& target, const std::string& uuid) +{ +	if(target == "_internal") +	{ +		// Force load in the internal browser, as if with a blank target. +		loadWebURLInternal(url, "", uuid); +	} +	else if (gSavedSettings.getBOOL("UseExternalBrowser") || (target == "_external")) +	{ +		loadURLExternal(url); +	} +	else +	{ +		loadWebURLInternal(url, target, uuid); +	} +}  // static  void LLWeb::loadURLInternal(const std::string &url, const std::string& target, const std::string& uuid) @@ -102,6 +120,13 @@ void LLWeb::loadURLInternal(const std::string &url, const std::string& target, c  	LLFloaterMediaBrowser::create(url, target, uuid);  } +// static +// Explicitly open a Web URL using the Web content floater +void LLWeb::loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid) +{ +	LLFloaterWebContent::create(url, target, uuid); +} +  // static  void LLWeb::loadURLExternal(const std::string& url, const std::string& uuid) diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h index 2915376583..dc5958e57f 100644 --- a/indra/newview/llweb.h +++ b/indra/newview/llweb.h @@ -57,6 +57,11 @@ public:  	static void loadURLExternal(const std::string& url, const std::string& uuid);  	static void loadURLExternal(const std::string& url, bool async, const std::string& uuid = LLStringUtil::null); +	// Explicitly open a Web URL using the Web content floater vs. the more general media browser +	static void loadWebURL(const std::string& url, const std::string& target, const std::string& uuid); +	static void loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid); +	static void loadWebURLInternal(const std::string &url) { loadWebURLInternal(url, LLStringUtil::null, LLStringUtil::null); } +  	/// Returns escaped url (eg, " " to "%20") - used by all loadURL methods  	static std::string escapeURL(const std::string& url);  	/// Expands various strings like [LANG], [VERSION], etc. in a URL diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp index be8298daab..74ed844376 100644 --- a/indra/newview/llworldmipmap.cpp +++ b/indra/newview/llworldmipmap.cpp @@ -181,8 +181,7 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32  LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level)  {  	// Get the grid coordinates -	std::string imageurl = gSavedSettings.getString("MapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y); - +	std::string imageurl = gSavedSettings.getString("CurrentMapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y);  	// DO NOT COMMIT!! DEBUG ONLY!!!  	// Use a local jpeg for every tile to test map speed without S3 access diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 1f1c8d46f5..24327bf535 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -4136,11 +4136,12 @@ void LLPipeline::renderDebug()  					gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);  					gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);  					gGL.end(); -					} - +				}  			} -			/*for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();  +			/*gGL.flush(); +			glLineWidth(16-i*2); +			for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();   					iter != LLWorld::getInstance()->getRegionList().end(); ++iter)  			{  				LLViewerRegion* region = *iter; @@ -4155,7 +4156,9 @@ void LLPipeline::renderDebug()  						}  					}  				} -			}*/ +			} +			gGL.flush(); +			glLineWidth(1.f);*/  		}  	} @@ -7084,6 +7087,8 @@ void LLPipeline::renderDeferredLighting()  			std::list<LLVector4> light_colors; +			LLVertexBuffer::unbind(); +  			F32 v[24];  			glVertexPointer(3, GL_FLOAT, 0, v); @@ -7173,7 +7178,7 @@ void LLPipeline::renderDeferredLighting()  							glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);  							glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);  							glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, -								GL_UNSIGNED_BYTE, get_box_fan_indices(camera, center)); +								GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center));  							stop_glerror();  						}  					} @@ -7239,7 +7244,7 @@ void LLPipeline::renderDeferredLighting()  					glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);  					glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);  					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, -							GL_UNSIGNED_BYTE, get_box_fan_indices(camera, center)); +							GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center));  				}  				gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);  				unbindDeferredShader(gDeferredSpotLightProgram); @@ -7650,11 +7655,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)  		LLCamera camera = camera_in;  		camera.setFar(camera.getFar()*0.87654321f);  		LLPipeline::sReflectionRender = TRUE; -		S32 occlusion = LLPipeline::sUseOcclusion; - -		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - -		LLPipeline::sUseOcclusion = llmin(occlusion, 1);  		gPipeline.pushRenderTypeMask(); @@ -7693,19 +7693,20 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)  			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);  			glClearColor(0,0,0,0);  			mWaterRef.bindTarget(); +			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0;  			gGL.setColorMask(true, true);  			mWaterRef.clear();  			gGL.setColorMask(true, false);  			mWaterRef.getViewport(gGLViewport); -			 +  			stop_glerror();  			glPushMatrix();  			mat.set_scale(glh::vec3f(1,1,-1));  			mat.set_translate(glh::vec3f(0,0,height*2.f)); -			 +  			glh::matrix4f current = glh_get_current_modelview();  			mat = current * mat; @@ -7725,22 +7726,24 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)  			glCullFace(GL_FRONT);  			static LLCullResult ref_result; -		 +  			if (LLDrawPoolWater::sNeedsDistortionUpdate)  			{  				//initial sky pass (no user clip plane)  				{ //mask out everything but the sky  					gPipeline.pushRenderTypeMask();  					gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, -												LLPipeline::RENDER_TYPE_WL_SKY, -												LLPipeline::END_RENDER_TYPES); +						LLPipeline::RENDER_TYPE_WL_SKY, +						LLPipeline::END_RENDER_TYPES); +  					static LLCullResult result;  					updateCull(camera, result);  					stateSort(camera, result); +  					andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, -										LLPipeline::RENDER_TYPE_CLOUDS, -										LLPipeline::RENDER_TYPE_WL_SKY, -										LLPipeline::END_RENDER_TYPES); +						LLPipeline::RENDER_TYPE_CLOUDS, +						LLPipeline::RENDER_TYPE_WL_SKY, +						LLPipeline::END_RENDER_TYPES);  					renderGeom(camera, TRUE);  					gPipeline.popRenderTypeMask(); @@ -7749,23 +7752,23 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)  				gPipeline.pushRenderTypeMask();  				clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, -									LLPipeline::RENDER_TYPE_VOIDWATER, -									LLPipeline::RENDER_TYPE_GROUND, -									LLPipeline::RENDER_TYPE_SKY, -									LLPipeline::RENDER_TYPE_CLOUDS, -									LLPipeline::END_RENDER_TYPES);	 +					LLPipeline::RENDER_TYPE_VOIDWATER, +					LLPipeline::RENDER_TYPE_GROUND, +					LLPipeline::RENDER_TYPE_SKY, +					LLPipeline::RENDER_TYPE_CLOUDS, +					LLPipeline::END_RENDER_TYPES);	 -					S32 detail = gSavedSettings.getS32("RenderReflectionDetail"); +				S32 detail = gSavedSettings.getS32("RenderReflectionDetail");  				if (detail > 0)  				{ //mask out selected geometry based on reflection detail  					if (detail < 4)  					{  						clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); -					if (detail < 3) -					{ -							clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); -						if (detail < 2) +						if (detail < 3)  						{ +							clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); +							if (detail < 2) +							{  								clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);  							}  						} @@ -7776,16 +7779,16 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)  					updateCull(camera, ref_result, 1);  					stateSort(camera, ref_result);  				}	 -				 -			if (LLDrawPoolWater::sNeedsDistortionUpdate) -			{ -					if (gSavedSettings.getS32("RenderReflectionDetail") > 0) + +				if (LLDrawPoolWater::sNeedsDistortionUpdate)  				{ -					gPipeline.grabReferences(ref_result); -					LLGLUserClipPlane clip_plane(plane, mat, projection); -					renderGeom(camera); -				} -			}	 +					if (gSavedSettings.getS32("RenderReflectionDetail") > 0) +					{ +						gPipeline.grabReferences(ref_result); +						LLGLUserClipPlane clip_plane(plane, mat, projection); +						renderGeom(camera); +					} +				}	  				gPipeline.popRenderTypeMask();  			}	 @@ -7823,6 +7826,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)  			LLColor4& col = LLDrawPoolWater::sWaterFogColor;  			glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);  			mWaterDis.bindTarget(); +			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;  			mWaterDis.getViewport(gGLViewport);  			if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate) @@ -7859,8 +7863,8 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)  		gPipeline.popRenderTypeMask();  		LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;  		LLDrawPoolWater::sNeedsDistortionUpdate = FALSE; -		LLViewerCamera::getInstance()->setUserClipPlane(LLPlane(-pnorm, -pd)); -		LLPipeline::sUseOcclusion = occlusion; +		LLPlane npnorm(-pnorm, -pd); +		LLViewerCamera::getInstance()->setUserClipPlane(npnorm);  		LLGLState::checkStates();  		LLGLState::checkTextureChannels(); @@ -7870,6 +7874,8 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)  		{  			gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());  		} + +		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;  	}  } @@ -7992,6 +7998,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera  	//glCullFace(GL_FRONT); +	LLVertexBuffer::unbind(); +  	{  		LLFastTimer ftm(FTM_SHADOW_SIMPLE);  		LLGLDisable test(GL_ALPHA_TEST); @@ -8059,14 +8067,13 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector  	}  	//get set of planes on bounding box -	std::vector<LLPlane> bp; -		 -	bp.push_back(LLPlane(min, LLVector3(-1,0,0))); -	bp.push_back(LLPlane(min, LLVector3(0,-1,0))); -	bp.push_back(LLPlane(min, LLVector3(0,0,-1))); -	bp.push_back(LLPlane(max, LLVector3(1,0,0))); -	bp.push_back(LLPlane(max, LLVector3(0,1,0))); -	bp.push_back(LLPlane(max, LLVector3(0,0,1))); +	LLPlane bp[] = {  +		LLPlane(min, LLVector3(-1,0,0)), +		LLPlane(min, LLVector3(0,-1,0)), +		LLPlane(min, LLVector3(0,0,-1)), +		LLPlane(max, LLVector3(1,0,0)), +		LLPlane(max, LLVector3(0,1,0)), +		LLPlane(max, LLVector3(0,0,1))};  	//potential points  	std::vector<LLVector3> pp; @@ -8114,7 +8121,8 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector  			const LLPlane& cp = camera.getAgentPlane(j);  			const LLVector3& v1 = pp[bs[i*2+0]];  			const LLVector3& v2 = pp[bs[i*2+1]]; -			const LLVector3 n(cp.mV); +			LLVector3 n; +			cp.getVector3(n);  			LLVector3 line = v1-v2; @@ -8128,8 +8136,8 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector  				LLVector3 intersect = v2+line*t;  				pp.push_back(intersect);  			} -			}  		} +	}  	//camera frustum line segments  	const U32 fs[] = @@ -8160,7 +8168,8 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector  			const LLVector3& v1 = pp[fs[i*2+0]+8];  			const LLVector3& v2 = pp[fs[i*2+1]+8];  			const LLPlane& cp = bp[j]; -			const LLVector3 n(cp.mV); +			LLVector3 n; +			cp.getVector3(n);  			LLVector3 line = v1-v2; @@ -8175,7 +8184,7 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector  				pp.push_back(intersect);  			}	  		} -				} +	}  	LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f),  		max+LLVector3(0.05f,0.05f,0.05f) }; diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 5c188173ce..62466e4fa3 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -397,7 +397,7 @@ with the same filename but different name    <texture name="RadioButton_On_Disabled" file_name="widgets/RadioButton_On_Disabled.png" preload="true" /> -  <texture name="Refresh_Off" file_name="icons/Refresh_Off.png" preload="false" /> +  <texture name="Refresh_Off" file_name="icons/Refresh_Off.png" preload="true" />    <texture name="Resize_Corner" file_name="windows/Resize_Corner.png" preload="true" /> @@ -473,7 +473,7 @@ with the same filename but different name    <texture name="Stepper_Up_Off" file_name="widgets/Stepper_Up_Off.png" preload="false" />    <texture name="Stepper_Up_Press" file_name="widgets/Stepper_Up_Press.png" preload="false" /> -  <texture name="Stop_Off" file_name="icons/Stop_Off.png" preload="false" /> +  <texture name="Stop_Off" file_name="icons/Stop_Off.png" preload="true" />    <texture name="StopReload_Off" file_name="icons/StopReload_Off.png" preload="false" />    <texture name="StopReload_Over" file_name="icons/StopReload_Over.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/en/floater_help_browser.xml b/indra/newview/skins/default/xui/en/floater_help_browser.xml index 837923bcf6..02e50ee584 100644 --- a/indra/newview/skins/default/xui/en/floater_help_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_help_browser.xml @@ -36,7 +36,8 @@           user_resize="false"           width="620">              <web_browser -              trusted_content="true"  +             trusted_content="true"  +             initial_mime_type="text/html"                bottom="-25"               follows="left|right|top|bottom"               layout="topleft" diff --git a/indra/newview/skins/default/xui/en/floater_media_browser.xml b/indra/newview/skins/default/xui/en/floater_media_browser.xml index 49e835cce4..43729d7c9f 100644 --- a/indra/newview/skins/default/xui/en/floater_media_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_media_browser.xml @@ -101,7 +101,7 @@               left_pad="5"               name="go"               top_delta="0" -             width="55"> +             width="50">  				<button.commit_callback  				function="MediaBrowser.Go" />  			</button> diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 0fdcf486e7..f23cb60121 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -69,7 +69,7 @@        Resource Cost: [COST]      </text>      <text left="25" top_pad="5" width="140" follows="bottom|left" height="15" name="physics cost"> -      Physics Cost: Unknown +      Physics Cost: [COST]      </text>      <text left="25" top_pad="5" follows="bottom|left" height="15" name="upload fee">        Upload Fee: N/A @@ -169,12 +169,12 @@          Queue Mode:        </text>        <combo_box follows="top|left" name="build_operator" top_pad="5" left="45" width="100" height="20"> -        <combo_item name="half_edge_collapse"> -          Half Edge Collapse -        </combo_item>          <combo_item name="edge_collapse">            Edge Collapse          </combo_item> +        <combo_item name="half_edge_collapse"> +          Half Edge Collapse +        </combo_item>        </combo_box>        <combo_box follows="top|left" name="queue_mode" left_pad="5" width="100" height="20"> @@ -205,7 +205,7 @@            Lock          </combo_item>        </combo_box> -      <spinner follows="left|top" name="share_tolerance" left_pad="5" width="100" height="20"/> +      <spinner follows="left|top" name="share_tolerance" left_pad="5" width="100" decimal_digits="5" initial_value="0.00001" height="20"/>        <text left="10" top_pad="35" follows="top|left" width="240" height="15">          Generate Normals @@ -295,6 +295,7 @@          <check_box name="Close Holes (Slow)" follows="top|left" top_pad="10" height="15" label="Close Holes (slow)"/>          <button left="200" bottom_delta="0" width="90" follows="top|left" label="Analyze" name="Decompose" height="20"/> +        <button left="200" bottom_delta="0" width="90" follows="top|left" label="Cancel" name="decompose_cancel" visble="false" height="20"/>        </panel> @@ -324,6 +325,7 @@          <slider name="Detail Scale" label="Detail Scale:" label_width="120" width="270" follows="top|left" top_pad="10" height="20"/>          <slider name="Retain%" label="Retain:" label_width="120" width="270" follows="top|left" bottom_delta="0" left_delta="0" visible="false" height="20"/>          <button left="190" width="90" follows="top|left" label="Simplify" name="Simplify" height="20"/> +        <button left="190" bottom_delta="0" width="90" follows="top|left" label="Cancel" name="simplify_cancel" height="20"/>        </panel> diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml index 0f8844519a..e2ec557b06 100644 --- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml +++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml @@ -1,624 +1,768 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 -<floater
 - legacy_header_height="18"
 - layout="topleft"
 - name="Model Wizard"
 - help_topic="model_wizard"
 - bg_opaque_image_overlay="0.5 0.5 0.5 1"
 - height="450"
 - save_rect="true"
 - title="UPLOAD MODEL WIZARD"
 - width="530">
 -	<button
 -	 top="30"
 -	 tab_stop="false"
 -	 left="410"
 -	 height="32"
 -	 name="upload_btn"
 -	 enabled="false"
 -	 label="5. Upload"
 -	 border="false"
 -	 image_unselected="model_wizard/middle_button_off.png"
 -	 image_selected="model_wizard/middle_button_press.png"
 -	 image_hover_unselected="model_wizard/middle_button_over.png"
 -	 image_disabled="model_wizard/middle_button_disabled.png"
 -	 image_disabled_selected="model_wizard/middle_button_disabled.png"
 -	 width="110"/>
 -	<button
 -	 top="30"
 -	 left="310"
 -	 height="32"
 -	 tab_stop="false"
 -	 name="review_btn"
 -	 label="4. Review"
 -	 enabled="false"
 -	 border="false"
 -	 image_unselected="model_wizard/middle_button_off.png"
 -	 image_selected="model_wizard/middle_button_press.png"
 -	 image_hover_unselected="model_wizard/middle_button_over.png"
 -	 image_disabled="model_wizard/middle_button_disabled.png"
 -	 image_disabled_selected="model_wizard/middle_button_disabled.png"
 -	 width="110"/>
 -	<button
 -	 top="30"
 -	 left="210"
 -	 height="32"
 -	 name="physics_btn"
 -	 label="3. Physics"
 -	 tab_stop="false"
 -	 enabled="false"
 -	 border="false"
 -	 image_unselected="model_wizard/middle_button_off.png"
 -	 image_selected="model_wizard/middle_button_press.png"
 -	 image_hover_unselected="model_wizard/middle_button_over.png"
 -	 image_disabled="model_wizard/middle_button_disabled.png"
 -	 image_disabled_selected="model_wizard/middle_button_disabled.png"
 -	 width="110"/>
 -	<button
 -	 top="30"
 -	 left="115"
 -	 name="optimize_btn"
 -	 label="2. Optimize"
 -	 tab_stop="false"
 -	 height="32"
 -	 border="false"
 -	 image_unselected="model_wizard/middle_button_off.png"
 -	 image_selected="model_wizard/middle_button_press.png"
 -	 image_hover_unselected="model_wizard/middle_button_over.png"
 -	 image_disabled="model_wizard/middle_button_disabled.png"
 -	 image_disabled_selected="model_wizard/middle_button_disabled.png"
 -	 width="110"/>
 -	<button
 -	 top="30"
 -	 left="15"
 -	 name="choose_file_btn"
 -	 tab_stop="false"
 -	 enabled="false"
 -	 label="1. Choose File"
 -	 height="32"
 -	 image_unselected="model_wizard/left_button_off.png"
 -	 image_selected="model_wizard/left_button_press.png"
 -	 image_hover_unselected="model_wizard/left_button_over.png"
 -	 image_disabled="model_wizard/left_button_disabled.png"
 -	 image_disabled_selected="model_wizard/left_button_disabled.png"
 -	 width="110"/>
 -	<panel
 -		 height="388"
 -		 top_pad="0"
 -		 name="choose_file_panel"
 -		 visible="false"
 -		 width="530"
 -		 left="0">
 -		<panel
 -		 height="20"
 -		 top_pad="20"
 -		 width="500"
 -		 name="header_panel"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true"
 -		 left="20">
 -			<text
 -			 width="200"
 -			 left="10"
 -			 top="2"
 -			 name="header_text"
 -			 height="10"
 -			 font="SansSerifBig"
 -			 layout="topleft">
 -				Upload Model
 -			</text>
 -		</panel>
 -		<text
 -		 top_pad="14"
 -		 width="460"
 -		 height="20"
 -		 name="description"
 -		 font="SansSerifSmall"
 -		 layout="topleft"
 -		 word_wrap="true"
 -		 left_delta="0">
 -			This wizard will help you import mesh models to Second Life.  First specify a file containing the model you wish to import.  Second Life supports COLLADA (.dae) files.
 -		</text>
 -		<panel
 -		 top_delta="40"
 -		 left="15"
 -		 height="245"
 -		 width="500"
 -		 name="content"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true">
 -			<text
 -			 type="string"
 -			 length="1"
 -			 text_color="White" 
 -			 follows="left|top"
 -			 top="10"
 -			 height="10"
 -			 layout="topleft"
 -			 left_delta="10"
 -			 name="Cache location"
 -			 width="300">
 -				Filename:
 -			</text>
 -			<line_editor
 -			 border_style="line"
 -			 border_thickness="1"
 -			 follows="left|top"
 -			 font="SansSerifSmall"
 -			 height="20"
 -			 layout="topleft"
 -			 left_delta="0"
 -			 max_length="4096"
 -			 name="lod_file"
 -			 top_pad="5"
 -			 width="220" />
 -			<button
 -			 follows="left|top"
 -			 height="23"
 -			 label="Browse..."
 -			 label_selected="Browse..."
 -			 layout="topleft"
 -			 left_pad="5"
 -			 name="browse"
 -			 top_delta="-1"
 -			 width="85">
 -			</button>
 -			<text
 -			 top_delta="-15"
 -			 width="200"
 -			 height="15"
 -			 font="SansSerifSmall"
 -			 layout="topleft"
 -			 text_color="White"
 -			 left_pad="19">
 -				Model Preview:
 -			</text>
 -			<!-- Placeholder panel for 3D preview render -->
 -			<panel
 -			 left_delta="0"
 -			 top_pad="0"
 -			 name="preview_panel"
 -			 bevel_style="none"
 -			 border_style="line"
 -			 border="true"
 -			 height="150"
 -			 follows="all"
 -			 width="150">
 -			</panel>
 -			<text
 -			 top_pad="10"
 -			 width="130"
 -			 height="15"
 -			 left="340"
 -			 text_color="White"
 -			 word_wrap="true">
 -				Dimensions (meters):
 -			</text>
 -			<text
 -			 top_pad="2"
 -			 width="160"
 -			 height="15"
 -			 name="import_dimensions"
 -			 left_delta="0">
 -				X:  [X] |Y:  [Y] |Z: [Z]
 -			</text>
 -			<text
 -			 top="100"
 -			 width="320"
 -			 height="15"
 -			 left="10"
 -			 text_color="White" 
 -			 word_wrap="true">
 -				Note:
 -			</text>
 -			<text
 -			 top_pad="0"
 -			 width="320"
 -			 height="40"
 -			 left="10"
 -			 word_wrap="true">
 -Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] .
 -			</text>
 -		</panel>
 -	</panel>
 -
 -
 -	<panel
 -		 height="388"
 -		 top_delta="0"
 -		 name="optimize_panel"
 -		 visible="true"
 -		 width="530"
 -		 left="0">
 -		<panel
 -		 height="20"
 -		 top_pad="20"
 -		 name="header_panel"
 -		 width="500"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true"
 -		 left="20">
 -			<text
 -			 width="200"
 -			 left="10"
 -			 name="header_text"
 -			 top="2"
 -			 height="10"
 -			 font="SansSerifBig"
 -			 layout="topleft">
 -				Optimize
 -			</text>
 -		</panel>
 -		<text
 -		 top_pad="14"
 -		 width="460"
 -		 height="20"
 -		 font="SansSerifSmall"
 -		 layout="topleft"
 -		 name="description"
 -		 word_wrap="true"
 -		 left_delta="0">
 -			This wizard is optimizing your model. This may take several minutes. To stop the process click the back button
 -		</text>
 -		<panel
 -		 top_delta="40"
 -		 visible="false"
 -		 left="15"
 -		 height="245"
 -		 width="500"
 -		 name="content"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true">
 -			<text
 -			 top="20"
 -			 width="300"
 -			 height="12"
 -			 font="SansSerifBold"
 -			 left="112">Generating Level of Detail</text>
 -			<progress_bar
 -			  name="optimize_progress_bar"
 -              image_fill="model_wizard\progress_light.png"
 -			  color_bg="1 1 1 1"
 -			  color_bar="1 1 1 0.96"
 -			  follows="left|right|top"
 -			  width="260"
 -			  height="16"
 -			  image_bar="model_wizard\progress_bar_bg.png"
 -			  top_pad="14"
 -			  left="110"/>
 -			<icon
 -			 top_pad="10"
 -			 left_delta="0"
 -			 width="13"
 -			 height="12"
 -			 image_name="model_wizard\check_mark.png"/>
 -			<text
 -			 top_delta="0"
 -			 left_delta="18"
 -			 name="high_detail_text"
 -			 width="200"
 -			 height="14">Generate Level of Detail: High</text>
 -			<icon
 -			 top_pad="10"
 -			 left_delta="-18"
 -			 width="13"
 -			 height="12"
 -			 image_name="model_wizard\check_mark.png"/>
 -			<text
 -			 top_delta="0"
 -			 left_delta="18"
 -			 name="medium_detail_text"
 -			 width="200"
 -			 height="14">Generate Level of Detail: Medium</text>
 -			<icon
 -			 top_pad="10"
 -			 left_delta="-18"
 -			 width="13"
 -			 height="12"
 -			 image_name="model_wizard\check_mark.png"/>
 -			<text
 -			 top_delta="0"
 -			 left_delta="18"
 -			 name="low_detail_text"
 -			 width="200"
 -			 height="14">Generate Level of Detail: Low</text>
 -			<icon
 -			 top_pad="10"
 -			 left_delta="-18"
 -			 width="13"
 -			 height="12"
 -			 image_name="model_wizard\check_mark.png"/>
 -			<text
 -			 top_delta="0"
 -			 left_delta="18"
 -			 name="lowest_detail_text"
 -			 width="200"
 -			 height="14">Generate Level of Detail: Lowest</text>
 -		</panel>
 -		<panel
 -				 top_delta="0"
 -				 left_delta="0"
 -				 height="245"
 -				 width="500"
 -				 name="content2"
 -				 bg_opaque_color="DkGray2"
 -				 background_visible="true"
 -				 background_opaque="true">
 -			<text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label">
 -				Model Preview:
 -			</text>
 -			<combo_box left_pad="5" top_delta="-2"  follows="left|top" list_position="below" height="18"
 -	     name="preview_lod_combo" width="90" tool_tip="LOD to view in preview render">
 -				<combo_item name="high">
 -					High
 -				</combo_item>
 -				<combo_item name="medium">
 -					Medium
 -				</combo_item>
 -				<combo_item name="lowest">
 -					Lowest
 -				</combo_item>
 -				<combo_item name="low">
 -					Low
 -				</combo_item>
 -			</combo_box>
 -			<panel
 -				 left="10"
 -				 top_pad="5"
 -				 name="preview_panel"
 -				 bevel_style="none"
 -				 border_style="line"
 -				 border="true"
 -				 height="175"
 -				 follows="all"
 -				 width="175">
 -			</panel>
 -			<text top="35" left="220" text_color="White" font="SansSerifSmallBold" width="300" height="4">Performance</text>
 -			<text top="55" left="200" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">Faster rendering but less detailed; lowers Resource (prim) cost.</text>
 -			<text top="35" left="380" text_color="White" font="SansSerifSmallBold" width="300" height="4">Accuracy</text>
 -			<text top="55" left="360" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">More detailed model but slower; increases Resource (prim) cost.</text>
 -
 -			<slider
 -		   follows="left|top"
 -		   height="20"
 -		   increment="1"
 -		   layout="topleft"
 -		   left="200"
 -		   max_val="2"
 -		   initial_value="1"
 -		   min_val="0"
 -		   name="accuracy_slider"
 -		   show_text="false"
 -		   top="105"
 -		   width="290" />
 -			<text 
 -			font="SansSerifSmall" 
 -			top_pad="1"  
 -			width="300" 
 -			left_delta="6" 
 -			height="4">'                                             '                                             '</text>
 -			<text top_delta="25" width="100" text_color="White" left_delta="50"  height="20">Resource Cost:</text>
 -			<text top_delta="25" width="100" text_color="White" left_delta="0"  height="20">Upload Fee:</text>
 -			<text
 -			 top_pad="15"
 -			 width="130"
 -			 height="15"
 -			 left="10"
 -			 text_color="White"
 -			 word_wrap="true">
 -				Dimensions (meters):
 -			</text>
 -			<text
 -			 top_pad="0"
 -			 width="160"
 -			 height="15"
 -			 name="import_dimensions"
 -			 left_delta="0">
 -				X:  [X] |Y:  [Y] |Z: [Z]
 -			</text>
 -		</panel>
 -	</panel>
 -
 -
 -
 -	<panel
 -		 height="388"
 -		 top_delta="0"
 -		 name="physics_panel"
 -		 visible="false"
 -		 width="530"
 -		 left="0">
 -		<panel
 -		 height="20"
 -		 top_pad="20"
 -		 name="header_panel"
 -		 width="500"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true"
 -		 left="20">
 -			<text
 -			 width="200"
 -			 left="10"
 -			 name="header_text"
 -			 top="2"
 -			 height="10"
 -			 font="SansSerifBig"
 -			 layout="topleft">
 -				Physics
 -			</text>
 -		</panel>
 -		<text
 -		 top_pad="14"
 -		 width="460"
 -		 height="20"
 -		 font="SansSerifSmall"
 -		 layout="topleft"
 -		 name="description"
 -		 word_wrap="true"
 -		 left_delta="0">
 -			The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used:
 -		</text>
 -		<panel
 -		 top_delta="40"
 -		 left="15"
 -		 height="245"
 -		 width="500"
 -		 name="content"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true"/>
 -	</panel>
 -
 -
 -	<panel
 -		 height="388"
 -		 top_delta="0"
 -		 name="review_panel"
 -		 visible="false"
 -		 width="530"
 -		 left="0">
 -		<panel
 -		 height="20"
 -		 top_pad="20"
 -		 name="header_panel"
 -		 width="500"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true"
 -		 left="20">
 -			<text
 -			 width="200"
 -			 left="10"
 -			 name="header_text"
 -			 top="2"
 -			 height="10"
 -			 font="SansSerifBig"
 -			 layout="topleft">
 -				Review
 -			</text>
 -		</panel>
 -		<text
 -		 top_pad="14"
 -		 width="460"
 -		 height="20"
 -		 font="SansSerifSmall"
 -		 layout="topleft"
 -		 name="description"
 -		 word_wrap="true"
 -		 left_delta="0">
 -			Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload.
 -		</text>
 -		<panel
 -		 top_delta="40"
 -		 left="15"
 -		 height="245"
 -		 width="500"
 -		 name="content"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true"/>
 -	</panel>
 -
 -
 -
 -
 -	<panel
 -		 height="388"
 -		 top_delta="0"
 -		 name="upload_panel"
 -		 visible="false"
 -		 width="530"
 -		 left="0">
 -		<panel
 -		 height="20"
 -		 top_pad="20"
 -		 name="header_panel"
 -		 width="500"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true"
 -		 left="20">
 -			<text
 -			 width="200"
 -			 left="10"
 -			 name="header_text"
 -			 top="2"
 -			 height="10"
 -			 font="SansSerifBig"
 -			 layout="topleft">
 -				Upload Complete!
 -			</text>
 -		</panel>
 -		<text
 -		 top_pad="14"
 -		 width="460"
 -		 height="20"
 -		 font="SansSerifSmall"
 -		 layout="topleft"
 -		 name="description"
 -		 word_wrap="true"
 -		 left_delta="0">
 -			Congratulations! Your model has been sucessfully uploaded.  You will find the model in the Objects folder in your inventory.
 -		</text>
 -		<panel
 -		 top_delta="40"
 -		 left="15"
 -		 height="245"
 -		 width="500"
 -		 name="content"
 -		 bg_opaque_color="DkGray2"
 -		 background_visible="true"
 -		 background_opaque="true">
 -			<button top="10" follows="top|left" height="20" label="Upload"
 -				   left="15" width="80" name="ok_btn" tool_tip="Upload to simulator"/>
 -		</panel>
 -	</panel>
 -
 -
 -
 -	<button
 -	 top="412"
 -	 right="-245"
 -	 width="90"
 -	 height="22"
 -	 name="back"
 -	 label="<< Back" />
 -	<button
 -	 top_delta="0"
 -	 right="-150"
 -	 width="90"
 -	 height="22"
 -	 name="next"
 -	 label="Next >> " />
 -	<button
 -	 top_delta="0"
 -	 right="-15"
 -	 width="90"
 -	 height="22"
 -	 name="cancel"
 -	 label="Cancel" />
 -	<spinner visible="false" left="10" height="20" follows="top|left" width="80" top_pad="-50" value="1.0" min_val="0.01" max_val="64.0" name="import_scale"/>
 -
 -	<string name="status_idle">Idle</string>
 -	<string name="status_reading_file">Loading...</string>
 -	<string name="status_generating_meshes">Generating Meshes...</string>
 -	<string name="high">High</string>
 -	<string name="medium">Medium</string>
 -	<string name="low">Low</string>
 -	<string name="lowest">Lowest</string>
 -	<string name="mesh_status_good">Ship it!</string>
 -	<string name="mesh_status_na">N/A</string>
 -	<string name="mesh_status_none">None</string>
 -	<string name="mesh_status_submesh_mismatch">Levels of detail have a different number of textureable faces.</string>
 -	<string name="mesh_status_mesh_mismatch">Levels of detail have a different number of mesh instances.</string>
 -	<string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string>
 -	<string name="mesh_status_missing_lod">Missing required level of detail.</string>
 -	<string name="layer_all">All</string>
 -	<!-- Text to display in physics layer combo box for "all layers" -->
 -
 -</floater>
 +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + layout="topleft" + name="Model Wizard" + help_topic="model_wizard" + bg_opaque_image_overlay="0.5 0.5 0.5 1" + height="475" + save_rect="true" + title="UPLOAD MODEL WIZARD" + width="530"> +	<button +	 top="32" +	 tab_stop="false" +	 left="410" +	 height="32" +	 name="upload_btn" +	 enabled="false" +	 label="5. Upload" +	 border="false" +	 image_unselected="model_wizard/middle_button_off.png" +	 image_selected="model_wizard/middle_button_press.png" +	 image_hover_unselected="model_wizard/middle_button_over.png" +	 image_disabled="model_wizard/middle_button_disabled.png" +	 image_disabled_selected="model_wizard/middle_button_disabled.png" +	 width="110"/> +	<button +	 top="32" +	 left="310" +	 height="32" +	 tab_stop="false" +	 name="review_btn" +	 label="4. Review" +	 enabled="false" +	 border="false" +	 image_unselected="model_wizard/middle_button_off.png" +	 image_selected="model_wizard/middle_button_press.png" +	 image_hover_unselected="model_wizard/middle_button_over.png" +	 image_disabled="model_wizard/middle_button_disabled.png" +	 image_disabled_selected="model_wizard/middle_button_disabled.png" +	 width="110"/> +	<button +	 top="32" +	 left="210" +	 height="32" +	 name="physics_btn" +	 label="3. Physics" +	 tab_stop="false" +	 enabled="false" +	 border="false" +	 image_unselected="model_wizard/middle_button_off.png" +	 image_selected="model_wizard/middle_button_press.png" +	 image_hover_unselected="model_wizard/middle_button_over.png" +	 image_disabled="model_wizard/middle_button_disabled.png" +	 image_disabled_selected="model_wizard/middle_button_disabled.png" +	 width="110"/> +	<button +	 top="32" +	 left="115" +	 name="optimize_btn" +	 label="2. Optimize" +	 tab_stop="false" +	 height="32" +	 border="false" +	 image_unselected="model_wizard/middle_button_off.png" +	 image_selected="model_wizard/middle_button_press.png" +	 image_hover_unselected="model_wizard/middle_button_over.png" +	 image_disabled="model_wizard/middle_button_disabled.png" +	 image_disabled_selected="model_wizard/middle_button_disabled.png" +	 width="110"/> +	<button +	 top="32" +	 left="15" +	 name="choose_file_btn" +	 tab_stop="false" +	 enabled="false" +	 label="1. Choose File" +	 height="32" +	 image_unselected="model_wizard/left_button_off.png" +	 image_selected="model_wizard/left_button_press.png" +	 image_hover_unselected="model_wizard/left_button_over.png" +	 image_disabled="model_wizard/left_button_disabled.png" +	 image_disabled_selected="model_wizard/left_button_disabled.png" +	 width="110"/> +	<panel +		 height="388" +		 top_pad="0" +		 name="choose_file_panel" +		 visible="false" +		 width="530" +		 left="0"> +		<panel +		 height="20" +		 top_pad="20" +		 width="500" +		 name="header_panel" +		 bg_opaque_color="DkGray2" +		 background_visible="true" +		 background_opaque="true" +		 left="20"> +			<text +			 width="200" +			 left="10" +			 top="2" +			 name="header_text" +			 height="10" +			 font="SansSerifBig" +			 layout="topleft"> +				Upload Model +			</text> +		</panel> +		<text +		 top_pad="14" +		 width="460" +		 height="20" +		 name="description" +		 font="SansSerifSmall" +		 layout="topleft" +		 word_wrap="true" +		 left_delta="0"> +			This wizard will help you import mesh models to Second Life.  First specify a file containing the model you wish to import.  Second Life supports COLLADA (.dae) files. +		</text> +		<panel +		 top_delta="40" +		 left="15" +		 height="245" +		 width="500" +		 name="content" +		 bg_opaque_color="DkGray2" +		 background_visible="true" +		 background_opaque="true"> +			<text +			 type="string" +			 length="1" +			 text_color="White"  +			 follows="left|top" +			 top="10" +			 height="10" +			 layout="topleft" +			 left_delta="10" +			 name="Cache location" +			 width="300"> +				Filename: +			</text> +			<line_editor +			 border_style="line" +			 border_thickness="1" +			 follows="left|top" +			 font="SansSerifSmall" +			 height="20" +			 layout="topleft" +			 left_delta="0" +			 max_length="4096" +			 name="lod_file" +			 top_pad="5" +			 width="220" /> +			<button +			 follows="left|top" +			 height="23" +			 label="Browse..." +			 label_selected="Browse..." +			 layout="topleft" +			 left_pad="5" +			 name="browse" +			 top_delta="-1" +			 width="85"> +			</button> +			<text +			 top_delta="-15" +			 width="200" +			 height="15" +			 font="SansSerifSmall" +			 layout="topleft" +			 text_color="White" +			 left_pad="19"> +				Model Preview: +			</text> +			<!-- Placeholder panel for 3D preview render --> +			<panel +			 left_delta="0" +			 top_pad="0" +			 name="preview_panel" +			 bevel_style="none" +			 border_style="line" +			 border="true" +			 height="150" +			 follows="all" +			 width="150"> +			</panel> +			<text +			 top_pad="10" +			 width="130" +			 height="15" +			 left="340" +			 text_color="White" +			 word_wrap="true"> +				Dimensions (meters): +			</text> +			<text +			 top_pad="2" +			 width="160" +			 height="15" +			 name="import_dimensions" +			 left_delta="0"> +				X:  [X] |Y:  [Y] |Z: [Z] +			</text> +			<text +			 top="100" +			 width="320" +			 height="15" +			 left="10" +			 text_color="White"  +			 word_wrap="true"> +				Note: +			</text> +			<text +			 top_pad="0" +			 width="320" +			 height="40" +			 left="10" +			 word_wrap="true"> +Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . +			</text> +		</panel> +	</panel> + + +	<panel +		 height="388" +		 top_delta="0" +		 name="optimize_panel" +		 visible="false" +		 width="530" +		 left="0"> +		<panel +		 height="20" +		 top_pad="20" +		 name="header_panel" +		 width="500" +		 bg_opaque_color="DkGray2" +		 background_visible="true" +		 background_opaque="true" +		 left="20"> +			<text +			 width="200" +			 left="10" +			 name="header_text" +			 top="2" +			 height="10" +			 font="SansSerifBig" +			 layout="topleft"> +				Optimize +			</text> +		</panel> +		<text +		 top_pad="14" +		 width="460" +		 height="20" +		 font="SansSerifSmall" +		 layout="topleft" +		 name="description" +		 word_wrap="true" +		 left_delta="0"> +			This wizard is optimizing your model. This may take several minutes. To stop the process click the back button +		</text> +		<panel +		 top_delta="40" +		 visible="false" +		 left="15" +		 height="245" +		 width="500" +		 name="content" +		 bg_opaque_color="DkGray2" +		 background_visible="true" +		 background_opaque="true"> +			<text +			 top="20" +			 width="300" +			 height="12" +			 font="SansSerifBold" +			 left="112">Generating Level of Detail</text> +			<progress_bar +			  name="optimize_progress_bar" +              image_fill="model_wizard\progress_light.png" +			  color_bg="1 1 1 1" +			  color_bar="1 1 1 0.96" +			  follows="left|right|top" +			  width="260" +			  height="16" +			  image_bar="model_wizard\progress_bar_bg.png" +			  top_pad="14" +			  left="110"/> +			<icon +			 top_pad="10" +			 left_delta="0" +			 width="13" +			 height="12" +			 image_name="model_wizard\check_mark.png"/> +			<text +			 top_delta="0" +			 left_delta="18" +			 name="high_detail_text" +			 width="200" +			 height="14">Generate Level of Detail: High</text> +			<icon +			 top_pad="10" +			 left_delta="-18" +			 width="13" +			 height="12" +			 image_name="model_wizard\check_mark.png"/> +			<text +			 top_delta="0" +			 left_delta="18" +			 name="medium_detail_text" +			 width="200" +			 height="14">Generate Level of Detail: Medium</text> +			<icon +			 top_pad="10" +			 left_delta="-18" +			 width="13" +			 height="12" +			 image_name="model_wizard\check_mark.png"/> +			<text +			 top_delta="0" +			 left_delta="18" +			 name="low_detail_text" +			 width="200" +			 height="14">Generate Level of Detail: Low</text> +			<icon +			 top_pad="10" +			 left_delta="-18" +			 width="13" +			 height="12" +			 image_name="model_wizard\check_mark.png"/> +			<text +			 top_delta="0" +			 left_delta="18" +			 name="lowest_detail_text" +			 width="200" +			 height="14">Generate Level of Detail: Lowest</text> +		</panel> +		<panel +				 top_delta="0" +				 left_delta="0" +				 height="245" +				 width="500" +				 name="content2" +				 bg_opaque_color="DkGray2" +				 background_visible="true" +				 background_opaque="true"> +			<text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label"> +				Model Preview: +			</text> +			<combo_box left_pad="5" top_delta="-2"  follows="left|top" list_position="below" height="18" +	     name="preview_lod_combo" width="90" tool_tip="LOD to view in preview render"> +				<combo_item name="high"> +					High +				</combo_item> +				<combo_item name="medium"> +					Medium +				</combo_item> +				<combo_item name="lowest"> +					Lowest +				</combo_item> +				<combo_item name="low"> +					Low +				</combo_item> +			</combo_box> +			<panel +				 left="10" +				 top_pad="5" +				 name="preview_panel" +				 bevel_style="none" +				 border_style="line" +				 border="true" +				 height="175" +				 follows="all" +				 width="175"> +			</panel> +			<text top="35" left="220" text_color="White" font="SansSerifSmallBold" width="300" height="4">Performance</text> +			<text top="55" left="200" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">Faster rendering but less detailed; lowers Resource (prim) cost.</text> +			<text top="35" left="380" text_color="White" font="SansSerifSmallBold" width="300" height="4">Accuracy</text> +			<text top="55" left="360" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">More detailed model but slower; increases Resource (prim) cost.</text> + +			<slider +		   follows="left|top" +		   height="20" +		   increment="1" +		   layout="topleft" +		   left="200" +		   max_val="2" +		   initial_value="1" +		   min_val="0" +		   name="accuracy_slider" +		   show_text="false" +		   top="105" +		   width="290" /> +			<text  +			font="SansSerifSmall"  +			top_pad="1"   +			width="300"  +			left_delta="6"  +			height="4">'                                             '                                             '</text> +			<text top_delta="25" width="100" text_color="White" left_delta="50"  height="20">Resource Cost:</text> +			<text top_delta="25" width="100" text_color="White" left_delta="0"  height="20">Upload Fee:</text> +			<text +			 top_pad="15" +			 width="130" +			 height="15" +			 left="10" +			 text_color="White" +			 word_wrap="true"> +				Dimensions (meters): +			</text> +			<text +			 top_pad="0" +			 width="160" +			 height="15" +			 name="import_dimensions" +			 left_delta="0"> +				X:  [X] |Y:  [Y] |Z: [Z] +			</text> +		</panel> +	</panel> + + + +	<panel +		 height="388" +		 top_delta="0" +		 name="physics_panel" +		 visible="false" +		 width="530" +		 left="0"> +		<panel +		 height="20" +		 top_pad="20" +		 name="header_panel" +		 width="500" +		 bg_opaque_color="DkGray2" +		 background_visible="true" +		 background_opaque="true" +		 left="20"> +			<text +			 width="200" +			 left="10" +			 name="header_text" +			 top="2" +			 height="10" +			 font="SansSerifBig" +			 layout="topleft"> +				Physics +			</text> +		</panel> +		<text +		 top_pad="14" +		 width="460" +		 height="50" +		 font="SansSerifSmall" +		 layout="topleft" +		 name="description" +		 word_wrap="true" +		 left_delta="0"> +			The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: +		</text> +    <panel +		 top_delta="40" +		 left="15" +		 height="245" +		 width="500" +		 name="content" +		 bg_opaque_color="DkGray2" +		 background_visible="true" +		 background_opaque="true"> +      <text top="15" left="30" text_color="White" font="SansSerifSmallBold" width="300" height="4">Performance</text> +      <text top="35" left="10" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">Faster rendering but less detailed; lowers Resource (prim) cost.</text> +      <text top="15" left="390" text_color="White" font="SansSerifSmallBold" width="300" height="4">Accuracy</text> +      <text top="35" left="360" halign="center" width="130" word_wrap="true"   font="SansSerifSmall" height="80">More detailed model but slower; increases Resource (prim) cost.</text> + +      <slider +		   follows="left|top" +		   height="22" +		   increment=".1" +		   layout="topleft" +		   left="20" +		   max_val="1" +		   initial_value="0.5" +		   min_val="0" +		   name="physics_slider" +		   show_text="false" +		   top="80" +		   width="440" /> +      <text +			font="SansSerifSmall" +			top_pad="0" +			width="500" +			left_delta="6" +			height="4">'             '             '             '             '              '             '             '             '              '             '</text> +      <text top_pad="10" width="110" halign="center" word_wrap="true" left="25"  height="40">Recommended for solid objects</text> +      <text top_delta="0" width="110" halign="center" word_wrap="true" left="190"  height="40">Recommended for buildings</text> +      <text top_delta="0" width="110" halign="center" word_wrap="true" left="350"  height="40">Recommended for vehicles</text> +      <text top_delta="60" width="100" text_color="White" left="160"  height="20">Resource Cost:</text> +      <text top_delta="20" width="100" text_color="White" left_delta="0"  height="20">Physics Cost:</text> +      <text top_delta="20" width="100" text_color="White" left_delta="0"  height="20">Upload Fee:</text> +  +    </panel> +	</panel> + + +	<panel +		 height="388" +		 top_delta="0" +		 name="review_panel" +		 visible="false" +		 width="530" +		 left="0"> +		<panel +		 height="22" +		 top_pad="16" +		 name="header_panel" +		 width="500" +		 bg_opaque_color="DkGray2" +		 background_visible="true" +		 background_opaque="true" +		 left="20"> +			<text +			 width="200" +			 left="10" +			 name="header_text" +			 text_color="White"  +			 top="3" +			 height="10" +			 font="SansSerifBig" +			 layout="topleft"> +				Review +			</text> +		</panel> +		<text +		 top_pad="14" +		 width="460" +		 height="20" +		 font="SansSerifSmall" +		 layout="topleft" +		 name="description" +		 word_wrap="true" +		 left_delta="10"> +			Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. +		</text> +    <panel +		 top_delta="40" +		 left="15" +		 height="245" +		 width="500" +		 name="content"> +      <text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label"> +        Model Preview: +      </text> +      <combo_box left_pad="5" top_delta="-2"  follows="left|top" list_position="below" height="18" +	     name="preview_lod_combo" width="90" tool_tip="LOD to view in preview render"> +        <combo_item name="high"> +          High +        </combo_item> +        <combo_item name="medium"> +          Medium +        </combo_item> +        <combo_item name="lowest"> +          Lowest +        </combo_item> +        <combo_item name="low"> +          Low +        </combo_item> +      </combo_box> +      <panel +				 left="10" +				 top_pad="10" +				 name="preview_panel" +				 bevel_style="none" +				 border_style="line" +				 border="true" +				 height="190" +				 follows="all" +				 width="190"> +			</panel>			 +      <text +			 top_pad="8" +			 width="130" +			 height="15" +			 left="10" +			 text_color="White" +			 word_wrap="true"> +				Dimensions (meters): +			</text> +      <text +			 top_pad="0" +			 width="160" +			 height="15" +			 name="import_dimensions" +			 left_delta="0"> +        X:  [X] |Y:  [Y] |Z: [Z] +      </text> +      </panel> +    <text +      width="200" +      height="12" +      top="125"  +      left="230"  +      font="SansSerifSmallBold"  +      text_color="White">Resource Cost:</text> +    <text +      width="285" +      height="30" +      top_pad="0" +      left_delta="0" +      word_wrap="true" +      font="SansSerifItalic">This is the cost to your Region's prim/object limit, at default scale</text> +	<text +	 width="200" +	 height="12" +	 top_pad="10" +		 left_delta="0" +	 font="SansSerifSmallBold" +	 text_color="White">Physics Cost:</text> +	<text +	  width="285" +	  height="30" +	  top_pad="0" +		  left_delta="0" +	  word_wrap="true" +	  font="SansSerifItalic">This is the cost to your Region's prim/object limit, at default scale</text> +		<text +		 width="200" +		 height="12" +		 top_pad="10" +		left_delta="0" +		 font="SansSerifSmallBold" +		 text_color="White">Upload Fee:</text> +		<text +		  width="285" +		  height="26" +		  top_pad="0" +		  left_delta="0" +		  word_wrap="true" +		  font="SansSerifItalic">This is the amount the upload will cost.</text> +		<check_box +			height="16" +			layout="topleft" +			left_delta="0" +			name="confirm_checkbox" +			top_pad="15" +			width="16" /> +		<text +		  height="100" +		  width="240" +		  word_wrap="true"  +		  left_delta="25" +		  top_delta="0">I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more]</text> +	</panel> + + + + +	<panel +		 height="388" +		 top_delta="0" +		 name="upload_panel" +		 visible="true" +		 width="530" +		 left="0"> +		<panel +		 height="20" +		 top_pad="20" +		 name="header_panel" +		 width="500" +		 bg_opaque_color="DkGray2" +		 background_visible="true" +		 background_opaque="true" +		 left="20"> +			<text +			 width="200" +			 left="10" +			 name="header_text" +			 top="2" +			 text_color="White"  +			 height="10" +			 font="SansSerifBig" +			 layout="topleft"> +				Upload Complete! +			</text> +		</panel> +		<text +		 top_pad="14" +		 width="460" +		 height="20" +		 font="SansSerifSmall" +		 layout="topleft" +		 name="description" +		 word_wrap="true" +		 left_delta="0"> +			Congratulations! Your model has been sucessfully uploaded.  You will find the model in the Objects folder in your inventory. +		</text> +		<icon +			 top_pad="15" +			 left_delta="0" +			 width="495" +			 height="2" +			 image_name="model_wizard\divider_line.png"/> +	</panel> + + + +	<button +	 top="440" +	 right="-245" +	 width="90" +	 height="22" +	 name="back" +	 label="<< Back" /> +	<button +	 top_delta="0" +	 right="-150" +	 width="90" +	 height="22" +	 name="next" +	 label="Next >> " /> +	<button +	 top_delta="0" +	 right="-150" +	 width="90" +	 height="22" +	 visible="false"  +	 name="upload"  +	 tool_tip="Upload to simulator" +	 label="Upload" /> +	<button +	 top_delta="0" +	 right="-15" +	 width="90" +	 height="22" +	 name="cancel" +	 label="Cancel" /> +	<button +	 top_delta="0" +	 right="-15" +	 width="90" +	 height="22" +	 name="close" +	 visible="false"  +	 label="Close" /> +	<spinner visible="false" left="10" height="20" follows="top|left" width="80" top_pad="-50" value="1.0" min_val="0.01" max_val="64.0" name="import_scale"/> + +	<string name="status_idle">Idle</string> +	<string name="status_reading_file">Loading...</string> +	<string name="status_generating_meshes">Generating Meshes...</string> +	<string name="high">High</string> +	<string name="medium">Medium</string> +	<string name="low">Low</string> +	<string name="lowest">Lowest</string> +	<string name="mesh_status_good">Ship it!</string> +	<string name="mesh_status_na">N/A</string> +	<string name="mesh_status_none">None</string> +	<string name="mesh_status_submesh_mismatch">Levels of detail have a different number of textureable faces.</string> +	<string name="mesh_status_mesh_mismatch">Levels of detail have a different number of mesh instances.</string> +	<string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string> +	<string name="mesh_status_missing_lod">Missing required level of detail.</string> +	<string name="layer_all">All</string> +	<!-- Text to display in physics layer combo box for "all layers" --> + +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml new file mode 100644 index 0000000000..2ad46824c2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_web_content.xml @@ -0,0 +1,190 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 +<floater
 +  legacy_header_height="18"
 +  can_resize="true"
 +  height="440"
 +  layout="topleft"
 +  min_height="140"
 +  min_width="467"
 +  name="floater_web_content"
 +  help_topic="floater_web_content"
 +  save_rect="true"
 +  auto_tile="true"
 +  title=""
 +  initial_mime_type="text/html"
 +  width="820">
 +  <layout_stack
 +    bottom="440"
 +    follows="left|right|top|bottom"
 +    layout="topleft"
 +    left="5"
 +    name="stack1"
 +    orientation="vertical"
 +    top="20"
 +    width="810">
 +    <layout_panel
 +      auto_resize="false"
 +      default_tab_group="1"
 +      height="22"
 +      layout="topleft"
 +      left="0"
 +      min_height="20"
 +      name="nav_controls"
 +      top="400"
 +      user_resize="false"
 +      width="800">
 +      <button
 +        image_overlay="Arrow_Left_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +		    hover_glow_amount="0.15"
 +        tool_tip="Navigate back"
 +        follows="left|top"
 +        height="22"
 +        layout="topleft"
 +        left="1"
 +        name="back"
 +        top="0"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.Back" />
 +      </button>
 +      <button
 +        image_overlay="Arrow_Right_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +        tool_tip="Navigate forward"
 +        follows="left|top"
 +        height="22"
 +        layout="topleft"
 +        left="27"
 +        name="forward"
 +        top_delta="0"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.Forward" />
 +      </button>
 +      <button
 +        image_overlay="Stop_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +        tool_tip="Stop navigation"
 +        enabled="true"
 +        follows="left|top"
 +        height="22"
 +        layout="topleft"
 +        left="51"
 +        name="stop"
 +        top_delta="0"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.Stop" />
 +      </button>
 +      <button
 +        image_overlay="Refresh_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +        tool_tip="Reload page"
 +        follows="left|top"
 +        height="22"
 +        layout="topleft"
 +        left="51"
 +        name="reload"
 +        top_delta="0"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.Reload" />
 +      </button>
 +      <combo_box
 +        allow_text_entry="true"
 +        follows="left|top|right"
 +        tab_group="1"
 +        height="22"
 +        layout="topleft"
 +        left_pad="4"
 +        max_chars="1024"
 +        name="address"
 +        combo_editor.select_on_focus="true"
 +        tool_tip="Enter URL here"
 +        top_delta="0"
 +        width="702">
 +        <combo_box.commit_callback
 +          function="WebContent.EnterAddress" />
 +      </combo_box>
 +      <icon
 +        name="media_secure_lock_flag"
 +        height="16"
 +        follows="top|right"
 +        image_name="Lock2"
 +        layout="topleft"
 +        left_delta="656"
 +        top_delta="2"
 +        visible="false" 
 +        tool_tip="Secured Browsing"
 +        width="16" />
 +      <button
 +        image_overlay="ExternalBrowser_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +        tool_tip="Open current URL in your desktop browser"
 +        follows="right|top"
 +        enabled="true" 
 +        height="22"
 +        layout="topleft"
 +        name="popexternal"
 +        right="800"
 +        top_delta="-2"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.PopExternal" />
 +      </button>
 +    </layout_panel>
 +    <layout_panel
 +      height="40"
 +      layout="topleft"
 +      left_delta="0"
 +      name="external_controls"
 +      top_delta="0"
 +      user_resize="false"
 +      width="540">
 +      <web_browser
 +        bottom="-22"
 +        follows="all"
 +        layout="topleft"
 +        left="0"
 +        name="webbrowser"
 +        top="0"/>
 +      <text
 +        type="string"
 +        length="100"
 +        follows="bottom|left"
 +        height="20"
 +        layout="topleft"
 +        left_delta="0"
 +        name="statusbartext"
 +        parse_urls="false"
 +        text_color="0.4 0.4 0.4 1" 
 +        top_pad="5"
 +        width="452"/>
 +      <progress_bar
 +        color_bar="0.3 1.0 0.3 1"
 +        follows="bottom|right"
 +        height="16"
 +        top_delta="-1"
 +        left_pad="24"
 +        layout="topleft"
 +        name="statusbarprogress"
 +        width="64"/>
 +    </layout_panel>
 +  </layout_stack>
 +</floater>
 diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 4f982cc8e9..0d4a095e14 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -176,13 +176,19 @@               parameter="message_critical" />          </menu_item_call>          <menu_item_call -         label="Web Browser Test" +         label="Media Browser Test"           name="Web Browser Test">            <menu_item_call.on_click             function="Advanced.WebBrowserTest"             parameter="http://join.secondlife.com/"/>          </menu_item_call> -      <menu_item_separator/> +      <menu_item_call +       label="Web Content Floater Test" +       name="Web Content Floater Test"> +        <menu_item_call.on_click +         function="Advanced.WebContentTest" +         parameter="http://www.google.com"/> +      </menu_item_call>        <menu_item_check          label="Show Grid Picker"          name="Show Grid Picker" diff --git a/indra/newview/skins/default/xui/en/menu_place.xml b/indra/newview/skins/default/xui/en/menu_place.xml index 1b96eb51f0..288811d2f6 100644 --- a/indra/newview/skins/default/xui/en/menu_place.xml +++ b/indra/newview/skins/default/xui/en/menu_place.xml @@ -24,26 +24,4 @@           function="Places.OverflowMenu.Enable"           parameter="can_create_pick" />      </menu_item_call> -    <menu_item_separator -     layout="topleft"/> -    <menu_item_call -     enabled="false" -     label="Buy Pass" -     layout="topleft" -     name="pass"> -        <menu_item_call.on_click -         function="Places.OverflowMenu.Action" -         parameter="pass" /> -    </menu_item_call> -    <menu_item_separator -     layout="topleft"/> -    <menu_item_call -     enabled="false" -     label="Edit" -     layout="topleft" -     name="edit"> -        <menu_item_call.on_click -         function="Places.OverflowMenu.Action" -         parameter="edit" /> -    </menu_item_call>  </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index df556691f0..b7816b8e25 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2700,13 +2700,21 @@                   parameter="BottomPanelNew" />              </menu_item_check>-->              <menu_item_call -             label="Web Browser Test" +             label="Media Browser Test"               name="Web Browser Test">                  <menu_item_call.on_click                   function="Advanced.WebBrowserTest"                   parameter="http://secondlife.com/app/search/slurls.html"/>              </menu_item_call> -            <menu_item_call +          <menu_item_call +           label="Web Content Browser" +           name="Web Content Browser" +           shortcut="control|alt|W"> +            <menu_item_call.on_click +             function="Advanced.WebContentTest" +             parameter="http://google.com"/> +          </menu_item_call> +          <menu_item_call               label="Dump SelectMgr"               name="Dump SelectMgr">                  <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index d53b299fe2..6af49fdecf 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2901,12 +2901,80 @@ http://secondlife.com/download.       name="okbutton"       yestext="OK"/>    </notification> +    <notification -   icon="notifytip.tga" -   name="DownloadBackground" -   type="notifytip"> -An updated version of [APP_NAME] has been downloaded. -It will be applied the next time you restart [APP_NAME] +   icon="alertmodal.tga" +   name="FailedRequiredUpdateInstall" +   type="alertmodal"> +We were unable to install a required update.  +You will be unable to log in until [APP_NAME] has been updated. + +Please download and install the latest viewer from +http://secondlife.com/download. +    <usetemplate +     name="okbutton" +     yestext="Quit"/> +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="UpdaterServiceNotRunning" +   type="alertmodal"> +There is a required update for your Second Life Installation. + +You may download this update from http://www.secondlife.com/downloads +or you can install it now. +    <usetemplate +     name="okcancelbuttons" +     notext="Quit Second Life" +     yestext="Download and install now"/> +  </notification> + +  <notification +   icon="notify.tga" +   name="DownloadBackgroundTip" +   type="notify"> +We have downloaded an update to your [APP_NAME] installation. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update] +    <usetemplate +     name="okcancelbuttons" +     notext="Later..." +     yestext="Install now and restart [APP_NAME]"/> +  </notification> + +  <notification + icon="alertmodal.tga" + name="DownloadBackgroundDialog" + type="alertmodal"> +We have downloaded an update to your [APP_NAME] installation. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update] +    <usetemplate +     name="okcancelbuttons" +     notext="Later..." +     yestext="Install now and restart [APP_NAME]"/> +  </notification> +   +  <notification + icon="alertmodal.tga" + name="RequiredUpdateDownloadedVerboseDialog" + type="alertmodal"> +We have downloaded a required software update. +Version [VERSION] + +We must restart [APP_NAME] to install the update. +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> +   +  <notification + icon="alertmodal.tga" + name="RequiredUpdateDownloadedDialog" + type="alertmodal"> +We must restart [APP_NAME] to install the update. +    <usetemplate +     name="okbutton" +     yestext="OK"/>    </notification>    <notification @@ -5014,7 +5082,7 @@ If you want to view streaming media on parcels that support it you should go to     type="notify">  No Media Plugin was found to handle the "[MIME_TYPE]" mime type.  Media of this type will be unavailable.      <unique> -      <context key="[MIME_TYPE]"/> +      <context>MIME_TYPE</context>      </unique>    </notification> @@ -5943,7 +6011,7 @@ You may only select up to [MAX_SELECT] items from this list.  [NAME] is inviting you to a Voice Chat call.  Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.      <unique> -      <context key="NAME"/> +      <context>NAME</context>      </unique>      <form name="form">        <button @@ -5992,8 +6060,8 @@ Click Accept to join the call or Decline to decline the invitation. Click Block  [NAME] has joined a Voice Chat call with the group [GROUP].  Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.      <unique> -      <context key="NAME"/> -      <context key="GROUP"/> +      <context>NAME</context> +      <context>GROUP</context>      </unique>      <form name="form">        <button @@ -6018,7 +6086,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block  [NAME] has joined a voice chat call with a conference chat.  Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.      <unique> -      <context key="NAME"/> +      <context>NAME</context>      </unique>      <form name="form">        <button @@ -6043,7 +6111,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block  [NAME] is inviting you to a conference chat.  Click Accept to join the chat or Decline to decline the invitation. Click Block to block this caller.      <unique> -      <context key="NAME"/> +      <context>NAME</context>      </unique>      <form name="form">        <button @@ -6067,7 +6135,7 @@ Click Accept to join the chat or Decline to decline the invitation. Click Block     type="notifytip">  The voice call you are trying to join, [VOICE_CHANNEL_NAME], has reached maximum capacity. Please try again later.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6085,7 +6153,7 @@ We're sorry.  This area has reached maximum capacity for voice conversation     type="notifytip">  You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6095,7 +6163,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect     type="notifytip">  [VOICE_CHANNEL_NAME] has ended the call.  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6105,7 +6173,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect     type="notifytip">  [VOICE_CHANNEL_NAME] has declined your call.  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6115,7 +6183,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect     type="notifytip">  [VOICE_CHANNEL_NAME] is not available to take your call.  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6125,7 +6193,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect     type="notifytip">  Failed to connect to [VOICE_CHANNEL_NAME], please try again later.  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6211,7 +6279,7 @@ Cannot enter parcel, you are not on the access list.     type="notifytip">  You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6221,7 +6289,7 @@ You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].     type="notifytip">  An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_NAME].  Please try again later.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6646,6 +6714,23 @@ Mute everyone?      </form>    </notification> +  <notification +  name="AuthRequest" +  type="browser"> +The site at '<nolink>[HOST_NAME]</nolink>' in realm '[REALM]' requires a user name and password. +    <form name="form"> +      <input name="username" type="text" text="User Name"/> +      <input name="password" type="password" text="Password    "/> +      <button default="true" +              index="0" +              name="ok" +              text="Submit"/> +      <button index="1" +              name="cancel" +              text="Cancel"/> +    </form> +  </notification> +    <global name="UnsupportedCPU">  - Your CPU speed does not meet the minimum requirements. diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index e3cd61c5aa..257ed799da 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -12,11 +12,7 @@ top="600"       name="create_account_url">         http://join.secondlife.com/  </panel.string> -<panel.string -     name="real_url" translate="false"> -       http://secondlife.com/app/login/ -</panel.string> -    <string name="reg_in_client_url" translate="false"> +<string name="reg_in_client_url" translate="false">       http://secondlife.eniac15.lindenlab.com/reg-in-client/  </string>  <panel.string @@ -92,6 +88,7 @@ follows="left|bottom"    height="22"    max_length_bytes="16"  name="password_edit" +is_password="true"   select_on_focus="true"    top_pad="0"    width="135" /> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 584bd1ea9d..901a1257e0 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -142,7 +142,7 @@     layout="topleft"     left="80"     name="Cache location" -   top_delta="40" +   top_delta="20"     width="300">      Cache location:    </text> @@ -341,20 +341,41 @@     name="web_proxy_port"     top_delta="0"     width="145" /> - -  <check_box -    top_delta="2" -    enabled="true" -    follows="left|top" -    height="18" -    initial_value="true" -    control_name="UpdaterServiceActive" -    label="Automatically download and install [APP_NAME] updates" -    left="30" -    mouse_opaque="true" -    name="updater_service_active" -    radio_style="false" -    width="400" -    top_pad="10"/> - +  <text +     type="string" +     length="1" +     follows="left|top" +     height="10" +     layout="topleft" +     left="30" +     name="Software updates:" +     mouse_opaque="false" +     top_pad="5" +     width="300"> +    Software updates: +  </text> +  <combo_box +     control_name="UpdaterServiceSetting" +     follows="left|top" +     height="23" +     layout="topleft" +     left_delta="50" +	 top_pad="5" +     name="updater_service_combobox" +     width="300"> +        <combo_box.item +         label="Install automatically" +         name="Install_automatically" +         value="3" /> +      <!-- +        <combo_box.item +         label="Ask before installing" +         name="Install_ask" +         value="1" /> +      --> +        <combo_box.item +         label="Download and install updates manually" +         name="Install_manual" +         value="0" /> +  </combo_box>  </panel> diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index 2f52ca660b..d756dfb7de 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -51,7 +51,7 @@       height="18"       left="0"        name="balance" -     tool_tip="My Balance" +     tool_tip="Click to refresh your L$ balance"       v_pad="4"       top="0"       wrap="false"  diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 01e91f20e6..1b2571a0d6 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1717,8 +1717,8 @@ integer llGetRegionAgentCount()  Returns the number of avatars in the region  	</string>  	<string name="LSLTipText_llTextBox" translate="false"> -llTextBox(key avatar, string message, integer chat_channel -Shows a dialog box on the avatar's screen with the message. +llTextBox(key avatar, string message, integer chat_channel) +Shows a window on the avatar's screen with the message.  It contains a text box for input, and if entered that text is chatted on chat_channel.  	</string>  	<string name="LSLTipText_llGetAgentLanguage" translate="false"> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 309e9e9ee3..9e321db889 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -40,6 +40,7 @@  #if defined(LL_WINDOWS)  #pragma warning(disable: 4355)      // using 'this' in base-class ctor initializer expr +#pragma warning(disable: 4702)      // disable 'unreachable code' so we can safely use skip().  #endif  // Constants @@ -68,6 +69,7 @@ static bool gDisconnectCalled = false;  #include "../llviewerwindow.h"  void LLViewerWindow::setShowProgress(BOOL show) {} +LLProgressView * LLViewerWindow::getProgressView(void) const { return 0; }  LLViewerWindow* gViewerWindow; @@ -185,6 +187,41 @@ const std::string &LLVersionInfo::getChannelAndVersion() { return VIEWERLOGIN_VE  const std::string &LLVersionInfo::getChannel() { return VIEWERLOGIN_CHANNEL; }  //----------------------------------------------------------------------------- +#include "../llappviewer.h" +void LLAppViewer::forceQuit(void) {} +LLAppViewer * LLAppViewer::sInstance = 0; + +//----------------------------------------------------------------------------- +#include "llnotificationsutil.h" +LLNotificationPtr LLNotificationsUtil::add(const std::string& name,  +					  const LLSD& substitutions,  +					  const LLSD& payload,  +					  boost::function<void (const LLSD&, const LLSD&)> functor) { return LLNotificationPtr((LLNotification*)0); } + + +//----------------------------------------------------------------------------- +#include "llupdaterservice.h" + +std::string const & LLUpdaterService::pumpName(void) +{ +	static std::string wakka = "wakka wakka wakka"; +	return wakka; +} +bool LLUpdaterService::updateReadyToInstall(void) { return false; } +void LLUpdaterService::initialize(const std::string& protocol_version, +				const std::string& url,  +				const std::string& path, +				const std::string& channel, +								  const std::string& version) {} + +void LLUpdaterService::setCheckPeriod(unsigned int seconds) {} +void LLUpdaterService::startChecking(bool install_if_ready) {} +void LLUpdaterService::stopChecking() {} +bool LLUpdaterService::isChecking() { return false; } +LLUpdaterService::eUpdaterState LLUpdaterService::getState() { return INITIAL; } +std::string LLUpdaterService::updatedVersion() { return ""; } + +//-----------------------------------------------------------------------------  #include "llnotifications.h"  #include "llfloaterreg.h"  static std::string gTOSType; @@ -198,6 +235,12 @@ LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key,  	return NULL;  } +//---------------------------------------------------------------------------- +#include "../llprogressview.h" +void LLProgressView::setText(std::string const &){} +void LLProgressView::setPercent(float){} +void LLProgressView::setMessage(std::string const &){} +  //-----------------------------------------------------------------------------  // LLNotifications  class MockNotifications : public LLNotificationsInterface @@ -435,6 +478,8 @@ namespace tut      template<> template<>      void lllogininstance_object::test<3>()      { +		skip(); +		  		set_test_name("Test Mandatory Update User Accepts");  		// Part 1 - Mandatory Update, with User accepts response. @@ -462,6 +507,8 @@ namespace tut  	template<> template<>      void lllogininstance_object::test<4>()      { +		skip(); +		  		set_test_name("Test Mandatory Update User Decline");  		// Test connect with update needed. diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 9fc76a09c4..adf7e4af9b 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -254,12 +254,6 @@ class WindowsManifest(ViewerManifest):              self.enable_crt_manifest_check() -            # Get kdu dll, continue if missing. -            try: -                self.path('llkdu.dll', dst='llkdu.dll') -            except RuntimeError: -                print "Skipping llkdu.dll" -              # Get llcommon and deps. If missing assume static linkage and continue.              try:                  self.path('llcommon.dll') @@ -638,21 +632,21 @@ class DarwinManifest(ViewerManifest):                  libdir = "../../libraries/universal-darwin/lib_release"                  dylibs = {} -                # need to get the kdu dll from any of the build directories as well -                for lib in "llkdu", "llcommon": -                    libfile = "lib%s.dylib" % lib -                    try: -                        self.path(self.find_existing_file(os.path.join(os.pardir, -                                                                       lib, -                                                                       self.args['configuration'], -                                                                       libfile), -                                                          os.path.join(libdir, libfile)), -                                  dst=libfile) -                    except RuntimeError: -                        print "Skipping %s" % libfile -                        dylibs[lib] = False -                    else: -                        dylibs[lib] = True +                # Need to get the llcommon dll from any of the build directories as well +                lib = "llcommon" +                libfile = "lib%s.dylib" % lib +                try: +                    self.path(self.find_existing_file(os.path.join(os.pardir, +                                                                    lib, +                                                                    self.args['configuration'], +                                                                    libfile), +                                                      os.path.join(libdir, libfile)), +                                                      dst=libfile) +                except RuntimeError: +                    print "Skipping %s" % libfile +                    dylibs[lib] = False +                else: +                    dylibs[lib] = True                  if dylibs["llcommon"]:                      for libfile in ("libapr-1.0.3.7.dylib", @@ -949,14 +943,6 @@ class Linux_i686Manifest(LinuxManifest):      def construct(self):          super(Linux_i686Manifest, self).construct() -        # install either the libllkdu we just built, or a prebuilt one, in -        # decreasing order of preference.  for linux package, this goes to bin/ -        try: -            self.path(self.find_existing_file('../llkdu/libllkdu.so', -                '../../libraries/i686-linux/lib_release_client/libllkdu.so'), -                  dst='bin/libllkdu.so') -        except: -            print "Skipping libllkdu.so - not found"          for lib, destdir in ("llkdu", "bin"), ("llcommon", "lib"):              libfile = "lib%s.so" % lib              try: @@ -987,7 +973,6 @@ class Linux_i686Manifest(LinuxManifest):          self.path("featuretable_linux.txt")          #self.path("secondlife-i686.supp") -          if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):              self.path("libapr-1.so.0")              self.path("libaprutil-1.so.0") @@ -1008,12 +993,6 @@ class Linux_i686Manifest(LinuxManifest):              self.path("libtcmalloc_minimal.so", "libtcmalloc_minimal.so") #formerly called google perf tools              self.path("libtcmalloc_minimal.so.0", "libtcmalloc_minimal.so.0") #formerly called google perf tools              try: -                    self.path("libkdu.so") -                    pass -            except: -                    print "Skipping libkdu.so - not found" -                    pass -            try:                      self.path("libfmod-3.75.so")                      pass              except: diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 66c78a86c4..e9eb3c1884 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -27,6 +27,7 @@ include_directories(      ${LLXML_INCLUDE_DIRS}      ${LSCRIPT_INCLUDE_DIRS}      ${GOOGLEMOCK_INCLUDE_DIRS} +    ${TUT_INCLUDE_DIR}      )  set(test_SOURCE_FILES diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp index 873fa23db8..4a2272032b 100644 --- a/indra/test_apps/llplugintest/llmediaplugintest.cpp +++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp @@ -2220,6 +2220,21 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e  				<< ", height = " << self->getGeometryHeight()   				<< std::endl;  		break; + +		case MEDIA_EVENT_AUTH_REQUEST: +		{ +			//std::cerr <<  "Media event:  MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() ", realm " << self->getAuthRealm() << std::endl; + +			// TODO: display an auth dialog +			self->sendAuthResponse(false, "", ""); +		} +		break; + +		case MEDIA_EVENT_LINK_HOVERED: +		{ +			std::cerr <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << std::endl; +		}; +		break;  	}  } diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index c17a50e242..e88d1bf811 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -24,17 +24,20 @@   */  #include "linden_common.h" + +#include "llupdatedownloader.h" +  #include <stdexcept>  #include <boost/format.hpp>  #include <boost/lexical_cast.hpp>  #include <curl/curl.h>  #include "lldir.h" +#include "llevents.h"  #include "llfile.h"  #include "llmd5.h"  #include "llsd.h"  #include "llsdserialize.h"  #include "llthread.h" -#include "llupdatedownloader.h"  #include "llupdaterservice.h" @@ -45,18 +48,25 @@ public:  	Implementation(LLUpdateDownloader::Client & client);  	~Implementation();  	void cancel(void); -	void download(LLURI const & uri, std::string const & hash); +	void download(LLURI const & uri, +				  std::string const & hash, +				  std::string const & updateVersion, +				  bool required);  	bool isDownloading(void);  	size_t onHeader(void * header, size_t size);  	size_t onBody(void * header, size_t size); +	int onProgress(double downloadSize, double bytesDownloaded);  	void resume(void); +	void setBandwidthLimit(U64 bytesPerSecond);  private: +	curl_off_t mBandwidthLimit;  	bool mCancelled;  	LLUpdateDownloader::Client & mClient;  	CURL * mCurl;  	LLSD mDownloadData;  	llofstream mDownloadStream; +	unsigned char mDownloadPercent;  	std::string mDownloadRecordPath;  	curl_slist * mHeaderList; @@ -113,9 +123,12 @@ void LLUpdateDownloader::cancel(void)  } -void LLUpdateDownloader::download(LLURI const & uri, std::string const & hash) +void LLUpdateDownloader::download(LLURI const & uri, +								  std::string const & hash, +								  std::string const & updateVersion, +								  bool required)  { -	mImplementation->download(uri, hash); +	mImplementation->download(uri, hash, updateVersion, required);  } @@ -131,6 +144,12 @@ void LLUpdateDownloader::resume(void)  } +void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) +{ +	mImplementation->setBandwidthLimit(bytesPerSecond); +} + +  // LLUpdateDownloader::Implementation  //----------------------------------------------------------------------------- @@ -149,14 +168,27 @@ namespace {  		size_t bytes = blockSize * blocks;  		return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onHeader(data, bytes);  	} + + +	int progress_callback(void * downloader, +						  double dowloadTotal, +						  double downloadNow, +						  double uploadTotal, +						  double uploadNow) +	{ +		return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)-> +			onProgress(dowloadTotal, downloadNow); +	}  }  LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client):  	LLThread("LLUpdateDownloader"), +	mBandwidthLimit(0),  	mCancelled(false),  	mClient(client),  	mCurl(0), +	mDownloadPercent(0),  	mHeaderList(0)  {  	CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case. @@ -182,12 +214,17 @@ void LLUpdateDownloader::Implementation::cancel(void)  } -void LLUpdateDownloader::Implementation::download(LLURI const & uri, std::string const & hash) +void LLUpdateDownloader::Implementation::download(LLURI const & uri, +												  std::string const & hash, +												  std::string const & updateVersion, +												  bool required)  {  	if(isDownloading()) mClient.downloadError("download in progress");  	mDownloadRecordPath = downloadMarkerPath();  	mDownloadData = LLSD(); +	mDownloadData["required"] = required; +	mDownloadData["update_version"] = updateVersion;  	try {  		startDownloading(uri, hash);  	} catch(DownloadError const & e) { @@ -233,12 +270,18 @@ void LLUpdateDownloader::Implementation::resume(void)  				resumeDownloading(fileStatus.st_size);  			} else if(!validateDownload()) {  				LLFile::remove(filePath); -				download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString()); +				download(LLURI(mDownloadData["url"].asString()),  +						 mDownloadData["hash"].asString(), +						 mDownloadData["update_version"].asString(), +						 mDownloadData["required"].asBoolean());  			} else {  				mClient.downloadComplete(mDownloadData);  			}  		} else { -			download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString()); +			download(LLURI(mDownloadData["url"].asString()),  +					 mDownloadData["hash"].asString(), +					 mDownloadData["update_version"].asString(), +					 mDownloadData["required"].asBoolean());  		}  	} catch(DownloadError & e) {  		mClient.downloadError(e.what()); @@ -246,6 +289,20 @@ void LLUpdateDownloader::Implementation::resume(void)  } +void LLUpdateDownloader::Implementation::setBandwidthLimit(U64 bytesPerSecond) +{ +	if((mBandwidthLimit != bytesPerSecond) && isDownloading() && !mDownloadData["required"].asBoolean()) { +		llassert(mCurl != 0); +		mBandwidthLimit = bytesPerSecond; +		CURLcode code = curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit); +		if(code != CURLE_OK) LL_WARNS("UpdateDownload") <<  +			"unable to change dowload bandwidth" << LL_ENDL; +	} else { +		mBandwidthLimit = bytesPerSecond; +	} +} + +  size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size)  {  	char const * headerPtr = reinterpret_cast<const char *> (buffer); @@ -290,6 +347,30 @@ size_t LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size)  } +int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double bytesDownloaded) +{ +	int downloadPercent = static_cast<int>(100. * (bytesDownloaded / downloadSize)); +	if(downloadPercent > mDownloadPercent) { +		mDownloadPercent = downloadPercent; +		 +		LLSD event; +		event["pump"] = LLUpdaterService::pumpName(); +		LLSD payload; +		payload["type"] = LLSD(LLUpdaterService::PROGRESS); +		payload["download_size"] = downloadSize; +		payload["bytes_downloaded"] = bytesDownloaded; +		event["payload"] = payload; +		LLEventPumps::instance().obtain("mainlooprepeater").post(event); +		 +		LL_INFOS("UpdateDownload") << "progress event " << payload << LL_ENDL; +	} else { +		; // Keep events to a reasonalbe number. +	} +	 +	return 0; +} + +  void LLUpdateDownloader::Implementation::run(void)  {  	CURLcode code = curl_easy_perform(mCurl); @@ -343,6 +424,14 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u  	}  	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true));  	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str())); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSFUNCTION, &progress_callback)); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSDATA, this)); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOPROGRESS, false)); +	// if it's a required update set the bandwidth limit to 0 (unlimited) +	curl_off_t limit = mDownloadData["required"].asBoolean() ? 0 : mBandwidthLimit; +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, limit)); +	 +	mDownloadPercent = 0;  } diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h index 1b3d7480fd..0d635640cf 100644 --- a/indra/viewer_components/updater/llupdatedownloader.h +++ b/indra/viewer_components/updater/llupdatedownloader.h @@ -52,7 +52,10 @@ public:  	void cancel(void);  	// Start a new download. -	void download(LLURI const & uri, std::string const & hash); +	void download(LLURI const & uri, +				  std::string const & hash,  +				  std::string const & updateVersion, +				  bool required=false);  	// Returns true if a download is in progress.  	bool isDownloading(void); @@ -60,6 +63,9 @@ public:  	// Resume a partial download.  	void resume(void); +	// Set a limit on the dowload rate. +	void setBandwidthLimit(U64 bytesPerSecond); +	  private:  	boost::shared_ptr<Implementation> mImplementation;  }; @@ -76,6 +82,7 @@ public:  	// url - source (remote) location  	// hash - the md5 sum that should match the installer file.  	// path - destination (local) location +	// required - boolean indicating if this is a required update.  	// size - the size of the installer in bytes  	virtual void downloadComplete(LLSD const & data) = 0; diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp index 650ef88af4..c7b70c2de8 100644 --- a/indra/viewer_components/updater/llupdateinstaller.cpp +++ b/indra/viewer_components/updater/llupdateinstaller.cpp @@ -31,6 +31,12 @@  #include "lldir.h"  +#if defined(LL_WINDOWS) +#pragma warning(disable: 4702)      // disable 'unreachable code' so we can use lexical_cast (really!). +#endif +#include <boost/lexical_cast.hpp> + +  namespace {  	class RelocateError {}; @@ -47,7 +53,10 @@ namespace {  } -int ll_install_update(std::string const & script, std::string const & updatePath, LLInstallScriptMode mode) +int ll_install_update(std::string const & script, +					  std::string const & updatePath, +					  bool required, +					  LLInstallScriptMode mode)  {  	std::string actualScriptPath;  	switch(mode) { @@ -73,6 +82,7 @@ int ll_install_update(std::string const & script, std::string const & updatePath  	launcher.setExecutable(actualScriptPath);  	launcher.addArgument(updatePath);  	launcher.addArgument(ll_install_failed_marker_path().c_str()); +	launcher.addArgument(boost::lexical_cast<std::string>(required));  	int result = launcher.launch();  	launcher.orphan(); diff --git a/indra/viewer_components/updater/llupdateinstaller.h b/indra/viewer_components/updater/llupdateinstaller.h index 6ce08ce6fa..fe5b1d19b5 100644 --- a/indra/viewer_components/updater/llupdateinstaller.h +++ b/indra/viewer_components/updater/llupdateinstaller.h @@ -42,9 +42,10 @@ enum LLInstallScriptMode {  // that the current application terminate once this function is called.  //  int ll_install_update( -					   std::string const & script, // Script to execute. -					   std::string const & updatePath, // Path to update file. -					   LLInstallScriptMode mode=LL_COPY_INSTALL_SCRIPT_TO_TEMP); // Run in place or copy to temp? +					  std::string const & script, // Script to execute. +					  std::string const & updatePath, // Path to update file. +					  bool required, // Is the update required. +					  LLInstallScriptMode mode=LL_COPY_INSTALL_SCRIPT_TO_TEMP); // Run in place or copy to temp?  // diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index cc60eaead2..aa4983a3b6 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -25,10 +25,11 @@  #include "linden_common.h" +#include "llupdaterservice.h" +  #include "llupdatedownloader.h"  #include "llevents.h"  #include "lltimer.h" -#include "llupdaterservice.h"  #include "llupdatechecker.h"  #include "llupdateinstaller.h"  #include "llversionviewer.h" @@ -98,6 +99,8 @@ class LLUpdaterServiceImpl :  	LLUpdaterService::app_exit_callback_t mAppExitCallback; +	LLUpdaterService::eUpdaterState mState; +	  	LOG_CLASS(LLUpdaterServiceImpl);  public: @@ -111,12 +114,15 @@ public:  				   const std::string& version);  	void setCheckPeriod(unsigned int seconds); +	void setBandwidthLimit(U64 bytesPerSecond);  	void startChecking(bool install_if_ready);  	void stopChecking();  	bool isChecking(); +	LLUpdaterService::eUpdaterState getState();  	void setAppExitCallback(LLUpdaterService::app_exit_callback_t aecb) { mAppExitCallback = aecb;} +	std::string updatedVersion(void);  	bool checkForInstall(bool launchInstaller); // Test if a local install is ready.  	bool checkForResume(); // Test for resumeable d/l. @@ -138,7 +144,10 @@ public:  	bool onMainLoop(LLSD const & event);  private: +	std::string mNewVersion; +	  	void restartTimer(unsigned int seconds); +	void setState(LLUpdaterService::eUpdaterState state);  	void stopTimer();  }; @@ -149,7 +158,8 @@ LLUpdaterServiceImpl::LLUpdaterServiceImpl() :  	mIsDownloading(false),  	mCheckPeriod(0),  	mUpdateChecker(*this), -	mUpdateDownloader(*this) +	mUpdateDownloader(*this), +	mState(LLUpdaterService::INITIAL)  {  } @@ -183,6 +193,11 @@ void LLUpdaterServiceImpl::setCheckPeriod(unsigned int seconds)  	mCheckPeriod = seconds;  } +void LLUpdaterServiceImpl::setBandwidthLimit(U64 bytesPerSecond) +{ +	mUpdateDownloader.setBandwidthLimit(bytesPerSecond); +} +  void LLUpdaterServiceImpl::startChecking(bool install_if_ready)  {  	if(mUrl.empty() || mChannel.empty() || mVersion.empty()) @@ -201,10 +216,16 @@ void LLUpdaterServiceImpl::startChecking(bool install_if_ready)  		if(!mIsDownloading)  		{ +			setState(LLUpdaterService::CHECKING_FOR_UPDATE); +			  			// Checking can only occur during the mainloop.  			// reset the timer to 0 so that the next mainloop event   			// triggers a check;  			restartTimer(0);  +		}  +		else +		{ +			setState(LLUpdaterService::DOWNLOADING);  		}  	}  } @@ -222,6 +243,8 @@ void LLUpdaterServiceImpl::stopChecking()          mUpdateDownloader.cancel();  		mIsDownloading = false;      } +	 +	setState(LLUpdaterService::TERMINAL);  }  bool LLUpdaterServiceImpl::isChecking() @@ -229,6 +252,16 @@ bool LLUpdaterServiceImpl::isChecking()  	return mIsChecking;  } +LLUpdaterService::eUpdaterState LLUpdaterServiceImpl::getState() +{ +	return mState; +} + +std::string LLUpdaterServiceImpl::updatedVersion(void) +{ +	return mNewVersion; +} +  bool LLUpdaterServiceImpl::checkForInstall(bool launchInstaller)  {  	bool foundInstall = false; // return true if install is found. @@ -266,10 +299,13 @@ bool LLUpdaterServiceImpl::checkForInstall(bool launchInstaller)  		{  			if(launchInstaller)  			{ +				setState(LLUpdaterService::INSTALLING); +				  				LLFile::remove(update_marker_path());  				int result = ll_install_update(install_script_path(),  											   update_info["path"].asString(), +											   update_info["required"].asBoolean(),  											   install_script_mode());	  				if((result == 0) && mAppExitCallback) @@ -304,6 +340,7 @@ bool LLUpdaterServiceImpl::checkForResume()  			if(download_info["current_version"].asString() == ll_get_version())  			{  				mIsDownloading = true; +				mNewVersion = download_info["update_version"].asString();  				mUpdateDownloader.resume();  				result = true;  			} @@ -333,8 +370,11 @@ void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion,  										  std::string const & hash)  {  	stopTimer(); +	mNewVersion = newVersion;  	mIsDownloading = true; -	mUpdateDownloader.download(uri, hash); +	mUpdateDownloader.download(uri, hash, newVersion, false); +	 +	setState(LLUpdaterService::DOWNLOADING);  }  void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion, @@ -342,8 +382,11 @@ void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,  										  std::string const & hash)  {  	stopTimer(); +	mNewVersion = newVersion;  	mIsDownloading = true; -	mUpdateDownloader.download(uri, hash); +	mUpdateDownloader.download(uri, hash, newVersion, true); +	 +	setState(LLUpdaterService::DOWNLOADING);  }  void LLUpdaterServiceImpl::upToDate(void) @@ -352,6 +395,8 @@ void LLUpdaterServiceImpl::upToDate(void)  	{  		restartTimer(mCheckPeriod);  	} +	 +	setState(LLUpdaterService::UP_TO_DATE);  }  void LLUpdaterServiceImpl::downloadComplete(LLSD const & data)  @@ -367,8 +412,12 @@ void LLUpdaterServiceImpl::downloadComplete(LLSD const & data)  	event["pump"] = LLUpdaterService::pumpName();  	LLSD payload;  	payload["type"] = LLSD(LLUpdaterService::DOWNLOAD_COMPLETE); +	payload["required"] = data["required"]; +	payload["version"] = mNewVersion;  	event["payload"] = payload;  	LLEventPumps::instance().obtain("mainlooprepeater").post(event); +	 +	setState(LLUpdaterService::TERMINAL);  }  void LLUpdaterServiceImpl::downloadError(std::string const & message)  @@ -390,6 +439,8 @@ void LLUpdaterServiceImpl::downloadError(std::string const & message)  	payload["message"] = message;  	event["payload"] = payload;  	LLEventPumps::instance().obtain("mainlooprepeater").post(event); + +	setState(LLUpdaterService::FAILURE);  }  void LLUpdaterServiceImpl::restartTimer(unsigned int seconds) @@ -402,6 +453,28 @@ void LLUpdaterServiceImpl::restartTimer(unsigned int seconds)  		sListenerName, boost::bind(&LLUpdaterServiceImpl::onMainLoop, this, _1));  } +void LLUpdaterServiceImpl::setState(LLUpdaterService::eUpdaterState state) +{ +	if(state != mState) +	{ +		mState = state; +		 +		LLSD event; +		event["pump"] = LLUpdaterService::pumpName(); +		LLSD payload; +		payload["type"] = LLSD(LLUpdaterService::STATE_CHANGE); +		payload["state"] = state; +		event["payload"] = payload; +		LLEventPumps::instance().obtain("mainlooprepeater").post(event); +		 +		LL_INFOS("UpdaterService") << "setting state to " << state << LL_ENDL; +	} +	else  +	{ +		; // State unchanged; noop. +	} +} +  void LLUpdaterServiceImpl::stopTimer()  {  	mTimer.stop(); @@ -417,6 +490,12 @@ bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event)  		// Check for failed install.  		if(LLFile::isfile(ll_install_failed_marker_path()))  		{ +			int requiredValue = 0;  +			{ +				llifstream stream(ll_install_failed_marker_path()); +				stream >> requiredValue; +				if(stream.fail()) requiredValue = 0; +			}  			// TODO: notify the user.  			llinfos << "found marker " << ll_install_failed_marker_path() << llendl;  			llinfos << "last install attempt failed" << llendl; @@ -424,11 +503,15 @@ bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event)  			LLSD event;  			event["type"] = LLSD(LLUpdaterService::INSTALL_ERROR); +			event["required"] = LLSD(requiredValue);  			LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).post(event); +			 +			setState(LLUpdaterService::TERMINAL);  		}  		else  		{  			mUpdateChecker.check(mProtocolVersion, mUrl, mPath, mChannel, mVersion); +			setState(LLUpdaterService::CHECKING_FOR_UPDATE);  		}  	}   	else  @@ -449,6 +532,11 @@ std::string const & LLUpdaterService::pumpName(void)  	return name;  } +bool LLUpdaterService::updateReadyToInstall(void) +{ +	return LLFile::isfile(update_marker_path()); +} +  LLUpdaterService::LLUpdaterService()  {  	if(gUpdater.expired()) @@ -480,6 +568,11 @@ void LLUpdaterService::setCheckPeriod(unsigned int seconds)  {  	mImpl->setCheckPeriod(seconds);  } + +void LLUpdaterService::setBandwidthLimit(U64 bytesPerSecond) +{ +	mImpl->setBandwidthLimit(bytesPerSecond); +}  void LLUpdaterService::startChecking(bool install_if_ready)  { @@ -496,11 +589,21 @@ bool LLUpdaterService::isChecking()  	return mImpl->isChecking();  } +LLUpdaterService::eUpdaterState LLUpdaterService::getState() +{ +	return mImpl->getState(); +} +  void LLUpdaterService::setImplAppExitCallback(LLUpdaterService::app_exit_callback_t aecb)  {  	return mImpl->setAppExitCallback(aecb);  } +std::string LLUpdaterService::updatedVersion(void) +{ +	return mImpl->updatedVersion(); +} +  std::string const & ll_get_version(void) {  	static std::string version(""); diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 752a6f834b..421481bc43 100644 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -43,12 +43,27 @@ public:  	// Name of the event pump through which update events will be delivered.  	static std::string const & pumpName(void); +	// Returns true if an update has been completely downloaded and is now ready to install. +	static bool updateReadyToInstall(void); +	  	// Type codes for events posted by this service.  Stored the event's 'type' element. -	enum eUpdateEvent { +	enum eUpdaterEvent {  		INVALID,  		DOWNLOAD_COMPLETE,  		DOWNLOAD_ERROR, -		INSTALL_ERROR +		INSTALL_ERROR, +		PROGRESS, +		STATE_CHANGE +	}; +	 +	enum eUpdaterState { +		INITIAL, +		CHECKING_FOR_UPDATE, +		DOWNLOADING, +		INSTALLING, +		UP_TO_DATE, +		TERMINAL, +		FAILURE  	};  	LLUpdaterService(); @@ -61,10 +76,12 @@ public:  				    const std::string& version);  	void setCheckPeriod(unsigned int seconds); +	void setBandwidthLimit(U64 bytesPerSecond);  	void startChecking(bool install_if_ready = false);  	void stopChecking();  	bool isChecking(); +	eUpdaterState getState();  	typedef boost::function<void (void)> app_exit_callback_t;  	template <typename F> @@ -73,6 +90,11 @@ public:  		app_exit_callback_t aecb = callable;  		setImplAppExitCallback(aecb);  	} +	 +	// If an update is or has been downloaded, this method will return the +	// version string for that update.  An empty string will be returned +	// otherwise. +	std::string updatedVersion(void);  private:  	boost::shared_ptr<LLUpdaterServiceImpl> mImpl; diff --git a/indra/viewer_components/updater/scripts/darwin/update_install b/indra/viewer_components/updater/scripts/darwin/update_install index 9df382f119..6a95f96d86 100644 --- a/indra/viewer_components/updater/scripts/darwin/update_install +++ b/indra/viewer_components/updater/scripts/darwin/update_install @@ -6,5 +6,5 @@  #  cd "$(dirname "$0")" -../Resources/mac-updater.app/Contents/MacOS/mac-updater -dmg "$1" -name "Second Life Viewer 2" -marker "$2" & +(../Resources/mac-updater.app/Contents/MacOS/mac-updater -dmg "$1" -name "Second Life Viewer 2"; if [ $? -ne 0 ]; then echo $3 >> "$2"; fi;) &  exit 0 diff --git a/indra/viewer_components/updater/scripts/linux/update_install b/indra/viewer_components/updater/scripts/linux/update_install index a271926e25..88451340ec 100644 --- a/indra/viewer_components/updater/scripts/linux/update_install +++ b/indra/viewer_components/updater/scripts/linux/update_install @@ -4,7 +4,7 @@ export LD_LIBRARY_PATH="$INSTALL_DIR/lib"  bin/linux-updater.bin --file "$1" --dest "$INSTALL_DIR" --name "Second Life Viewer 2" --stringsdir "$INSTALL_DIR/skins/default/xui/en" --stringsfile "strings.xml"  if [ $? -ne 0 ] -   then touch "$2" +   then echo $3 >> "$2"  fi  rm -f "$1" diff --git a/indra/viewer_components/updater/scripts/windows/update_install.bat b/indra/viewer_components/updater/scripts/windows/update_install.bat index 42e148a707..96687226a8 100644 --- a/indra/viewer_components/updater/scripts/windows/update_install.bat +++ b/indra/viewer_components/updater/scripts/windows/update_install.bat @@ -1,3 +1,3 @@  start /WAIT %1 /SKIP_DIALOGS
 -IF ERRORLEVEL 1 ECHO %ERRORLEVEL% > %2
 +IF ERRORLEVEL 1 ECHO %3 > %2
  DEL %1
 diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index 04ed4e6364..5f8cd28f29 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -48,7 +48,7 @@ void LLUpdateChecker::check(std::string const & protocolVersion, std::string con  								  std::string const & servicePath, std::string channel, std::string version)
  {}
  LLUpdateDownloader::LLUpdateDownloader(Client & ) {}
 -void LLUpdateDownloader::download(LLURI const & , std::string const &){}
 +void LLUpdateDownloader::download(LLURI const & , std::string const &, std::string const &, bool){}
  class LLDir_Mock : public LLDir
  {
 @@ -101,8 +101,9 @@ std::string LLUpdateDownloader::downloadMarkerPath(void)  void LLUpdateDownloader::resume(void) {}
  void LLUpdateDownloader::cancel(void) {}
 +void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) {}
 -int ll_install_update(std::string const &, std::string const &, LLInstallScriptMode)
 +int ll_install_update(std::string const &, std::string const &, bool, LLInstallScriptMode)
  {
  	return 0;
  }
 diff --git a/install.xml b/install.xml index e043445c99..88a6a7ce90 100755 --- a/install.xml +++ b/install.xml @@ -299,16 +299,16 @@            <key>darwin</key>            <map>              <key>md5sum</key> -            <string>752e295ccb17f0dcb7c0167db3ad1e69</string> +            <string>ca8f0134fa5ab6f34a6eeb8d0896c9b0</string>              <key>url</key> -            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.20.1-darwin-20100606.tar.bz2</uri> +            <uri>https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/Darwin/installer/curl-7.21.1-darwin-20101214.tar.bz2</uri>            </map>            <key>linux</key>            <map>              <key>md5sum</key> -            <string>a20e73f2e7d6a032ff25a5161b1b7394</string> +            <string>9c9b629b62bf874d550c430ad678dc04</string>              <key>url</key> -            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.20.1-linux-20100527.tar.bz2</uri> +            <uri>https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/Linux/installer/curl-7.21.1-linux-20101215.tar.bz2</uri>            </map>            <key>linux64</key>            <map> @@ -903,23 +903,23 @@            <key>darwin</key>            <map>              <key>md5sum</key> -            <string>ae18dd120807a46ac961b881a631ad94</string> +            <string>8261994de5af6581e08c26fefe1b2810</string>              <key>url</key> -            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/indra_private-2.1.1-darwin-20100820.tar.bz2</uri> +            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-darwin-20101123.tar.bz2</uri>            </map>            <key>linux</key>            <map>              <key>md5sum</key> -            <string>b1f15bbabb68445e55ce23a2aeaca598</string> +            <string>ed3e58899a424684dad49c94ba3813e7</string>              <key>url</key> -            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/indra_private-2.1.1-linux-20100826.tar.bz2</uri> +            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-linux-20101124.tar.bz2</uri>            </map>            <key>windows</key>            <map>              <key>md5sum</key> -            <string>0e2fe621ce99085eba00d86d9a3bc130</string> +            <string>066e089a5d9faeaf131e1f4e4860a163</string>              <key>url</key> -            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/indra_private-2.1.1-windows-20100820.tar.bz2</uri> +            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-windows-20101123.tar.bz2</uri>            </map>          </map>        </map> @@ -1120,9 +1120,9 @@ anguage Infrstructure (CLI) international standard</string>            <key>darwin</key>            <map>              <key>md5sum</key> -            <string>34d9e4c93678a422cf80521bf0cd7628</string> +            <string>66c46841825ab4969ec875b5c8f9b24c</string>              <key>url</key> -            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-4.6-darwin-20100914.tar.bz2</uri> +            <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-darwin-qt4.7.1-20101221.tar.bz2</uri>            </map>            <key>linux</key>            <map> @@ -1134,9 +1134,9 @@ anguage Infrstructure (CLI) international standard</string>            <key>windows</key>            <map>              <key>md5sum</key> -            <string>4b8412833c00f8cdaba26808f0ddb404</string> +            <string>b678c4d18ea8e4fab42b20f8d0b2629a</string>              <key>url</key> -            <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-windows-qt4.6-20100916.tar.bz2</uri> +            <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-windows-qt4.7.1-20101221.tar.bz2</uri>            </map>          </map>        </map> diff --git a/scripts/install.py b/scripts/install.py index c2adf4d0a2..d3bdf52283 100755 --- a/scripts/install.py +++ b/scripts/install.py @@ -486,7 +486,7 @@ windows/i686/vs/2003 -- specify a windows visual studio 2003 package"""          for filename in remove_file_list:              print "rm",filename              if not self._dryrun: -                if os.path.exists(filename): +                if os.path.lexists(filename):                      remove_dir_set.add(os.path.dirname(filename))                      try:                          os.remove(filename)  | 
