Compare commits
162 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e19372adf | ||
|
|
b911e86b02 | ||
|
|
c6ce417fac | ||
|
|
a7510d3b3a | ||
|
|
aad10c9b8d | ||
|
|
ca96e00135 | ||
|
|
536189340d | ||
|
|
23b97efb69 | ||
|
|
2c8e3bb0a3 | ||
|
|
7a48cb9979 | ||
|
|
2f5caa27fd | ||
|
|
d69f00741f | ||
|
|
8c4a52e58d | ||
|
|
fd22d80dfd | ||
|
|
e071dc52fd | ||
|
|
e1cbeb7e02 | ||
|
|
9d367cf9f2 | ||
|
|
3890e61fbc | ||
|
|
3df853b74b | ||
|
|
10bc483305 | ||
|
|
f55fa45b73 | ||
|
|
acb24dd3e1 | ||
|
|
4b87c45298 | ||
|
|
a2fb56bf48 | ||
|
|
37095dc2cd | ||
|
|
a57ac5a954 | ||
|
|
29045609a3 | ||
|
|
b4dad425aa | ||
|
|
c73414f1a1 | ||
|
|
6920bee5e2 | ||
|
|
6a5e203884 | ||
|
|
6b1f44ed6d | ||
|
|
ab8cd3e5d5 | ||
|
|
78f7cc0d64 | ||
|
|
b607650d5c | ||
|
|
1bfa72fa7c | ||
|
|
0030ca3af7 | ||
|
|
a53e08032f | ||
|
|
62febda165 | ||
|
|
a726de0e99 | ||
|
|
918d527b14 | ||
|
|
5919c9a788 | ||
|
|
14f2248ea1 | ||
|
|
81499fc6ea | ||
|
|
ffb285c6ff | ||
|
|
e08e8cf131 | ||
|
|
40b4b47023 | ||
|
|
2565caf62a | ||
|
|
d63df79b85 | ||
|
|
697dd7e929 | ||
|
|
f613be9276 | ||
|
|
f5a08b1c12 | ||
|
|
f40bbb1602 | ||
|
|
aeb766ee37 | ||
|
|
cd67046b33 | ||
|
|
66f4c170cb | ||
|
|
a485760028 | ||
|
|
0b5a2cd6a3 | ||
|
|
8e7733b2ce | ||
|
|
08d2c17c65 | ||
|
|
09f7136cf4 | ||
|
|
c4b77e247e | ||
|
|
9f9daba33d | ||
|
|
dc3831c86b | ||
|
|
ab14f1908c | ||
|
|
bf6e1d6c75 | ||
|
|
5d8d402403 | ||
|
|
b8eb3076ce | ||
|
|
d16e48e128 | ||
|
|
e46c906a8b | ||
|
|
83e8a9076b | ||
|
|
56b28756ad | ||
|
|
13fad75811 | ||
|
|
1cf367aae5 | ||
|
|
70909f86c8 | ||
|
|
1fd908b2c4 | ||
|
|
f0108c17b9 | ||
|
|
0566bde61b | ||
|
|
a31fc8a612 | ||
|
|
2ba9e16a6c | ||
|
|
e6dce6ad7b | ||
|
|
c87caebcf7 | ||
|
|
121a557fe5 | ||
|
|
6aa7f219cd | ||
|
|
e9e05bec90 | ||
|
|
8421661a89 | ||
|
|
7fea7c589d | ||
|
|
0e3b735a60 | ||
|
|
236f5757a2 | ||
|
|
0a44e3ee09 | ||
|
|
ee5a9c97be | ||
|
|
2126654979 | ||
|
|
df40a8c5cf | ||
|
|
34fb647903 | ||
|
|
5de4f1e2da | ||
|
|
18dd31f51a | ||
|
|
40689f7d1e | ||
|
|
4ce0345842 | ||
|
|
844e38702a | ||
|
|
5f074c8c82 | ||
|
|
5c2b1d396b | ||
|
|
b0b7837c4d | ||
|
|
7789c5a703 | ||
|
|
b64cb8d339 | ||
|
|
3891928092 | ||
|
|
f5983208eb | ||
|
|
0ef5931212 | ||
|
|
6381e4d9a4 | ||
|
|
6964cec6f1 | ||
|
|
d9f674218f | ||
|
|
693e3a0555 | ||
|
|
8376e890b2 | ||
|
|
33827bf8b0 | ||
|
|
a35ef93d19 | ||
|
|
e5f75d1e48 | ||
|
|
231af66b90 | ||
|
|
f386fc75df | ||
|
|
06349951d2 | ||
|
|
cc45a24aff | ||
|
|
e06d0b2e70 | ||
|
|
0281ac4afe | ||
|
|
7227c01d79 | ||
|
|
c5abde1616 | ||
|
|
c2a4951f20 | ||
|
|
4d68dc7c57 | ||
|
|
722e7d09ff | ||
|
|
0fde15246b | ||
|
|
b3423de80a | ||
|
|
743449e635 | ||
|
|
405182025d | ||
|
|
bd6d14d741 | ||
|
|
0e190cadcd | ||
|
|
408f5a4a51 | ||
|
|
53f5957b92 | ||
|
|
fb32a0be5a | ||
|
|
474e1ec7cc | ||
|
|
1e9d09b82e | ||
|
|
c3b1bf4b76 | ||
|
|
e2d9c31f5e | ||
|
|
7b81e9d248 | ||
|
|
6e6c438e2a | ||
|
|
4606c7512e | ||
|
|
88e373c960 | ||
|
|
f2deb39dac | ||
|
|
8a5793ce23 | ||
|
|
a36c5f2ee6 | ||
|
|
c63bf31328 | ||
|
|
5d811163a6 | ||
|
|
78a98cbf08 | ||
|
|
91348909b5 | ||
|
|
73f2543a6f | ||
|
|
d80458b726 | ||
|
|
22385c44c8 | ||
|
|
40261d3472 | ||
|
|
06ff562cd2 | ||
|
|
e7b023778a | ||
|
|
2e4419a295 | ||
|
|
bdc95a1544 | ||
|
|
ff786ad2c7 | ||
|
|
c95696e8a0 | ||
|
|
4dbed63f0b | ||
|
|
cdebc1c5cc |
@@ -1,4 +0,0 @@
|
||||
This is a modified version of openal-soft from GIT (56cc03860378e2758370b773b2a6f1b4e086b49a).
|
||||
The modified source which this was built from is available here:
|
||||
http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/openal-soft-linden-56cc03860378e2758370b773b2a6f1b4e086b49a.tar.bz2
|
||||
|
||||
@@ -113,7 +113,7 @@ if (WINDOWS)
|
||||
|
||||
endif (WINDOWS)
|
||||
|
||||
set (GCC_EXTRA_OPTIMIZATION "-ffast-math -frounding-math")
|
||||
set (GCC_EXTRA_OPTIMIZATIONS "-ffast-math -frounding-math")
|
||||
|
||||
if (LINUX)
|
||||
set(CMAKE_SKIP_RPATH TRUE)
|
||||
@@ -182,53 +182,29 @@ if (LINUX)
|
||||
-pthread
|
||||
)
|
||||
|
||||
if (SERVER)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-60")
|
||||
if (EXISTS /etc/debian_version)
|
||||
FILE(READ /etc/debian_version DEBIAN_VERSION)
|
||||
else (EXISTS /etc/debian_version)
|
||||
set(DEBIAN_VERSION "")
|
||||
endif (EXISTS /etc/debian_version)
|
||||
|
||||
if (NOT DEBIAN_VERSION STREQUAL "3.1")
|
||||
add_definitions(-DCTYPE_WORKAROUND)
|
||||
endif (NOT DEBIAN_VERSION STREQUAL "3.1")
|
||||
|
||||
if (EXISTS /usr/lib/mysql4/mysql)
|
||||
link_directories(/usr/lib/mysql4/mysql)
|
||||
endif (EXISTS /usr/lib/mysql4/mysql)
|
||||
|
||||
add_definitions(
|
||||
-msse2
|
||||
-mfpmath=sse
|
||||
)
|
||||
endif (SERVER)
|
||||
|
||||
if (VIEWER)
|
||||
add_definitions(-DAPPID=secondlife)
|
||||
add_definitions(-fvisibility=hidden)
|
||||
# don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The viewer doesn't need to catch SIGCHLD anyway.
|
||||
add_definitions(-DLL_IGNORE_SIGCHLD)
|
||||
add_definitions(-DAPPID=secondlife)
|
||||
add_definitions(-fvisibility=hidden)
|
||||
# don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The viewer doesn't need to catch SIGCHLD anyway.
|
||||
add_definitions(-DLL_IGNORE_SIGCHLD)
|
||||
if (NOT STANDALONE)
|
||||
# this stops us requiring a really recent glibc at runtime
|
||||
add_definitions(-fno-stack-protector)
|
||||
endif (NOT STANDALONE)
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
add_definitions(-DLINUX64=1 -pipe)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
else (${ARCH} STREQUAL "x86_64")
|
||||
if (NOT STANDALONE)
|
||||
# this stops us requiring a really recent glibc at runtime
|
||||
add_definitions(-fno-stack-protector)
|
||||
set(MARCH_FLAG " -march=pentium4")
|
||||
endif (NOT STANDALONE)
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
add_definitions(-DLINUX64=1 -pipe)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
else (${ARCH} STREQUAL "x86_64")
|
||||
if (NOT STANDALONE)
|
||||
set(MARCH_FLAG " -march=pentium4")
|
||||
endif (NOT STANDALONE)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
endif (${ARCH} STREQUAL "x86_64")
|
||||
endif (VIEWER)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
endif (${ARCH} STREQUAL "x86_64")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG} -msse2")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
@@ -258,13 +234,13 @@ endif (DARWIN)
|
||||
|
||||
|
||||
if (LINUX OR DARWIN)
|
||||
set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor -Woverloaded-virtual")
|
||||
set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs")
|
||||
|
||||
if (NOT GCC_DISABLE_FATAL_WARNINGS)
|
||||
set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
|
||||
endif (NOT GCC_DISABLE_FATAL_WARNINGS)
|
||||
|
||||
set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder")
|
||||
set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
|
||||
|
||||
set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}")
|
||||
@@ -298,10 +274,6 @@ if(1 EQUAL 1)
|
||||
add_definitions(-DMESH_ENABLED=1)
|
||||
endif(1 EQUAL 1)
|
||||
|
||||
if(SERVER)
|
||||
include_directories(${LIBS_PREBUILT_DIR}/include/havok)
|
||||
endif(SERVER)
|
||||
|
||||
SET( CMAKE_EXE_LINKER_FLAGS_RELEASESSE2
|
||||
"${CMAKE_EXE_LINKER_FLAGS_RELEASE}" CACHE STRING
|
||||
"Flags used for linking binaries under SSE2 build."
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -35,7 +35,7 @@ set(cmake_SOURCE_FILES
|
||||
FindNDOF.cmake
|
||||
FindOpenJPEG.cmake
|
||||
FindXmlRpcEpi.cmake
|
||||
FMOD.cmake
|
||||
FMOD.cmake
|
||||
FreeType.cmake
|
||||
GStreamer010Plugin.cmake
|
||||
GooglePerfTools.cmake
|
||||
@@ -84,6 +84,10 @@ set(cmake_SOURCE_FILES
|
||||
ZLIB.cmake
|
||||
)
|
||||
|
||||
if(FMODEX)
|
||||
list(APPEND cmake_SOURCE_FILES FMODEX.cmake)
|
||||
endif(FMODEX)
|
||||
|
||||
source_group("Shared Rules" FILES ${cmake_SOURCE_FILES})
|
||||
|
||||
set(master_SOURCE_FILES
|
||||
|
||||
@@ -243,12 +243,51 @@ set(all_targets ${all_targets} ${out_targets})
|
||||
set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
||||
set(release_files
|
||||
libtcmalloc_minimal.dll
|
||||
fmod.dll
|
||||
libhunspell.dll
|
||||
libapr-1.dll
|
||||
libaprutil-1.dll
|
||||
libapriconv-1.dll
|
||||
)
|
||||
|
||||
if(FMODEX)
|
||||
find_path(FMODEX_BINARY_DIR fmodex.dll
|
||||
${release_src_dir}
|
||||
${FMODEX_SDK_DIR}/api
|
||||
${FMODEX_SDK_DIR}
|
||||
)
|
||||
|
||||
if(FMODEX_BINARY_DIR)
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/ReleaseSSE2" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
endif(FMODEX_BINARY_DIR)
|
||||
endif(FMODEX)
|
||||
|
||||
if(FMOD)
|
||||
find_path(FMOD_BINARY_DIR fmod.dll
|
||||
${release_src_dir}
|
||||
${FMOD_SDK_DIR}/api
|
||||
${FMOD_SDK_DIR}
|
||||
)
|
||||
|
||||
if(FMOD_BINARY_DIR)
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/ReleaseSSE2" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
else(FMOD_BINARY_DIR)
|
||||
list(APPEND release_files fmod.dll) #Required for compile. This will cause an error in copying binaries.
|
||||
endif(FMOD_BINARY_DIR)
|
||||
endif(FMOD)
|
||||
|
||||
copy_if_different(
|
||||
${release_src_dir}
|
||||
|
||||
@@ -6,6 +6,7 @@ set(install_dir "@CMAKE_SOURCE_DIR@/..")
|
||||
set(scp "@SCP_EXECUTABLE@")
|
||||
set(scripts_dir "@SCRIPTS_DIR@")
|
||||
set(sentinel_dir "@CMAKE_BINARY_DIR@/prepare")
|
||||
set(prebuilt_type "@PREBUILT_TYPE@")
|
||||
|
||||
# In proprietary mode we use scp for download.
|
||||
set(proprietary "@INSTALL_PROPRIETARY@")
|
||||
@@ -19,7 +20,7 @@ foreach(package ${packages})
|
||||
# This package is missing or out of date.
|
||||
message(STATUS "Obtaining${proprietary_message} prebuilt '${package}'")
|
||||
execute_process(
|
||||
COMMAND ${python} install.py --install-dir=${install_dir} ${scp_option} ${package}
|
||||
COMMAND ${python} install.py -p${prebuilt_type} --install-dir=${install_dir} ${scp_option} ${package}
|
||||
WORKING_DIRECTORY ${scripts_dir}
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
|
||||
83
indra/cmake/FMODEX.cmake
Normal file
83
indra/cmake/FMODEX.cmake
Normal file
@@ -0,0 +1,83 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
include(Linking)
|
||||
|
||||
if(INSTALL_PROPRIETARY)
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(fmodex)
|
||||
endif(INSTALL_PROPRIETARY)
|
||||
|
||||
find_library(FMODEX_LIBRARY_RELEASE
|
||||
NAMES fmodex fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${ARCH_PREBUILT_DIRS_RELEASE}
|
||||
)
|
||||
|
||||
find_library(FMODEX_LIBRARY_DEBUG
|
||||
NAMES fmodex fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${ARCH_PREBUILT_DIRS_DEBUG}
|
||||
)
|
||||
|
||||
if (FMODEX_LIBRARY_RELEASE AND FMODEX_LIBRARY_DEBUG)
|
||||
set(FMODEX_LIBRARY
|
||||
debug ${FMODEX_LIBRARY_DEBUG}
|
||||
optimized ${FMODEX_LIBRARY_RELEASE})
|
||||
elseif (FMODEX_LIBRARY_RELEASE)
|
||||
set(FMODEX_LIBRARY ${FMODEX_LIBRARY_RELEASE})
|
||||
endif (FMODEX_LIBRARY_RELEASE AND FMODEX_LIBRARY_DEBUG)
|
||||
|
||||
if (NOT FMODEX_LIBRARY)
|
||||
set(FMODEX_SDK_DIR CACHE PATH "Path to the FMOD Ex SDK.")
|
||||
if (FMODEX_SDK_DIR)
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${FMODEX_SDK_DIR}/api/lib
|
||||
${FMODEX_SDK_DIR}/api
|
||||
${FMODEX_SDK_DIR}/lib
|
||||
${FMODEX_SDK_DIR}
|
||||
)
|
||||
|
||||
|
||||
endif(FMODEX_SDK_DIR)
|
||||
if(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||
set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows")
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${FMODEX_PROG_DIR}/api/lib
|
||||
${FMODEX_PROG_DIR}/api
|
||||
${FMODEX_PROG_DIR}
|
||||
)
|
||||
if(FMODEX_LIBRARY)
|
||||
message(STATUS "Found fmodex in ${FMODEX_PROG_DIR}")
|
||||
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR})
|
||||
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR} CACHE PATH "Path to the FMOD Ex SDK." FORCE)
|
||||
endif(FMODEX_LIBRARY)
|
||||
endif(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||
endif (NOT FMODEX_LIBRARY)
|
||||
|
||||
find_path(FMODEX_INCLUDE_DIR fmod.h
|
||||
${LIBS_PREBUILT_DIR}/include/fmodex
|
||||
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/fmodex
|
||||
${FMODEX_SDK_DIR}/api/inc
|
||||
${FMODEX_SDK_DIR}/inc
|
||||
${FMODEX_SDK_DIR}
|
||||
)
|
||||
|
||||
if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
set(FMODEX ON CACHE BOOL "Use closed source FMOD Ex sound library.")
|
||||
else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
set(FMODEX_LIBRARY "")
|
||||
set(FMODEX_INCLUDE_DIR "")
|
||||
if (FMODEX)
|
||||
message(STATUS "No support for FMOD Ex audio (need to set FMODEX_SDK_DIR?)")
|
||||
endif (FMODEX)
|
||||
set(FMODEX OFF CACHE BOOL "Use closed source FMOD Ex sound library.")
|
||||
set(FMODEX OFF)
|
||||
endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
|
||||
if (FMODEX)
|
||||
message(STATUS "Building with FMOD Ex audio support")
|
||||
endif (FMODEX)
|
||||
@@ -18,7 +18,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)
|
||||
|
||||
set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
|
||||
if(LLCOMMON_LINK_SHARED)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
if (NOT STANDALONE)
|
||||
if (NOT (STANDALONE OR DARWIN))
|
||||
use_prebuilt_binary(glext)
|
||||
# possible glh_linear should have its own .cmake file instead
|
||||
#use_prebuilt_binary(glh_linear)
|
||||
# actually... not any longer, it's now in git -SG
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||
endif (NOT STANDALONE)
|
||||
endif ()
|
||||
|
||||
@@ -76,24 +76,16 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(DARWIN 1)
|
||||
|
||||
# NOTE: If specifying a different SDK with CMAKE_OSX_SYSROOT at configure
|
||||
# time you should also specify CMAKE_OSX_DEPLOYMENT_TARGET explicitly,
|
||||
# otherwise CMAKE_OSX_SYSROOT will be overridden here. We can't just check
|
||||
# for it being unset, as it gets set to the system default :(
|
||||
|
||||
# Default to building against the 10.5 SDK if no deployment target is
|
||||
# specified.
|
||||
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
# NOTE: setting -isysroot is NOT adequate: http://lists.apple.com/archives/Xcode-users/2007/Oct/msg00696.html
|
||||
# see http://public.kitware.com/Bug/view.php?id=9959 + poppy
|
||||
#SDK Compiler and Deployment targets for XCode
|
||||
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
|
||||
endif (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
set(CMAKE_XCODE_ATTIBUTE_GCC_VERSION "4.2")
|
||||
else (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
|
||||
endif (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
|
||||
# Use GCC 4.2
|
||||
if (${CMAKE_OSX_SYSROOT} MATCHES "10.5")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.2")
|
||||
endif (${CMAKE_OSX_SYSROOT} MATCHES "10.5")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
|
||||
|
||||
# NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
|
||||
# -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
|
||||
@@ -118,6 +110,17 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
|
||||
|
||||
if (WINDOWS)
|
||||
set(PREBUILT_TYPE windows)
|
||||
elseif(DARWIN)
|
||||
set(PREBUILT_TYPE darwin)
|
||||
elseif(LINUX AND WORD_SIZE EQUAL 32)
|
||||
set(PREBUILT_TYPE linux)
|
||||
elseif(LINUX AND WORD_SIZE EQUAL 64)
|
||||
set(PREBUILT_TYPE linux64)
|
||||
endif(WINDOWS)
|
||||
|
||||
|
||||
# Default deploy grid
|
||||
set(GRID agni CACHE STRING "Target Grid")
|
||||
|
||||
|
||||
@@ -1,105 +1,84 @@
|
||||
# Main CMakeLists.txt to build the OpenJPEG project using CMake (www.cmake.org)
|
||||
# Written by Mathieu Malaterre
|
||||
# -*- cmake -*-
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
project(openjpeg)
|
||||
|
||||
IF(COMMAND CMAKE_POLICY)
|
||||
CMAKE_POLICY(SET CMP0003 NEW)
|
||||
ENDIF(COMMAND CMAKE_POLICY)
|
||||
include(00-Common)
|
||||
|
||||
PROJECT(openjpeg)
|
||||
|
||||
# Do full dependency headers.
|
||||
INCLUDE_REGULAR_EXPRESSION("^.*$")
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# OPENJPEG version number, useful for packaging and doxygen doc:
|
||||
SET(OPENJPEG_VERSION_MAJOR 1)
|
||||
SET(OPENJPEG_VERSION_MINOR 4)
|
||||
SET(OPENJPEG_VERSION_BUILD 0)
|
||||
SET(OPENJPEG_VERSION
|
||||
set(OPENJPEG_VERSION_MAJOR 1)
|
||||
set(OPENJPEG_VERSION_MINOR 4)
|
||||
set(OPENJPEG_VERSION_BUILD 0)
|
||||
set(OPENJPEG_VERSION
|
||||
"${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}")
|
||||
|
||||
set(openjpeg_SOURCE_FILES
|
||||
bio.c
|
||||
cio.c
|
||||
dwt.c
|
||||
event.c
|
||||
image.c
|
||||
j2k.c
|
||||
j2k_lib.c
|
||||
jp2.c
|
||||
jpt.c
|
||||
mct.c
|
||||
mqc.c
|
||||
openjpeg.c
|
||||
pi.c
|
||||
raw.c
|
||||
t1.c
|
||||
t2.c
|
||||
tcd.c
|
||||
tgt.c
|
||||
)
|
||||
|
||||
set(openjpeg_HEADER_FILES
|
||||
bio.h
|
||||
cio.h
|
||||
dwt.h
|
||||
event.h
|
||||
fix.h
|
||||
image.h
|
||||
int.h
|
||||
j2k.h
|
||||
j2k_lib.h
|
||||
jp2.h
|
||||
jpt.h
|
||||
mct.h
|
||||
mqc.h
|
||||
openjpeg.h
|
||||
opj_includes.h
|
||||
opj_malloc.h
|
||||
pi.h
|
||||
raw.h
|
||||
t1.h
|
||||
t1_luts.h
|
||||
t2.h
|
||||
tcd.h
|
||||
tgt.h
|
||||
)
|
||||
|
||||
IF(WINDOWS)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-DOPJ_STATIC)
|
||||
ENDIF(WINDOWS)
|
||||
|
||||
|
||||
set_source_files_properties(${openjpeg_HEADER_FILES}
|
||||
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
list(APPEND openjpeg_SOURCE_FILES ${openjpeg_HEADER_FILES})
|
||||
|
||||
add_library (openjpeg ${openjpeg_SOURCE_FILES})
|
||||
|
||||
# This setting of SOVERSION assumes that any API change
|
||||
# will increment either the minor or major version number of openjpeg
|
||||
SET(OPENJPEG_LIBRARY_PROPERTIES
|
||||
set(OPENJPEG_LIBRARY_PROPERTIES
|
||||
VERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}"
|
||||
SOVERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}"
|
||||
)
|
||||
|
||||
# On Visual Studio 8 MS deprecated C. This removes all 1.276E1265 security
|
||||
# warnings
|
||||
IF(WIN32)
|
||||
IF(NOT BORLAND)
|
||||
IF(NOT CYGWIN)
|
||||
IF(NOT MINGW)
|
||||
IF(NOT ITK_ENABLE_VISUAL_STUDIO_DEPRECATED_C_WARNINGS)
|
||||
ADD_DEFINITIONS(
|
||||
-D_CRT_FAR_MAPPINGS_NO_DEPRECATE
|
||||
-D_CRT_IS_WCTYPE_NO_DEPRECATE
|
||||
-D_CRT_MANAGED_FP_NO_DEPRECATE
|
||||
-D_CRT_NONSTDC_NO_DEPRECATE
|
||||
-D_CRT_SECURE_NO_DEPRECATE
|
||||
-D_CRT_SECURE_NO_DEPRECATE_GLOBALS
|
||||
-D_CRT_SETERRORMODE_BEEP_SLEEP_NO_DEPRECATE
|
||||
-D_CRT_TIME_FUNCTIONS_NO_DEPRECATE
|
||||
-D_CRT_VCCLRIT_NO_DEPRECATE
|
||||
-D_SCL_SECURE_NO_DEPRECATE
|
||||
)
|
||||
ENDIF(NOT ITK_ENABLE_VISUAL_STUDIO_DEPRECATED_C_WARNINGS)
|
||||
ENDIF(NOT MINGW)
|
||||
ENDIF(NOT CYGWIN)
|
||||
ENDIF(NOT BORLAND)
|
||||
ENDIF(WIN32)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Test for some required system information.
|
||||
# INCLUDE (${CMAKE_ROOT}/Modules/CMakeBackwardCompatibilityC.cmake)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Compiler specific flags:
|
||||
IF(CMAKE_COMPILER_IS_GNUCC)
|
||||
# For all builds, make sure openjpeg is std99 compliant:
|
||||
# SET(CMAKE_C_FLAGS "-Wall -std=c99 ${CMAKE_C_FLAGS}") # FIXME: this setting prevented us from setting a coverage build.
|
||||
# Do not use ffast-math for all build, it would produce incorrect results, only set for release:
|
||||
SET(CMAKE_C_FLAGS_RELEASE "-ffast-math ${CMAKE_C_FLAGS_RELEASE}")
|
||||
ENDIF(CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
# Defines the source code for the library
|
||||
SET(OPENJPEG_SRCS
|
||||
bio.c
|
||||
cio.c
|
||||
dwt.c
|
||||
event.c
|
||||
image.c
|
||||
j2k.c
|
||||
j2k_lib.c
|
||||
jp2.c
|
||||
jpt.c
|
||||
mct.c
|
||||
mqc.c
|
||||
openjpeg.c
|
||||
pi.c
|
||||
raw.c
|
||||
t1.c
|
||||
t2.c
|
||||
tcd.c
|
||||
tgt.c
|
||||
)
|
||||
|
||||
# Pass proper definition to preprocessor to generate shared lib
|
||||
IF(WIN32)
|
||||
IF(BUILD_SHARED_LIBS)
|
||||
ADD_DEFINITIONS(-DOPJ_EXPORTS)
|
||||
ELSE(BUILD_SHARED_LIBS)
|
||||
ADD_DEFINITIONS(-DOPJ_STATIC)
|
||||
ENDIF(BUILD_SHARED_LIBS)
|
||||
ENDIF(WIN32)
|
||||
|
||||
# Create the library
|
||||
ADD_LIBRARY(openjpeg ${OPENJPEG_SRCS})
|
||||
SET_TARGET_PROPERTIES(openjpeg PROPERTIES
|
||||
set_target_properties(openjpeg PROPERTIES
|
||||
${OPENJPEG_LIBRARY_PROPERTIES})
|
||||
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1
|
||||
|
||||
int w = tilec->x1 - tilec->x0;
|
||||
|
||||
h.mem = opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int));
|
||||
h.mem = (int *)opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int));
|
||||
v.mem = h.mem;
|
||||
|
||||
while( --numres) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
|
||||
* Copyright (c) 2005, Hervé Drolon, FreeImage Team
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,41 +26,6 @@
|
||||
|
||||
#include "opj_includes.h"
|
||||
|
||||
/* ==========================================================
|
||||
Utility functions
|
||||
==========================================================*/
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
||||
static char*
|
||||
i2a(unsigned i, char *a, unsigned r) {
|
||||
if (i/r > 0) a = i2a(i/r,a,r);
|
||||
*a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r];
|
||||
return a+1;
|
||||
}
|
||||
|
||||
/**
|
||||
Transforms integer i into an ascii string and stores the result in a;
|
||||
string is encoded in the base indicated by r.
|
||||
@param i Number to be converted
|
||||
@param a String result
|
||||
@param r Base of value; must be in the range 2 - 36
|
||||
@return Returns a
|
||||
*/
|
||||
static char *
|
||||
_itoa(int i, char *a, int r) {
|
||||
r = ((r < 2) || (r > 36)) ? 10 : r;
|
||||
if(i < 0) {
|
||||
*a = '-';
|
||||
*i2a(-i, a+1, r) = 0;
|
||||
}
|
||||
else *i2a(i, a, r) = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
#endif /* !WIN32 */
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context) {
|
||||
if(cinfo) {
|
||||
opj_event_mgr_t *previous = cinfo->event_mgr;
|
||||
|
||||
@@ -236,7 +236,7 @@ static void j2k_read_unk(opj_j2k_t *j2k);
|
||||
/* ----------------------------------------------------------------------- */
|
||||
typedef struct j2k_prog_order{
|
||||
OPJ_PROG_ORDER enum_prog;
|
||||
char str_prog[4];
|
||||
char str_prog[5];
|
||||
}j2k_prog_order_t;
|
||||
|
||||
j2k_prog_order_t j2k_prog_order_list[] = {
|
||||
|
||||
@@ -38,7 +38,7 @@ list(APPEND linux_crash_logger_SOURCE_FILES
|
||||
${linux_crash_logger_HEADER_FILES}
|
||||
)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lrt -lapr-1 -Wl,--as-needed")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
|
||||
|
||||
add_executable(linux-crash-logger ${linux_crash_logger_SOURCE_FILES})
|
||||
|
||||
@@ -47,11 +47,18 @@ target_link_libraries(linux-crash-logger
|
||||
${LLVFS_LIBRARIES}
|
||||
${LLXML_LIBRARIES}
|
||||
${LLMESSAGE_LIBRARIES}
|
||||
${LLUI_LIBRARIES}
|
||||
${LLVFS_LIBRARIES}
|
||||
${LLMATH_LIBRARIES}
|
||||
${LLCOMMON_LIBRARIES}
|
||||
${UI_LIBRARIES}
|
||||
${DB_LIBRARIES}
|
||||
${XMLRPCEPI_LIBRARIES}
|
||||
${CURL_LIBRARIES}
|
||||
${APR_LIBRARIES}
|
||||
${APRUTIL_LIBRARIES}
|
||||
${CRYPTO_LIBRARIES}
|
||||
rt
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
|
||||
@@ -5,16 +5,30 @@ project(llaudio)
|
||||
include(00-Common)
|
||||
include(Audio)
|
||||
include(LLAudio)
|
||||
include(FMOD)
|
||||
if(FMODEX)
|
||||
include(FMODEX)
|
||||
if(FMODEX)
|
||||
set(FMOD OFF)
|
||||
endif(FMODEX)
|
||||
endif(FMODEX)
|
||||
if(NOT FMODEX)
|
||||
include(FMOD)
|
||||
endif(NOT FMODEX)
|
||||
include(OPENAL)
|
||||
include(LLCommon)
|
||||
include(LLMath)
|
||||
include(LLMessage)
|
||||
include(LLVFS)
|
||||
|
||||
if(FMODEX)
|
||||
include_directories(${FMODEX_INCLUDE_DIR})
|
||||
endif(FMODEX)
|
||||
if(FMOD)
|
||||
include_directories(${FMOD_INCLUDE_DIR})
|
||||
endif(FMOD)
|
||||
|
||||
include_directories(
|
||||
${LLAUDIO_INCLUDE_DIRS}
|
||||
${FMOD_INCLUDE_DIR}
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLMESSAGE_INCLUDE_DIRS}
|
||||
@@ -46,6 +60,19 @@ set(llaudio_HEADER_FILES
|
||||
llwindgen.h
|
||||
)
|
||||
|
||||
if (FMODEX)
|
||||
list(APPEND llaudio_SOURCE_FILES
|
||||
llaudioengine_fmodex.cpp
|
||||
lllistener_fmodex.cpp
|
||||
llstreamingaudio_fmodex.cpp
|
||||
)
|
||||
|
||||
list(APPEND llaudio_HEADER_FILES
|
||||
llaudioengine_fmodex.h
|
||||
lllistener_fmodex.h
|
||||
llstreamingaudio_fmodex.h
|
||||
)
|
||||
endif (FMODEX)
|
||||
if (FMOD)
|
||||
list(APPEND llaudio_SOURCE_FILES
|
||||
llaudioengine_fmod.cpp
|
||||
|
||||
782
indra/llaudio/llaudioengine_fmodex.cpp
Normal file
782
indra/llaudio/llaudioengine_fmodex.cpp
Normal file
@@ -0,0 +1,782 @@
|
||||
/**
|
||||
* @file audioengine_FMODEX.cpp
|
||||
* @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
#include "llstreamingaudio_fmodex.h"
|
||||
|
||||
#include "llaudioengine_fmodex.h"
|
||||
#include "lllistener_fmodex.h"
|
||||
|
||||
#include "llerror.h"
|
||||
#include "llmath.h"
|
||||
#include "llrand.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_errors.h"
|
||||
#include "lldir.h"
|
||||
#include "llapr.h"
|
||||
|
||||
#include "sound_ids.h"
|
||||
|
||||
#if LL_WINDOWS //Some ugly code to make missing fmodex.dll not cause a fatal error.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "windows.h"
|
||||
#include <DelayImp.h>
|
||||
#pragma comment(lib, "delayimp.lib")
|
||||
|
||||
bool attemptDelayLoad()
|
||||
{
|
||||
__try
|
||||
{
|
||||
if( FAILED( __HrLoadAllImportsForDll( "fmodex.dll" ) ) )
|
||||
return false;
|
||||
}
|
||||
__except( EXCEPTION_EXECUTE_HANDLER )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
|
||||
LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler)
|
||||
{
|
||||
mInited = false;
|
||||
mWindGen = NULL;
|
||||
mWindDSP = NULL;
|
||||
mSystem = NULL;
|
||||
mEnableProfiler = enable_profiler;
|
||||
}
|
||||
|
||||
|
||||
LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
||||
{
|
||||
if(result == FMOD_OK)
|
||||
return false;
|
||||
llwarns << string << " Error: " << FMOD_ErrorString(result) << llendl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
|
||||
{
|
||||
|
||||
#if LL_WINDOWS
|
||||
if(!attemptDelayLoad())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
U32 version;
|
||||
FMOD_RESULT result;
|
||||
int numdrivers;
|
||||
FMOD_SPEAKERMODE speakermode;
|
||||
FMOD_CAPS caps;
|
||||
char name[256];
|
||||
|
||||
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL;
|
||||
|
||||
result = FMOD::System_Create(&mSystem);
|
||||
if(Check_FMOD_Error(result, "FMOD::System_Create"))
|
||||
return false;
|
||||
|
||||
//will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer.
|
||||
LLAudioEngine::init(num_channels, userdata);
|
||||
|
||||
result = mSystem->getVersion(&version);
|
||||
Check_FMOD_Error(result, "FMOD::System::getVersion");
|
||||
|
||||
if (version < FMOD_VERSION)
|
||||
{
|
||||
LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version
|
||||
<< ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL;
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
//Is this block applicable to linux?
|
||||
{
|
||||
result = mSystem->getNumDrivers(&numdrivers);
|
||||
Check_FMOD_Error(result, "FMOD::System::getNumDrivers");
|
||||
if (numdrivers == 0)
|
||||
{
|
||||
result = mSystem->setOutput(FMOD_OUTPUTTYPE_NOSOUND);
|
||||
Check_FMOD_Error(result, "FMOD::System::setOutput");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = mSystem->getDriverCaps(0, &caps, 0, &speakermode);
|
||||
Check_FMOD_Error(result,"FMOD::System::getDriverCaps");
|
||||
/*
|
||||
Set the user selected speaker mode.
|
||||
*/
|
||||
result = mSystem->setSpeakerMode(speakermode);
|
||||
Check_FMOD_Error(result, "FMOD::System::setSpeakerMode");
|
||||
if (caps & FMOD_CAPS_HARDWARE_EMULATED)
|
||||
{
|
||||
/*
|
||||
The user has the 'Acceleration' slider set to off! This is really bad
|
||||
for latency! You might want to warn the user about this.
|
||||
*/
|
||||
result = mSystem->setDSPBufferSize(1024, 10);
|
||||
Check_FMOD_Error(result, "FMOD::System::setDSPBufferSize");
|
||||
}
|
||||
result = mSystem->getDriverInfo(0, name, 256, 0);
|
||||
Check_FMOD_Error(result, "FMOD::System::getDriverInfo");
|
||||
|
||||
if (strstr(name, "SigmaTel"))
|
||||
{
|
||||
/*
|
||||
Sigmatel sound devices crackle for some reason if the format is PCM 16bit.
|
||||
PCM floating point output seems to solve it.
|
||||
*/
|
||||
result = mSystem->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0,0, FMOD_DSP_RESAMPLER_LINEAR);
|
||||
Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //LL_WINDOWS
|
||||
|
||||
// In this case, all sounds, PLUS wind and stream will be software.
|
||||
result = mSystem->setSoftwareChannels(num_channels+2);
|
||||
Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels");
|
||||
|
||||
U32 fmod_flags = FMOD_INIT_NORMAL;
|
||||
if(mEnableProfiler)
|
||||
fmod_flags |= FMOD_INIT_ENABLE_PROFILE;
|
||||
|
||||
#if LL_LINUX
|
||||
// If we don't set an output method, Linux FMOD always
|
||||
// decides on OSS and fails otherwise. So we'll manually
|
||||
// try ESD, then OSS, then ALSA.
|
||||
// Why this order? See SL-13250, but in short, OSS emulated
|
||||
// on top of ALSA is ironically more reliable than raw ALSA.
|
||||
// Ack, and ESD has more reliable failure modes - but has worse
|
||||
// latency - than all of them, so wins for now.
|
||||
bool audio_ok = false;
|
||||
|
||||
if (!audio_ok)
|
||||
{
|
||||
if (NULL == getenv("LL_BAD_FMODEX_ESD")) /*Flawfinder: ignore*/
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL;
|
||||
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_ESD) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "ESD audio output FAILED to initialize");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ESD audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
if (NULL == getenv("LL_BAD_FMODEX_OSS")) /*Flawfinder: ignore*/
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL;
|
||||
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_OSS) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "OSS audio output FAILED to initialize" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
if (NULL == getenv("LL_BAD_FMODEX_ALSA")) /*Flawfinder: ignore*/
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
|
||||
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_ALSA) &&
|
||||
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "ALSA audio output FAILED to initialize");
|
||||
}
|
||||
} else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// On Linux, FMOD causes a SIGPIPE for some netstream error
|
||||
// conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us.
|
||||
// NOW FIXED in FMOD 3.x since 2006-10-01.
|
||||
//signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
// We're interested in logging which output method we
|
||||
// ended up with, for QA purposes.
|
||||
FMOD_OUTPUTTYPE output_type;
|
||||
mSystem->getOutput(output_type);
|
||||
switch (output_type)
|
||||
{
|
||||
case FSOUND_OUTPUT_NOSOUND:
|
||||
LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
|
||||
case FSOUND_OUTPUT_OSS:
|
||||
LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break;
|
||||
case FSOUND_OUTPUT_ESD:
|
||||
LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break;
|
||||
case FSOUND_OUTPUT_ALSA:
|
||||
LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
|
||||
default:
|
||||
LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
|
||||
};
|
||||
#else // LL_LINUX
|
||||
|
||||
// initialize the FMOD engine
|
||||
result = mSystem->init( num_channels + 2, fmod_flags, 0);
|
||||
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
|
||||
{
|
||||
/*
|
||||
Ok, the speaker mode selected isn't supported by this soundcard. Switch it
|
||||
back to stereo...
|
||||
*/
|
||||
result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
|
||||
Check_FMOD_Error(result,"Error falling back to stereo mode");
|
||||
/*
|
||||
... and re-init.
|
||||
*/
|
||||
result = mSystem->init(100, FMOD_INIT_NORMAL, 0);
|
||||
}
|
||||
if(Check_FMOD_Error(result, "Error initializing FMOD"))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
||||
if (!getStreamingAudioImpl()) // no existing implementation added
|
||||
setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem));
|
||||
|
||||
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD initialized correctly" << LL_ENDL;
|
||||
|
||||
mInited = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::string LLAudioEngine_FMODEX::getDriverName(bool verbose)
|
||||
{
|
||||
llassert_always(mSystem);
|
||||
if (verbose)
|
||||
{
|
||||
U32 version;
|
||||
if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion"))
|
||||
{
|
||||
return llformat("FMOD version %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF);
|
||||
}
|
||||
}
|
||||
return "FMOD";
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODEX::allocateListener(void)
|
||||
{
|
||||
mListenerp = (LLListener *) new LLListener_FMODEX(mSystem);
|
||||
if (!mListenerp)
|
||||
{
|
||||
llwarns << "Listener creation failed" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODEX::shutdown()
|
||||
{
|
||||
stopInternetStream();
|
||||
|
||||
LLAudioEngine::shutdown();
|
||||
|
||||
llinfos << "LLAudioEngine_FMODEX::shutdown() closing FMOD" << llendl;
|
||||
mSystem->close();
|
||||
mSystem->release();
|
||||
llinfos << "LLAudioEngine_FMODEX::shutdown() done closing FMOD" << llendl;
|
||||
|
||||
delete mListenerp;
|
||||
mListenerp = NULL;
|
||||
}
|
||||
|
||||
|
||||
LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer()
|
||||
{
|
||||
return new LLAudioBufferFMODEX(mSystem);
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannel * LLAudioEngine_FMODEX::createChannel()
|
||||
{
|
||||
return new LLAudioChannelFMODEX(mSystem);
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODEX::initWind()
|
||||
{
|
||||
mNextWindUpdate = 0.0;
|
||||
|
||||
if (!mWindDSP)
|
||||
{
|
||||
FMOD_DSP_DESCRIPTION dspdesc;
|
||||
memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
|
||||
strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
|
||||
dspdesc.read = &windCallback; //Assign callback.
|
||||
if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP"))
|
||||
return false;
|
||||
|
||||
if(mWindGen)
|
||||
delete mWindGen;
|
||||
|
||||
float frequency = 44100;
|
||||
mWindDSP->getDefaults(&frequency,0,0,0);
|
||||
mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency);
|
||||
mWindDSP->setUserData((void*)mWindGen);
|
||||
}
|
||||
|
||||
if (mWindDSP)
|
||||
{
|
||||
mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODEX::cleanupWind()
|
||||
{
|
||||
if (mWindDSP)
|
||||
{
|
||||
mWindDSP->remove();
|
||||
mWindDSP->release();
|
||||
mWindDSP = NULL;
|
||||
}
|
||||
|
||||
delete mWindGen;
|
||||
mWindGen = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLAudioEngine_FMODEX::updateWind(LLVector3 wind_vec, F32 camera_height_above_water)
|
||||
{
|
||||
LLVector3 wind_pos;
|
||||
F64 pitch;
|
||||
F64 center_freq;
|
||||
|
||||
if (!mEnableWind)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
|
||||
{
|
||||
|
||||
// wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
|
||||
// need to convert this to the conventional orientation DS3D and OpenAL use
|
||||
// where +X = right, +Y = up, +Z = backwards
|
||||
|
||||
wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
|
||||
|
||||
// cerr << "Wind update" << endl;
|
||||
|
||||
pitch = 1.0 + mapWindVecToPitch(wind_vec);
|
||||
center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
|
||||
|
||||
mWindGen->mTargetFreq = (F32)center_freq;
|
||||
mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
|
||||
mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLAudioEngine_FMODEX::setInternalGain(F32 gain)
|
||||
{
|
||||
if (!mInited)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gain = llclamp( gain, 0.0f, 1.0f );
|
||||
|
||||
FMOD::ChannelGroup *master_group;
|
||||
mSystem->getMasterChannelGroup(&master_group);
|
||||
|
||||
master_group->setVolume(gain);
|
||||
|
||||
LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
|
||||
if ( saimpl )
|
||||
{
|
||||
// fmod likes its streaming audio channel gain re-asserted after
|
||||
// master volume change.
|
||||
saimpl->setGain(saimpl->getGain());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODEX implementation
|
||||
//
|
||||
|
||||
LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannelFMODEX::~LLAudioChannelFMODEX()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool LLAudioChannelFMODEX::updateBuffer()
|
||||
{
|
||||
if (LLAudioChannel::updateBuffer())
|
||||
{
|
||||
// Base class update returned true, which means that we need to actually
|
||||
// set up the channel for a different buffer.
|
||||
|
||||
LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentSourcep->getCurrentBuffer();
|
||||
|
||||
// Grab the FMOD sample associated with the buffer
|
||||
FMOD::Sound *soundp = bufferp->getSound();
|
||||
if (!soundp)
|
||||
{
|
||||
// This is bad, there should ALWAYS be a sound associated with a legit
|
||||
// buffer.
|
||||
llerrs << "No FMOD sound!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Actually play the sound. Start it off paused so we can do all the necessary
|
||||
// setup.
|
||||
if(!mChannelp)
|
||||
{
|
||||
FMOD_RESULT result = getSystem()->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp);
|
||||
Check_FMOD_Error(result, "FMOD::System::playSound");
|
||||
}
|
||||
|
||||
//llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
|
||||
}
|
||||
|
||||
// If we have a source for the channel, we need to update its gain.
|
||||
if (mCurrentSourcep)
|
||||
{
|
||||
// SJB: warnings can spam and hurt framerate, disabling
|
||||
FMOD_RESULT result;
|
||||
|
||||
result = mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain());
|
||||
//Check_FMOD_Error(result, "FMOD::Channel::setVolume");
|
||||
|
||||
result = mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
|
||||
/*if(Check_FMOD_Error(result, "FMOD::Channel::setMode"))
|
||||
{
|
||||
S32 index;
|
||||
mChannelp->getIndex(&index);
|
||||
llwarns << "Channel " << index << "Source ID: " << mCurrentSourcep->getID()
|
||||
<< " at " << mCurrentSourcep->getPositionGlobal() << llendl;
|
||||
}*/
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::update3DPosition()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// We're not actually a live channel (i.e., we're not playing back anything)
|
||||
return;
|
||||
}
|
||||
|
||||
LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentBufferp;
|
||||
if (!bufferp)
|
||||
{
|
||||
// We don't have a buffer associated with us (should really have been picked up
|
||||
// by the above if.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentSourcep->isAmbient())
|
||||
{
|
||||
// Ambient sound, don't need to do any positional updates.
|
||||
set3DMode(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Localized sound. Update the position and velocity of the sound.
|
||||
set3DMode(true);
|
||||
|
||||
LLVector3 float_pos;
|
||||
float_pos.setVec(mCurrentSourcep->getPositionGlobal());
|
||||
FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV);
|
||||
Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::updateLoop()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// May want to clear up the loop/sample counters.
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Hack: We keep track of whether we looped or not by seeing when the
|
||||
// sample position looks like it's going backwards. Not reliable; may
|
||||
// yield false negatives.
|
||||
//
|
||||
U32 cur_pos;
|
||||
mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES);
|
||||
|
||||
if (cur_pos < (U32)mLastSamplePos)
|
||||
{
|
||||
mLoopedThisFrame = true;
|
||||
}
|
||||
mLastSamplePos = cur_pos;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::cleanup()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
//llinfos << "Aborting cleanup with no channel handle." << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
//llinfos << "Cleaning up channel: " << mChannelID << llendl;
|
||||
Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop");
|
||||
|
||||
mCurrentBufferp = NULL;
|
||||
mChannelp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::play()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
llwarns << "Playing without a channel handle, aborting" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause");
|
||||
|
||||
getSource()->setPlayedOnce(true);
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp)
|
||||
{
|
||||
LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)channelp;
|
||||
if (!(fmod_channelp->mChannelp && mChannelp))
|
||||
{
|
||||
// Don't have channels allocated to both the master and the slave
|
||||
return;
|
||||
}
|
||||
|
||||
U32 cur_pos;
|
||||
if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position"))
|
||||
return;
|
||||
|
||||
cur_pos %= mCurrentBufferp->getLength();
|
||||
|
||||
// Try to match the position of our sync master
|
||||
Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position");
|
||||
|
||||
// Start us playing
|
||||
play();
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioChannelFMODEX::isPlaying()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool paused, playing;
|
||||
mChannelp->getPaused(&paused);
|
||||
mChannelp->isPlaying(&playing);
|
||||
return !paused && playing;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODEX implementation
|
||||
//
|
||||
|
||||
|
||||
LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystemp(system), mSoundp(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioBufferFMODEX::~LLAudioBufferFMODEX()
|
||||
{
|
||||
if(mSoundp)
|
||||
{
|
||||
mSoundp->release();
|
||||
mSoundp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioBufferFMODEX::loadWAV(const std::string& filename)
|
||||
{
|
||||
// Try to open a wav file from disk. This will eventually go away, as we don't
|
||||
// really want to block doing this.
|
||||
if (filename.empty())
|
||||
{
|
||||
// invalid filename, abort.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LLAPRFile::isExist(filename, LL_APR_RPB))
|
||||
{
|
||||
// File not found, abort.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSoundp)
|
||||
{
|
||||
// If there's already something loaded in this buffer, clean it up.
|
||||
mSoundp->release();
|
||||
mSoundp = NULL;
|
||||
}
|
||||
|
||||
FMOD_MODE base_mode = FMOD_LOOP_NORMAL | FMOD_SOFTWARE;
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
memset(&exinfo,0,sizeof(exinfo));
|
||||
exinfo.cbsize = sizeof(exinfo);
|
||||
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading.
|
||||
// Load up the wav file into an fmod sample
|
||||
#if LL_WINDOWS
|
||||
FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp);
|
||||
#else
|
||||
FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp);
|
||||
#endif
|
||||
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
// We failed to load the file for some reason.
|
||||
llwarns << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl;
|
||||
|
||||
//
|
||||
// If we EVER want to load wav files provided by end users, we need
|
||||
// to rethink this!
|
||||
//
|
||||
// file is probably corrupt - remove it.
|
||||
LLFile::remove(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything went well, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
U32 LLAudioBufferFMODEX::getLength()
|
||||
{
|
||||
if (!mSoundp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
U32 length;
|
||||
mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::set3DMode(bool use3d)
|
||||
{
|
||||
FMOD_MODE current_mode;
|
||||
if(mChannelp->getMode(¤t_mode) != FMOD_OK)
|
||||
return;
|
||||
FMOD_MODE new_mode = current_mode;
|
||||
new_mode &= ~(use3d ? FMOD_2D : FMOD_3D);
|
||||
new_mode |= use3d ? FMOD_3D : FMOD_2D;
|
||||
|
||||
if(current_mode != new_mode)
|
||||
{
|
||||
mChannelp->setMode(new_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels)
|
||||
{
|
||||
// originalbuffer = fmod's original mixbuffer.
|
||||
// newbuffer = the buffer passed from the previous DSP unit.
|
||||
// length = length in samples at this mix time.
|
||||
// userdata = user parameter passed through in FSOUND_DSP_Create.
|
||||
|
||||
LLWindGen<LLAudioEngine_FMODEX::MIXBUFFERFORMAT> *windgen;
|
||||
FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;
|
||||
|
||||
thisdsp->getUserData((void **)&windgen);
|
||||
S32 channels, configwidth, configheight;
|
||||
thisdsp->getInfo(0, 0, &channels, &configwidth, &configheight);
|
||||
|
||||
windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
131
indra/llaudio/llaudioengine_fmodex.h
Normal file
131
indra/llaudio/llaudioengine_fmodex.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file audioengine_FMODEX.h
|
||||
* @brief Definition of LLAudioEngine class abstracting the audio
|
||||
* support as a FMOD 3D implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_AUDIOENGINE_FMODEX_H
|
||||
#define LL_AUDIOENGINE_FMODEX_H
|
||||
|
||||
#include "llaudioengine.h"
|
||||
#include "lllistener_fmod.h"
|
||||
#include "llwindgen.h"
|
||||
|
||||
//Stubs
|
||||
class LLAudioStreamManagerFMODEX;
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
class Sound;
|
||||
class DSP;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLAudioEngine_FMODEX : public LLAudioEngine
|
||||
{
|
||||
public:
|
||||
LLAudioEngine_FMODEX(bool enable_profiler);
|
||||
virtual ~LLAudioEngine_FMODEX();
|
||||
|
||||
// initialization/startup/shutdown
|
||||
virtual bool init(const S32 num_channels, void *user_data);
|
||||
virtual std::string getDriverName(bool verbose);
|
||||
virtual void allocateListener();
|
||||
|
||||
virtual void shutdown();
|
||||
|
||||
/*virtual*/ bool initWind();
|
||||
/*virtual*/ void cleanupWind();
|
||||
|
||||
/*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water);
|
||||
|
||||
typedef F32 MIXBUFFERFORMAT;
|
||||
|
||||
FMOD::System *getSystem() const {return mSystem;}
|
||||
protected:
|
||||
/*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to.
|
||||
/*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel.
|
||||
|
||||
/*virtual*/ void setInternalGain(F32 gain);
|
||||
|
||||
bool mInited;
|
||||
|
||||
LLWindGen<MIXBUFFERFORMAT> *mWindGen;
|
||||
|
||||
FMOD::DSP *mWindDSP;
|
||||
FMOD::System *mSystem;
|
||||
bool mEnableProfiler;
|
||||
};
|
||||
|
||||
|
||||
class LLAudioChannelFMODEX : public LLAudioChannel
|
||||
{
|
||||
public:
|
||||
LLAudioChannelFMODEX(FMOD::System *audioengine);
|
||||
virtual ~LLAudioChannelFMODEX();
|
||||
|
||||
protected:
|
||||
/*virtual*/ void play();
|
||||
/*virtual*/ void playSynced(LLAudioChannel *channelp);
|
||||
/*virtual*/ void cleanup();
|
||||
/*virtual*/ bool isPlaying();
|
||||
|
||||
/*virtual*/ bool updateBuffer();
|
||||
/*virtual*/ void update3DPosition();
|
||||
/*virtual*/ void updateLoop();
|
||||
|
||||
void set3DMode(bool use3d);
|
||||
protected:
|
||||
FMOD::System *getSystem() const {return mSystemp;}
|
||||
FMOD::System *mSystemp;
|
||||
FMOD::Channel *mChannelp;
|
||||
S32 mLastSamplePos;
|
||||
};
|
||||
|
||||
|
||||
class LLAudioBufferFMODEX : public LLAudioBuffer
|
||||
{
|
||||
public:
|
||||
LLAudioBufferFMODEX(FMOD::System *audioengine);
|
||||
virtual ~LLAudioBufferFMODEX();
|
||||
|
||||
/*virtual*/ bool loadWAV(const std::string& filename);
|
||||
/*virtual*/ U32 getLength();
|
||||
friend class LLAudioChannelFMODEX;
|
||||
protected:
|
||||
FMOD::System *getSystem() const {return mSystemp;}
|
||||
FMOD::System *mSystemp;
|
||||
FMOD::Sound *getSound() const{ return mSoundp; }
|
||||
FMOD::Sound *mSoundp;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_AUDIOENGINE_FMODEX_H
|
||||
132
indra/llaudio/lllistener_fmodex.cpp
Normal file
132
indra/llaudio/lllistener_fmodex.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @file listener_fmod.cpp
|
||||
* @brief implementation of LISTENER class abstracting the audio
|
||||
* support as a FMOD 3D implementation (windows only)
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llaudioengine.h"
|
||||
#include "lllistener_fmodex.h"
|
||||
#include "fmod.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// constructor
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system)
|
||||
{
|
||||
mSystem = system;
|
||||
init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODEX::~LLListener_FMODEX()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::init(void)
|
||||
{
|
||||
// do inherited
|
||||
LLListener::init();
|
||||
mDopplerFactor = 1.0f;
|
||||
mRolloffFactor = 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::translate(LLVector3 offset)
|
||||
{
|
||||
LLListener::translate(offset);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::setPosition(LLVector3 pos)
|
||||
{
|
||||
LLListener::setPosition(pos);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::setVelocity(LLVector3 vel)
|
||||
{
|
||||
LLListener::setVelocity(vel);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at)
|
||||
{
|
||||
LLListener::orient(up, at);
|
||||
|
||||
// Welcome to the transition between right and left
|
||||
// (coordinate systems, that is)
|
||||
// Leaving the at vector alone results in a L/R reversal
|
||||
// since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed
|
||||
at = -at;
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::commitDeferredChanges()
|
||||
{
|
||||
mSystem->update();
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODEX::setRolloffFactor(F32 factor)
|
||||
{
|
||||
mRolloffFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODEX::getRolloffFactor()
|
||||
{
|
||||
return mRolloffFactor;
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODEX::setDopplerFactor(F32 factor)
|
||||
{
|
||||
mDopplerFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODEX::getDopplerFactor()
|
||||
{
|
||||
return mDopplerFactor;
|
||||
}
|
||||
|
||||
|
||||
71
indra/llaudio/lllistener_fmodex.h
Normal file
71
indra/llaudio/lllistener_fmodex.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file listener_fmod.h
|
||||
* @brief Description of LISTENER class abstracting the audio support
|
||||
* as an FMOD 3D implementation (windows and Linux)
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LISTENER_FMODEX_H
|
||||
#define LL_LISTENER_FMODEX_H
|
||||
|
||||
#include "lllistener.h"
|
||||
|
||||
//Stubs
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLListener_FMODEX : public LLListener
|
||||
{
|
||||
public:
|
||||
LLListener_FMODEX(FMOD::System *system);
|
||||
virtual ~LLListener_FMODEX();
|
||||
virtual void init();
|
||||
|
||||
virtual void translate(LLVector3 offset);
|
||||
virtual void setPosition(LLVector3 pos);
|
||||
virtual void setVelocity(LLVector3 vel);
|
||||
virtual void orient(LLVector3 up, LLVector3 at);
|
||||
virtual void commitDeferredChanges();
|
||||
|
||||
virtual void setDopplerFactor(F32 factor);
|
||||
virtual F32 getDopplerFactor();
|
||||
virtual void setRolloffFactor(F32 factor);
|
||||
virtual F32 getRolloffFactor();
|
||||
protected:
|
||||
FMOD::System *mSystem;
|
||||
F32 mDopplerFactor;
|
||||
F32 mRolloffFactor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#include "stdtypes.h" // from llcommon
|
||||
|
||||
class LLSD;
|
||||
|
||||
// Entirely abstract. Based exactly on the historic API.
|
||||
class LLStreamingAudioInterface
|
||||
{
|
||||
@@ -51,6 +53,7 @@ class LLStreamingAudioInterface
|
||||
virtual void setGain(F32 vol) = 0;
|
||||
virtual F32 getGain() = 0;
|
||||
virtual std::string getURL() = 0;
|
||||
virtual const LLSD *getMetaData() = 0; //return NULL if not supported.
|
||||
};
|
||||
|
||||
#endif // LL_STREAMINGAUDIO_H
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
const std::string& getURL() { return mInternetStreamURL; }
|
||||
|
||||
int getOpenState();
|
||||
|
||||
FSOUND_STREAM* getStream() { return mInternetStream; }
|
||||
protected:
|
||||
FSOUND_STREAM* mInternetStream;
|
||||
bool mReady;
|
||||
@@ -66,7 +68,8 @@ protected:
|
||||
LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
|
||||
mCurrentInternetStreamp(NULL),
|
||||
mFMODInternetStreamChannel(-1),
|
||||
mGain(1.0f)
|
||||
mGain(1.0f),
|
||||
mMetaData(NULL)
|
||||
{
|
||||
// Number of milliseconds of audio to buffer for the audio card.
|
||||
// Must be larger than the usual Second Life frame stutter time.
|
||||
@@ -87,6 +90,17 @@ LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD()
|
||||
// nothing interesting/safe to do.
|
||||
}
|
||||
|
||||
signed char F_CALLBACKAPI MetaDataCallback(char *name, char *value, void *userdata)
|
||||
{
|
||||
std::string szName(name);
|
||||
if(szName == "TITLE" || szName=="TIT2" || szName=="Title")
|
||||
(*(LLSD*)userdata)["TITLE"] = value;
|
||||
if(szName == "ARTIST" || szName=="TPE1" || szName =="WM/AlbumTitle")
|
||||
(*(LLSD*)userdata)["ARTIST"] = value;
|
||||
else
|
||||
(*(LLSD*)userdata)[std::string(name)] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMOD::start(const std::string& url)
|
||||
{
|
||||
@@ -104,6 +118,10 @@ void LLStreamingAudio_FMOD::start(const std::string& url)
|
||||
llinfos << "Starting internet stream: " << url << llendl;
|
||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url);
|
||||
mURL = url;
|
||||
if(mCurrentInternetStreamp->getStream())
|
||||
{
|
||||
mMetaData = new LLSD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -154,6 +172,10 @@ void LLStreamingAudio_FMOD::update()
|
||||
// Reset volume to previously set volume
|
||||
setGain(getGain());
|
||||
FSOUND_SetPaused(mFMODInternetStreamChannel, false);
|
||||
if(mCurrentInternetStreamp->getStream() && mMetaData)
|
||||
{
|
||||
FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),&MetaDataCallback, mMetaData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,11 +206,17 @@ void LLStreamingAudio_FMOD::update()
|
||||
// buffering
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMOD::stop()
|
||||
{
|
||||
if(mMetaData)
|
||||
{
|
||||
if(mCurrentInternetStreamp && mCurrentInternetStreamp->getStream())
|
||||
FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),NULL,NULL);
|
||||
delete mMetaData;
|
||||
mMetaData = NULL;
|
||||
}
|
||||
if (mFMODInternetStreamChannel != -1)
|
||||
{
|
||||
FSOUND_SetPaused(mFMODInternetStreamChannel, true);
|
||||
|
||||
@@ -54,6 +54,7 @@ class LLStreamingAudio_FMOD : public LLStreamingAudioInterface
|
||||
/*virtual*/ void setGain(F32 vol);
|
||||
/*virtual*/ F32 getGain();
|
||||
/*virtual*/ std::string getURL();
|
||||
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not supported.
|
||||
|
||||
private:
|
||||
LLAudioStreamManagerFMOD *mCurrentInternetStreamp;
|
||||
@@ -62,6 +63,8 @@ private:
|
||||
|
||||
std::string mURL;
|
||||
F32 mGain;
|
||||
|
||||
LLSD *mMetaData;
|
||||
};
|
||||
|
||||
|
||||
|
||||
427
indra/llaudio/llstreamingaudio_fmodex.cpp
Normal file
427
indra/llaudio/llstreamingaudio_fmodex.cpp
Normal file
@@ -0,0 +1,427 @@
|
||||
/**
|
||||
* @file streamingaudio_fmod.cpp
|
||||
* @brief LLStreamingAudio_FMODEX implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llmath.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_errors.h"
|
||||
|
||||
#include "llstreamingaudio_fmodex.h"
|
||||
|
||||
|
||||
class LLAudioStreamManagerFMODEX
|
||||
{
|
||||
public:
|
||||
LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url);
|
||||
FMOD::Channel* startStream();
|
||||
bool stopStream(); // Returns true if the stream was successfully stopped.
|
||||
bool ready();
|
||||
|
||||
const std::string& getURL() { return mInternetStreamURL; }
|
||||
|
||||
FMOD_OPENSTATE getOpenState();
|
||||
protected:
|
||||
FMOD::System* mSystem;
|
||||
FMOD::Channel* mStreamChannel;
|
||||
FMOD::Sound* mInternetStream;
|
||||
bool mReady;
|
||||
|
||||
std::string mInternetStreamURL;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Internet Streaming
|
||||
//---------------------------------------------------------------------------
|
||||
LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) :
|
||||
mSystem(system),
|
||||
mCurrentInternetStreamp(NULL),
|
||||
mFMODInternetStreamChannelp(NULL),
|
||||
mGain(1.0f),
|
||||
mMetaData(NULL)
|
||||
{
|
||||
// Number of milliseconds of audio to buffer for the audio card.
|
||||
// Must be larger than the usual Second Life frame stutter time.
|
||||
mSystem->setStreamBufferSize(200, FMOD_TIMEUNIT_MS);
|
||||
|
||||
// Here's where we set the size of the network buffer and some buffering
|
||||
// parameters. In this case we want a network buffer of 16k, we want it
|
||||
// to prebuffer 40% of that when we first connect, and we want it
|
||||
// to rebuffer 80% of that whenever we encounter a buffer underrun.
|
||||
|
||||
// Leave the net buffer properties at the default.
|
||||
//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
|
||||
}
|
||||
|
||||
|
||||
LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX()
|
||||
{
|
||||
// nothing interesting/safe to do.
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODEX::start(const std::string& url)
|
||||
{
|
||||
//if (!mInited)
|
||||
//{
|
||||
// llwarns << "startInternetStream before audio initialized" << llendl;
|
||||
// return;
|
||||
//}
|
||||
|
||||
// "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
|
||||
stop();
|
||||
|
||||
if (!url.empty())
|
||||
{
|
||||
llinfos << "Starting internet stream: " << url << llendl;
|
||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url);
|
||||
mURL = url;
|
||||
mMetaData = new LLSD;
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "Set internet stream to null" << llendl;
|
||||
mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODEX::update()
|
||||
{
|
||||
// Kill dead internet streams, if possible
|
||||
std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
|
||||
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
|
||||
{
|
||||
LLAudioStreamManagerFMODEX *streamp = *iter;
|
||||
if (streamp->stopStream())
|
||||
{
|
||||
llinfos << "Closed dead stream" << llendl;
|
||||
delete streamp;
|
||||
mDeadStreams.erase(iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't do anything if there are no streams playing
|
||||
if (!mCurrentInternetStreamp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState();
|
||||
|
||||
if (open_state == FMOD_OPENSTATE_READY)
|
||||
{
|
||||
// Stream is live
|
||||
|
||||
// start the stream if it's ready
|
||||
if (!mFMODInternetStreamChannelp &&
|
||||
(mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream()))
|
||||
{
|
||||
// Reset volume to previously set volume
|
||||
setGain(getGain());
|
||||
mFMODInternetStreamChannelp->setPaused(false);
|
||||
}
|
||||
}
|
||||
else if(open_state == FMOD_OPENSTATE_ERROR)
|
||||
{
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(mFMODInternetStreamChannelp)
|
||||
{
|
||||
if(!mMetaData)
|
||||
mMetaData = new LLSD;
|
||||
|
||||
FMOD::Sound *sound = NULL;
|
||||
|
||||
if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
|
||||
{
|
||||
FMOD_TAG tag;
|
||||
S32 tagcount, dirtytagcount;
|
||||
if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount)
|
||||
{
|
||||
mMetaData->clear();
|
||||
|
||||
for(S32 i = 0; i < tagcount; ++i)
|
||||
{
|
||||
if(sound->getTag(NULL, i, &tag)!=FMOD_OK)
|
||||
continue;
|
||||
std::string name = tag.name;
|
||||
switch(tag.type) //Crappy tag translate table.
|
||||
{
|
||||
case(FMOD_TAGTYPE_ID3V2):
|
||||
if(name == "TIT2") name = "TITLE";
|
||||
else if(name == "TPE1") name = "ARTIST";
|
||||
break;
|
||||
case(FMOD_TAGTYPE_ASF):
|
||||
if(name == "Title") name = "TITLE";
|
||||
else if(name == "WM/AlbumArtist") name = "ARTIST";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch(tag.datatype)
|
||||
{
|
||||
case(FMOD_TAGDATATYPE_INT):
|
||||
(*mMetaData)[name]=*(LLSD::Integer*)(tag.data);
|
||||
llinfos << tag.name << ": " << *(int*)(tag.data) << llendl;
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_FLOAT):
|
||||
(*mMetaData)[name]=*(LLSD::Float*)(tag.data);
|
||||
llinfos << tag.name << ": " << *(float*)(tag.data) << llendl;
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_STRING):
|
||||
{
|
||||
std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
|
||||
(*mMetaData)[name]=out;
|
||||
llinfos << tag.name << ": " << out << llendl;
|
||||
}
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_STRING_UTF16):
|
||||
{
|
||||
std::string out((char*)tag.data,tag.datalen);
|
||||
(*mMetaData)[std::string(tag.name)]=out;
|
||||
llinfos << tag.name << ": " << out << llendl;
|
||||
}
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_STRING_UTF16BE):
|
||||
{
|
||||
std::string out((char*)tag.data,tag.datalen);
|
||||
U16* buf = (U16*)out.c_str();
|
||||
for(U32 j = 0; j < out.size()/2; ++j)
|
||||
(((buf[j] & 0xff)<<8) | ((buf[j] & 0xff00)>>8));
|
||||
(*mMetaData)[std::string(tag.name)]=out;
|
||||
llinfos << tag.name << ": " << out << llendl;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODEX::stop()
|
||||
{
|
||||
if(mMetaData)
|
||||
{
|
||||
delete mMetaData;
|
||||
mMetaData = NULL;
|
||||
}
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
mFMODInternetStreamChannelp->setPaused(true);
|
||||
mFMODInternetStreamChannelp->setPriority(0);
|
||||
mFMODInternetStreamChannelp = NULL;
|
||||
}
|
||||
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl;
|
||||
if (mCurrentInternetStreamp->stopStream())
|
||||
{
|
||||
delete mCurrentInternetStreamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl;
|
||||
mDeadStreams.push_back(mCurrentInternetStreamp);
|
||||
}
|
||||
mCurrentInternetStreamp = NULL;
|
||||
//mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODEX::pause(int pauseopt)
|
||||
{
|
||||
if (pauseopt < 0)
|
||||
{
|
||||
pauseopt = mCurrentInternetStreamp ? 1 : 0;
|
||||
}
|
||||
|
||||
if (pauseopt)
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
stop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start(getURL());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A stream is "playing" if it has been requested to start. That
|
||||
// doesn't necessarily mean audio is coming out of the speakers.
|
||||
int LLStreamingAudio_FMODEX::isPlaying()
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
return 1; // Active and playing
|
||||
}
|
||||
else if (!mURL.empty())
|
||||
{
|
||||
return 2; // "Paused"
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
F32 LLStreamingAudio_FMODEX::getGain()
|
||||
{
|
||||
return mGain;
|
||||
}
|
||||
|
||||
|
||||
std::string LLStreamingAudio_FMODEX::getURL()
|
||||
{
|
||||
return mURL;
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODEX::setGain(F32 vol)
|
||||
{
|
||||
mGain = vol;
|
||||
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here?
|
||||
|
||||
mFMODInternetStreamChannelp->setVolume(vol);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// manager of possibly-multiple internet audio streams
|
||||
|
||||
LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) :
|
||||
mSystem(system),
|
||||
mStreamChannel(NULL),
|
||||
mInternetStream(NULL),
|
||||
mReady(false)
|
||||
{
|
||||
mInternetStreamURL = url;
|
||||
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
memset(&exinfo,0,sizeof(exinfo));
|
||||
exinfo.cbsize = sizeof(exinfo);
|
||||
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_MPEG; //Hint to speed up loading.
|
||||
|
||||
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING, &exinfo, &mInternetStream);
|
||||
|
||||
if (result!= FMOD_OK)
|
||||
{
|
||||
llwarns << "Couldn't open fmod stream, error "
|
||||
<< FMOD_ErrorString(result)
|
||||
<< llendl;
|
||||
mReady = false;
|
||||
return;
|
||||
}
|
||||
|
||||
mReady = true;
|
||||
}
|
||||
|
||||
FMOD::Channel *LLAudioStreamManagerFMODEX::startStream()
|
||||
{
|
||||
// We need a live and opened stream before we try and play it.
|
||||
if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY)
|
||||
{
|
||||
llwarns << "No internet stream to start playing!" << llendl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(mStreamChannel)
|
||||
return mStreamChannel; //Already have a channel for this stream.
|
||||
|
||||
mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel);
|
||||
return mStreamChannel;
|
||||
}
|
||||
|
||||
bool LLAudioStreamManagerFMODEX::stopStream()
|
||||
{
|
||||
if (mInternetStream)
|
||||
{
|
||||
|
||||
|
||||
bool close = true;
|
||||
switch (getOpenState())
|
||||
{
|
||||
case FMOD_OPENSTATE_CONNECTING:
|
||||
close = false;
|
||||
break;
|
||||
/*case FSOUND_STREAM_NET_NOTCONNECTED:
|
||||
case FSOUND_STREAM_NET_BUFFERING:
|
||||
case FSOUND_STREAM_NET_READY:
|
||||
case FSOUND_STREAM_NET_ERROR:*/
|
||||
default:
|
||||
close = true;
|
||||
}
|
||||
|
||||
if (close)
|
||||
{
|
||||
mInternetStream->release();
|
||||
mStreamChannel = NULL;
|
||||
mInternetStream = NULL;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState()
|
||||
{
|
||||
FMOD_OPENSTATE state;
|
||||
mInternetStream->getOpenState(&state,NULL,NULL,NULL);
|
||||
return state;
|
||||
}
|
||||
80
indra/llaudio/llstreamingaudio_fmodex.h
Normal file
80
indra/llaudio/llstreamingaudio_fmodex.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file streamingaudio_fmod.h
|
||||
* @author Tofu Linden
|
||||
* @brief Definition of LLStreamingAudio_FMOD implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_STREAMINGAUDIO_FMOD_H
|
||||
#define LL_STREAMINGAUDIO_FMOD_H
|
||||
|
||||
#include "stdtypes.h" // from llcommon
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
|
||||
//Stubs
|
||||
class LLAudioStreamManagerFMODEX;
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface
|
||||
{
|
||||
public:
|
||||
LLStreamingAudio_FMODEX(FMOD::System *system);
|
||||
/*virtual*/ ~LLStreamingAudio_FMODEX();
|
||||
|
||||
/*virtual*/ void start(const std::string& url);
|
||||
/*virtual*/ void stop();
|
||||
/*virtual*/ void pause(int pause);
|
||||
/*virtual*/ void update();
|
||||
/*virtual*/ int isPlaying();
|
||||
/*virtual*/ void setGain(F32 vol);
|
||||
/*virtual*/ F32 getGain();
|
||||
/*virtual*/ std::string getURL();
|
||||
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not supported.
|
||||
|
||||
private:
|
||||
FMOD::System *mSystem;
|
||||
|
||||
LLAudioStreamManagerFMODEX *mCurrentInternetStreamp;
|
||||
FMOD::Channel *mFMODInternetStreamChannelp;
|
||||
std::list<LLAudioStreamManagerFMODEX *> mDeadStreams;
|
||||
|
||||
std::string mURL;
|
||||
F32 mGain;
|
||||
|
||||
LLSD *mMetaData;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_STREAMINGAUDIO_FMOD_H
|
||||
@@ -33,6 +33,7 @@
|
||||
#define WINDGEN_H
|
||||
|
||||
#include "llcommon.h"
|
||||
#include "llrand.h"
|
||||
|
||||
template <class MIXBUFFERFORMAT_T>
|
||||
class LLWindGen
|
||||
@@ -60,7 +61,9 @@ public:
|
||||
}
|
||||
|
||||
const U32 getInputSamplingRate() { return mInputSamplingRate; }
|
||||
|
||||
const F32 getNextSample();
|
||||
const F32 getClampedSample(bool clamp, F32 sample);
|
||||
|
||||
// newbuffer = the buffer passed from the previous DSP unit.
|
||||
// numsamples = length in samples-per-channel at this mix time.
|
||||
// NOTE: generates L/R interleaved stereo
|
||||
@@ -95,7 +98,7 @@ public:
|
||||
|
||||
// Start with white noise
|
||||
// This expression is fragile, rearrange it and it will break!
|
||||
next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8);
|
||||
next_sample = getNextSample();
|
||||
|
||||
// Apply a pinking filter
|
||||
// Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
|
||||
@@ -132,23 +135,13 @@ public:
|
||||
for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
|
||||
{
|
||||
mLastSample = mLastSample + delta;
|
||||
S32 sample_right = (S32)(mLastSample * mCurrentPanGainR);
|
||||
S32 sample_left = (S32)mLastSample - sample_right;
|
||||
MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR);
|
||||
MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right);
|
||||
|
||||
if (!clip)
|
||||
{
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)sample_left;
|
||||
++cursamplep;
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)sample_right;
|
||||
++cursamplep;
|
||||
}
|
||||
else
|
||||
{
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX);
|
||||
++cursamplep;
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX);
|
||||
++cursamplep;
|
||||
}
|
||||
*cursamplep = sample_left;
|
||||
++cursamplep;
|
||||
*cursamplep = sample_right;
|
||||
++cursamplep;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,4 +172,9 @@ private:
|
||||
F32 mLastSample;
|
||||
};
|
||||
|
||||
template<class T> inline const F32 LLWindGen<T>::getNextSample() { return (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8); }
|
||||
template<> inline const F32 LLWindGen<F32>::getNextSample() { return ll_frand()-.5f; }
|
||||
template<class T> inline const F32 LLWindGen<T>::getClampedSample(bool clamp, F32 sample) { return clamp ? (F32)llclamp((S32)sample,(S32)S16_MIN,(S32)S16_MAX) : sample; }
|
||||
template<> inline const F32 LLWindGen<F32>::getClampedSample(bool clamp, F32 sample) { return sample; }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -56,9 +56,7 @@ LLJoint::LLJoint()
|
||||
mUpdateXform = TRUE;
|
||||
mJointNum = -1;
|
||||
touch();
|
||||
#if MESH_ENABLED
|
||||
mResetAfterRestoreOldXform = false;
|
||||
#endif //MESH_ENABLED
|
||||
}
|
||||
|
||||
|
||||
@@ -242,7 +240,6 @@ void LLJoint::setPosition( const LLVector3& pos )
|
||||
}
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
//--------------------------------------------------------------------
|
||||
// setPosition()
|
||||
//--------------------------------------------------------------------
|
||||
@@ -278,7 +275,6 @@ void LLJoint::restoreToDefaultXform( void )
|
||||
mXform = mDefaultXform;
|
||||
setPosition( mXform.getPosition() );
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// getWorldPosition()
|
||||
|
||||
@@ -86,19 +86,14 @@ protected:
|
||||
|
||||
// explicit transformation members
|
||||
LLXformMatrix mXform;
|
||||
#if MESH_ENABLED
|
||||
LLXformMatrix mOldXform;
|
||||
LLXformMatrix mDefaultXform;
|
||||
|
||||
LLUUID mId;
|
||||
#endif //MESH_ENABLED
|
||||
public:
|
||||
U32 mDirtyFlags;
|
||||
BOOL mUpdateXform;
|
||||
|
||||
#if MESH_ENABLED
|
||||
BOOL mResetAfterRestoreOldXform;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// describes the skin binding pose
|
||||
LLVector3 mSkinOffset;
|
||||
@@ -188,8 +183,6 @@ public:
|
||||
S32 getJointNum() const { return mJointNum; }
|
||||
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
|
||||
|
||||
#if MESH_ENABLED
|
||||
|
||||
void restoreOldXform( void );
|
||||
void restoreToDefaultXform( void );
|
||||
void setDefaultFromCurrentXform( void );
|
||||
@@ -204,7 +197,6 @@ public:
|
||||
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
|
||||
//Setter for joint reset flag
|
||||
void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// <edit>
|
||||
std::string exportString(U32 tabs = 0);
|
||||
|
||||
@@ -153,10 +153,10 @@ const char LAND_LAYER_CODE = 'L';
|
||||
const char WATER_LAYER_CODE = 'W';
|
||||
const char WIND_LAYER_CODE = '7';
|
||||
const char CLOUD_LAYER_CODE = '8';
|
||||
// Extended land layer for Aurora Sim
|
||||
// Extended land layer for Aurora Sim
|
||||
const char AURORA_LAND_LAYER_CODE = 'M';
|
||||
const char AURORA_WATER_LAYER_CODE = 'X';
|
||||
const char AURORA_WIND_LAYER_CODE = '9';
|
||||
const char AURORA_WATER_LAYER_CODE = 'X';
|
||||
const char AURORA_WIND_LAYER_CODE = '9';
|
||||
const char AURORA_CLOUD_LAYER_CODE = ':';
|
||||
|
||||
// keys
|
||||
|
||||
@@ -72,11 +72,9 @@ public:
|
||||
FTM_UPDATE_GRASS,
|
||||
FTM_UPDATE_TREE,
|
||||
FTM_UPDATE_AVATAR,
|
||||
#if MESH_ENABLED
|
||||
FTM_UPDATE_RIGGED_VOLUME,
|
||||
FTM_SKIN_RIGGED,
|
||||
FTM_RIGGED_OCTREE,
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// common render components
|
||||
FTM_SHADOW_GEOMETRY,
|
||||
@@ -136,14 +134,21 @@ public:
|
||||
FTM_STATESORT,
|
||||
FTM_STATESORT_DRAWABLE,
|
||||
FTM_STATESORT_POSTSORT,
|
||||
#if MESH_ENABLED
|
||||
FTM_MESH_UPDATE,
|
||||
FTM_MESH_LOCK1,
|
||||
FTM_MESH_LOCK2,
|
||||
FTM_LOAD_MESH_LOD,
|
||||
#endif //MESH_ENABLED
|
||||
FTM_REBUILD_VBO,
|
||||
FTM_REBUILD_VOLUME_VB,
|
||||
FTM_FACE_GET_GEOM,
|
||||
FTM_FACE_GEOM_POSITION,
|
||||
FTM_FACE_GEOM_NORMAL,
|
||||
FTM_FACE_GEOM_TEXTURE,
|
||||
FTM_FACE_GEOM_COLOR,
|
||||
FTM_FACE_GEOM_EMISSIVE,
|
||||
FTM_FACE_GEOM_WEIGHTS,
|
||||
FTM_FACE_GEOM_BINORMAL,
|
||||
FTM_FACE_GEOM_INDEX,
|
||||
FTM_REBUILD_BRIDGE_VB,
|
||||
FTM_REBUILD_HUD_VB,
|
||||
FTM_REBUILD_TERRAIN_VB,
|
||||
@@ -217,6 +222,13 @@ public:
|
||||
FTM_TEMP6,
|
||||
FTM_TEMP7,
|
||||
FTM_TEMP8,
|
||||
FTM_TEMP9,
|
||||
FTM_TEMP10,
|
||||
FTM_TEMP11,
|
||||
FTM_TEMP12,
|
||||
FTM_TEMP13,
|
||||
FTM_TEMP14,
|
||||
FTM_TEMP15,
|
||||
|
||||
FTM_OTHER, // Special, used by display code
|
||||
|
||||
|
||||
@@ -194,7 +194,12 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
LLInstanceTracker(KEY key) { add_(key); }
|
||||
LLInstanceTracker(KEY key)
|
||||
{
|
||||
// make sure static data outlives all instances
|
||||
getStatic();
|
||||
add_(key);
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
@@ -282,7 +287,8 @@ public:
|
||||
protected:
|
||||
LLInstanceTracker()
|
||||
{
|
||||
// it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
|
||||
// make sure static data outlives all instances
|
||||
getStatic();
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,9 +40,6 @@
|
||||
#endif
|
||||
|
||||
#include "llerror.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if LL_DEBUG
|
||||
inline void* ll_aligned_malloc( size_t size, int align )
|
||||
{
|
||||
@@ -120,6 +117,10 @@ inline void ll_aligned_free_32(void *p)
|
||||
#define ll_aligned_free_32 free
|
||||
#endif // LL_DEBUG
|
||||
|
||||
#ifndef __DEBUG_PRIVATE_MEM__
|
||||
#define __DEBUG_PRIVATE_MEM__ 0
|
||||
#endif
|
||||
|
||||
class LL_COMMON_API LLMemory
|
||||
{
|
||||
public:
|
||||
@@ -130,14 +131,399 @@ public:
|
||||
// Return value is zero if not known.
|
||||
static U64 getCurrentRSS();
|
||||
static U32 getWorkingSetSize();
|
||||
static void* tryToAlloc(void* address, U32 size);
|
||||
static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure);
|
||||
static void updateMemoryInfo() ;
|
||||
static void logMemoryInfo(BOOL update = FALSE);
|
||||
static bool isMemoryPoolLow();
|
||||
|
||||
static U32 getAvailableMemKB() ;
|
||||
static U32 getMaxMemKB() ;
|
||||
static U32 getAllocatedMemKB() ;
|
||||
private:
|
||||
static char* reserveMem;
|
||||
static U32 sAvailPhysicalMemInKB ;
|
||||
static U32 sMaxPhysicalMemInKB ;
|
||||
static U32 sAllocatedMemInKB;
|
||||
static U32 sAllocatedPageSizeInKB ;
|
||||
|
||||
static U32 sMaxHeapSizeInKB;
|
||||
static BOOL sEnableMemoryFailurePrevention;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class LLMutex ;
|
||||
#if MEM_TRACK_MEM
|
||||
class LL_COMMON_API LLMemTracker
|
||||
{
|
||||
private:
|
||||
LLMemTracker() ;
|
||||
~LLMemTracker() ;
|
||||
|
||||
public:
|
||||
static void release() ;
|
||||
static LLMemTracker* getInstance() ;
|
||||
|
||||
void track(const char* function, const int line) ;
|
||||
void preDraw(BOOL pause) ;
|
||||
void postDraw() ;
|
||||
const char* getNextLine() ;
|
||||
|
||||
private:
|
||||
static LLMemTracker* sInstance ;
|
||||
|
||||
char** mStringBuffer ;
|
||||
S32 mCapacity ;
|
||||
U32 mLastAllocatedMem ;
|
||||
S32 mCurIndex ;
|
||||
S32 mCounter;
|
||||
S32 mDrawnIndex;
|
||||
S32 mNumOfDrawn;
|
||||
BOOL mPaused;
|
||||
LLMutex* mMutexp ;
|
||||
};
|
||||
|
||||
#define MEM_TRACK_RELEASE LLMemTracker::release() ;
|
||||
#define MEM_TRACK LLMemTracker::getInstance()->track(__FUNCTION__, __LINE__) ;
|
||||
|
||||
#else // MEM_TRACK_MEM
|
||||
|
||||
#define MEM_TRACK_RELEASE
|
||||
#define MEM_TRACK
|
||||
|
||||
#endif // MEM_TRACK_MEM
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
//class LLPrivateMemoryPool defines a private memory pool for an application to use, so the application does not
|
||||
//need to access the heap directly fro each memory allocation. Throught this, the allocation speed is faster,
|
||||
//and reduces virtaul address space gragmentation problem.
|
||||
//Note: this class is thread-safe by passing true to the constructor function. However, you do not need to do this unless
|
||||
//you are sure the memory allocation and de-allocation will happen in different threads. To make the pool thread safe
|
||||
//increases allocation and deallocation cost.
|
||||
//
|
||||
class LL_COMMON_API LLPrivateMemoryPool
|
||||
{
|
||||
friend class LLPrivateMemoryPoolManager ;
|
||||
|
||||
public:
|
||||
class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly
|
||||
{
|
||||
public:
|
||||
LLMemoryBlock() ;
|
||||
~LLMemoryBlock() ;
|
||||
|
||||
void init(char* buffer, U32 buffer_size, U32 slot_size) ;
|
||||
void setBuffer(char* buffer, U32 buffer_size) ;
|
||||
|
||||
char* allocate() ;
|
||||
void freeMem(void* addr) ;
|
||||
|
||||
bool empty() {return !mAllocatedSlots;}
|
||||
bool isFull() {return mAllocatedSlots == mTotalSlots;}
|
||||
bool isFree() {return !mTotalSlots;}
|
||||
|
||||
U32 getSlotSize()const {return mSlotSize;}
|
||||
U32 getTotalSlots()const {return mTotalSlots;}
|
||||
U32 getBufferSize()const {return mBufferSize;}
|
||||
char* getBuffer() const {return mBuffer;}
|
||||
|
||||
//debug use
|
||||
void resetBitMap() ;
|
||||
private:
|
||||
char* mBuffer;
|
||||
U32 mSlotSize ; //when the block is not initialized, it is the buffer size.
|
||||
U32 mBufferSize ;
|
||||
U32 mUsageBits ;
|
||||
U8 mTotalSlots ;
|
||||
U8 mAllocatedSlots ;
|
||||
U8 mDummySize ; //size of extra bytes reserved for mUsageBits.
|
||||
|
||||
public:
|
||||
LLMemoryBlock* mPrev ;
|
||||
LLMemoryBlock* mNext ;
|
||||
LLMemoryBlock* mSelf ;
|
||||
|
||||
struct CompareAddress
|
||||
{
|
||||
bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs)
|
||||
{
|
||||
return (U32)lhs->getBuffer() < (U32)rhs->getBuffer();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLMemoryChunk //is divided into memory blocks.
|
||||
{
|
||||
public:
|
||||
LLMemoryChunk() ;
|
||||
~LLMemoryChunk() ;
|
||||
|
||||
void init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
|
||||
void setBuffer(char* buffer, U32 buffer_size) ;
|
||||
|
||||
bool empty() ;
|
||||
|
||||
char* allocate(U32 size) ;
|
||||
void freeMem(void* addr) ;
|
||||
|
||||
char* getBuffer() const {return mBuffer;}
|
||||
U32 getBufferSize() const {return mBufferSize;}
|
||||
U32 getAllocatedSize() const {return mAlloatedSize;}
|
||||
|
||||
bool containsAddress(const char* addr) const;
|
||||
|
||||
static U32 getMaxOverhead(U32 data_buffer_size, U32 min_slot_size,
|
||||
U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
|
||||
|
||||
void dump() ;
|
||||
|
||||
private:
|
||||
U32 getPageIndex(U32 addr) ;
|
||||
U32 getBlockLevel(U32 size) ;
|
||||
U16 getPageLevel(U32 size) ;
|
||||
LLMemoryBlock* addBlock(U32 blk_idx) ;
|
||||
void popAvailBlockList(U32 blk_idx) ;
|
||||
void addToFreeSpace(LLMemoryBlock* blk) ;
|
||||
void removeFromFreeSpace(LLMemoryBlock* blk) ;
|
||||
void removeBlock(LLMemoryBlock* blk) ;
|
||||
void addToAvailBlockList(LLMemoryBlock* blk) ;
|
||||
U32 calcBlockSize(U32 slot_size);
|
||||
LLMemoryBlock* createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) ;
|
||||
|
||||
private:
|
||||
LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize
|
||||
LLMemoryBlock** mFreeSpaceList;
|
||||
LLMemoryBlock* mBlocks ; //index of blocks by address.
|
||||
|
||||
char* mBuffer ;
|
||||
U32 mBufferSize ;
|
||||
char* mDataBuffer ;
|
||||
char* mMetaBuffer ;
|
||||
U32 mMinBlockSize ;
|
||||
U32 mMinSlotSize ;
|
||||
U32 mMaxSlotSize ;
|
||||
U32 mAlloatedSize ;
|
||||
U16 mBlockLevels;
|
||||
U16 mPartitionLevels;
|
||||
|
||||
public:
|
||||
//form a linked list
|
||||
LLMemoryChunk* mNext ;
|
||||
LLMemoryChunk* mPrev ;
|
||||
} ;
|
||||
|
||||
private:
|
||||
LLPrivateMemoryPool(S32 type, U32 max_pool_size) ;
|
||||
~LLPrivateMemoryPool() ;
|
||||
|
||||
char *allocate(U32 size) ;
|
||||
void freeMem(void* addr) ;
|
||||
|
||||
void dump() ;
|
||||
U32 getTotalAllocatedSize() ;
|
||||
U32 getTotalReservedSize() {return mReservedPoolSize;}
|
||||
S32 getType() const {return mType; }
|
||||
bool isEmpty() const {return !mNumOfChunks; }
|
||||
|
||||
private:
|
||||
void lock() ;
|
||||
void unlock() ;
|
||||
S32 getChunkIndex(U32 size) ;
|
||||
LLMemoryChunk* addChunk(S32 chunk_index) ;
|
||||
bool checkSize(U32 asked_size) ;
|
||||
void removeChunk(LLMemoryChunk* chunk) ;
|
||||
U16 findHashKey(const char* addr);
|
||||
void addToHashTable(LLMemoryChunk* chunk) ;
|
||||
void removeFromHashTable(LLMemoryChunk* chunk) ;
|
||||
void rehash() ;
|
||||
bool fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) ;
|
||||
LLMemoryChunk* findChunk(const char* addr) ;
|
||||
|
||||
void destroyPool() ;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB.
|
||||
MEDIUM_ALLOCATION, //from 2KB to 512KB(exclusive), page size 32KB, max chunk size 4MB
|
||||
LARGE_ALLOCATION, //from 512KB to 4MB(inclusive), page size 64KB, max chunk size 16MB
|
||||
SUPER_ALLOCATION //allocation larger than 4MB.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
STATIC = 0 , //static pool(each alllocation stays for a long time) without threading support
|
||||
VOLATILE, //Volatile pool(each allocation stays for a very short time) without threading support
|
||||
STATIC_THREADED, //static pool with threading support
|
||||
VOLATILE_THREADED, //volatile pool with threading support
|
||||
MAX_TYPES
|
||||
}; //pool types
|
||||
|
||||
private:
|
||||
LLMutex* mMutexp ;
|
||||
U32 mMaxPoolSize;
|
||||
U32 mReservedPoolSize ;
|
||||
|
||||
LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address
|
||||
U16 mNumOfChunks ;
|
||||
U16 mHashFactor ;
|
||||
|
||||
S32 mType ;
|
||||
|
||||
class LLChunkHashElement
|
||||
{
|
||||
public:
|
||||
LLChunkHashElement() {mFirst = NULL ; mSecond = NULL ;}
|
||||
|
||||
bool add(LLMemoryChunk* chunk) ;
|
||||
void remove(LLMemoryChunk* chunk) ;
|
||||
LLMemoryChunk* findChunk(const char* addr) ;
|
||||
|
||||
bool empty() {return !mFirst && !mSecond; }
|
||||
bool full() {return mFirst && mSecond; }
|
||||
bool hasElement(LLMemoryChunk* chunk) {return mFirst == chunk || mSecond == chunk;}
|
||||
|
||||
private:
|
||||
LLMemoryChunk* mFirst ;
|
||||
LLMemoryChunk* mSecond ;
|
||||
};
|
||||
std::vector<LLChunkHashElement> mChunkHashList ;
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLPrivateMemoryPoolManager
|
||||
{
|
||||
private:
|
||||
LLPrivateMemoryPoolManager(BOOL enabled, U32 max_pool_size) ;
|
||||
~LLPrivateMemoryPoolManager() ;
|
||||
|
||||
public:
|
||||
static LLPrivateMemoryPoolManager* getInstance() ;
|
||||
static void initClass(BOOL enabled, U32 pool_size) ;
|
||||
static void destroyClass() ;
|
||||
|
||||
LLPrivateMemoryPool* newPool(S32 type) ;
|
||||
void deletePool(LLPrivateMemoryPool* pool) ;
|
||||
|
||||
private:
|
||||
std::vector<LLPrivateMemoryPool*> mPoolList ;
|
||||
U32 mMaxPrivatePoolSize;
|
||||
|
||||
static LLPrivateMemoryPoolManager* sInstance ;
|
||||
static BOOL sPrivatePoolEnabled;
|
||||
static std::vector<LLPrivateMemoryPool*> sDanglingPoolList ;
|
||||
public:
|
||||
//debug and statistics info.
|
||||
void updateStatistics() ;
|
||||
|
||||
U32 mTotalReservedSize ;
|
||||
U32 mTotalAllocatedSize ;
|
||||
|
||||
public:
|
||||
#if __DEBUG_PRIVATE_MEM__
|
||||
static char* allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) ;
|
||||
|
||||
typedef std::map<char*, std::string> mem_allocation_info_t ;
|
||||
static mem_allocation_info_t sMemAllocationTracker;
|
||||
#else
|
||||
static char* allocate(LLPrivateMemoryPool* poolp, U32 size) ;
|
||||
#endif
|
||||
static void freeMem(LLPrivateMemoryPool* poolp, void* addr) ;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
#if __DEBUG_PRIVATE_MEM__
|
||||
#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size), __FUNCTION__, __LINE__)
|
||||
#else
|
||||
#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size))
|
||||
//#define ALLOCATE_MEM(poolp, size) new char[size]
|
||||
#endif
|
||||
#define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr))
|
||||
//#define FREE_MEM(poolp, addr) delete[] addr;
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
//the below singleton is used to test the private memory pool.
|
||||
//
|
||||
#if 0
|
||||
class LL_COMMON_API LLPrivateMemoryPoolTester
|
||||
{
|
||||
private:
|
||||
LLPrivateMemoryPoolTester() ;
|
||||
~LLPrivateMemoryPoolTester() ;
|
||||
|
||||
public:
|
||||
static LLPrivateMemoryPoolTester* getInstance() ;
|
||||
static void destroy() ;
|
||||
|
||||
void run(S32 type) ;
|
||||
|
||||
private:
|
||||
void correctnessTest() ;
|
||||
void performanceTest() ;
|
||||
void fragmentationtest() ;
|
||||
|
||||
void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ;
|
||||
void testAndTime(U32 size, U32 times) ;
|
||||
|
||||
#if 0
|
||||
public:
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
void operator delete(void* addr)
|
||||
{
|
||||
sPool->freeMem(addr) ;
|
||||
}
|
||||
void* operator new[](size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
void operator delete[](void* addr)
|
||||
{
|
||||
sPool->freeMem(addr) ;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
static LLPrivateMemoryPoolTester* sInstance;
|
||||
static LLPrivateMemoryPool* sPool ;
|
||||
static LLPrivateMemoryPool* sThreadedPool ;
|
||||
};
|
||||
#if 0
|
||||
//static
|
||||
void* LLPrivateMemoryPoolTester::operator new(size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrivateMemoryPoolTester::operator delete(void* addr)
|
||||
{
|
||||
sPool->free(addr) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void* LLPrivateMemoryPoolTester::operator new[](size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrivateMemoryPoolTester::operator delete[](void* addr)
|
||||
{
|
||||
sPool->free(addr) ;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//EVENTUALLY REMOVE THESE:
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsingleton.h"
|
||||
#include "llsafehandle.h"
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -39,13 +39,11 @@
|
||||
|
||||
#include <iostream>
|
||||
#include "apr_base64.h"
|
||||
#if MESH_ENABLED
|
||||
#ifdef LL_STANDALONE
|
||||
# include <zlib.h>
|
||||
#else
|
||||
# include "zlib/zlib.h" // for davep's dirty little zip functions
|
||||
#endif
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
#if !LL_WINDOWS
|
||||
#include <netinet/in.h> // htonl & ntohl
|
||||
@@ -1999,8 +1997,6 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
|
||||
return s;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
|
||||
//dirty little zippers -- yell at davep if these are horrid
|
||||
|
||||
//return a string containing gzipped bytes of binary serialized LLSD
|
||||
@@ -2176,4 +2172,3 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
|
||||
free(result);
|
||||
return true;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
@@ -788,9 +788,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if MESH_ENABLED
|
||||
//dirty little zip functions -- yell at davep
|
||||
LL_COMMON_API std::string zip_llsd(LLSD& data);
|
||||
LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
|
||||
#endif //MESH_ENABLED
|
||||
#endif // LL_LLSDSERIALIZE_H
|
||||
|
||||
@@ -42,17 +42,17 @@ template <class Object> class LLStrider
|
||||
U8* mBytep;
|
||||
};
|
||||
U32 mSkip;
|
||||
U32 mTypeSize;
|
||||
//U32 mTypeSize;
|
||||
public:
|
||||
|
||||
LLStrider() { mObjectp = NULL; mTypeSize = mSkip = sizeof(Object); }
|
||||
LLStrider() { mObjectp = NULL; /*mTypeSize = */mSkip = sizeof(Object); }
|
||||
~LLStrider() { }
|
||||
|
||||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
|
||||
void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
|
||||
//void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
|
||||
|
||||
bool isStrided() const { return mTypeSize != mSkip; }
|
||||
//bool isStrided() const { return mTypeSize != mSkip; }
|
||||
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||
U32 getSkip() const { return mSkip; }
|
||||
Object* get() { return mObjectp; }
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
||||
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
||||
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
|
||||
void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
|
||||
/*void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
|
||||
{
|
||||
llassert_always(sizeof(Object) <= elem_size);
|
||||
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
source+=elem_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
};
|
||||
|
||||
#endif // LL_LLSTRIDER_H
|
||||
|
||||
@@ -111,7 +111,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
|
||||
// after the LLCurl::Multi::run() function exits and we actually
|
||||
// change this variable (which really SHOULD have been inside
|
||||
// the critical area of the mSignal lock)].
|
||||
llinfos << "LLThread::staticRun() Exiting: " << name << llendl;
|
||||
lldebugs << "LLThread::staticRun() Exiting: " << name << llendl;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
const S32 LL_VERSION_MAJOR = 1;
|
||||
const S32 LL_VERSION_MINOR = 6;
|
||||
const S32 LL_VERSION_PATCH = 0;
|
||||
const S32 LL_VERSION_BUILD = 2;
|
||||
const S32 LL_VERSION_BUILD = 3;
|
||||
|
||||
const char * const LL_CHANNEL = "Singularity";
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "llimagepng.h"
|
||||
#include "llimagedxt.h"
|
||||
#include "llimageworker.h"
|
||||
#include "llmemory.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// LLImage
|
||||
@@ -53,12 +54,14 @@
|
||||
//static
|
||||
std::string LLImage::sLastErrorMessage;
|
||||
LLMutex* LLImage::sMutex = NULL;
|
||||
LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ;
|
||||
|
||||
//static
|
||||
void LLImage::initClass()
|
||||
{
|
||||
sMutex = new LLMutex;
|
||||
LLImageJ2C::openDSO();
|
||||
LLImageBase::createPrivatePool() ;
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -67,6 +70,8 @@ void LLImage::cleanupClass()
|
||||
LLImageJ2C::closeDSO();
|
||||
delete sMutex;
|
||||
sMutex = NULL;
|
||||
|
||||
LLImageBase::destroyPrivatePool() ;
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -105,6 +110,25 @@ LLImageBase::~LLImageBase()
|
||||
deleteData(); // virtual
|
||||
}
|
||||
|
||||
//static
|
||||
void LLImageBase::createPrivatePool()
|
||||
{
|
||||
if(!sPrivatePoolp)
|
||||
{
|
||||
sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC_THREADED) ;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLImageBase::destroyPrivatePool()
|
||||
{
|
||||
if(sPrivatePoolp)
|
||||
{
|
||||
LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ;
|
||||
sPrivatePoolp = NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLImageBase::dump()
|
||||
{
|
||||
@@ -138,7 +162,7 @@ void LLImageBase::sanityCheck()
|
||||
// virtual
|
||||
void LLImageBase::deleteData()
|
||||
{
|
||||
delete[] mData;
|
||||
FREE_MEM(sPrivatePoolp, mData) ;
|
||||
mData = NULL;
|
||||
mDataSize = 0;
|
||||
}
|
||||
@@ -164,14 +188,14 @@ U8* LLImageBase::allocateData(S32 size)
|
||||
if (!mData || size != mDataSize)
|
||||
{
|
||||
deleteData(); // virtual
|
||||
mBadBufferAllocation = FALSE ;
|
||||
mData = new (std::nothrow) U8[size];
|
||||
mBadBufferAllocation = false ;
|
||||
mData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
|
||||
if (!mData)
|
||||
{
|
||||
llwarns << "allocate image data: " << size << llendl;
|
||||
size = 0 ;
|
||||
mWidth = mHeight = 0 ;
|
||||
mBadBufferAllocation = TRUE ;
|
||||
mBadBufferAllocation = true ;
|
||||
}
|
||||
mDataSize = size;
|
||||
}
|
||||
@@ -186,7 +210,7 @@ U8* LLImageBase::reallocateData(S32 size)
|
||||
return mData;
|
||||
|
||||
LLMemType mt1((LLMemType::EMemType)mMemType);
|
||||
U8 *new_datap = new (std::nothrow) U8[size];
|
||||
U8 *new_datap = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
|
||||
if (!new_datap)
|
||||
{
|
||||
llwarns << "Out of memory in LLImageBase::reallocateData" << llendl;
|
||||
@@ -196,7 +220,7 @@ U8* LLImageBase::reallocateData(S32 size)
|
||||
{
|
||||
S32 bytes = llmin(mDataSize, size);
|
||||
memcpy(new_datap, mData, bytes); /* Flawfinder: ignore */
|
||||
delete[] mData;
|
||||
FREE_MEM(sPrivatePoolp, mData) ;
|
||||
}
|
||||
mData = new_datap;
|
||||
mDataSize = size;
|
||||
@@ -276,11 +300,11 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
|
||||
++sRawImageCount;
|
||||
}
|
||||
|
||||
LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
|
||||
/*LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
|
||||
: LLImageBase(), mCacheEntries(0)
|
||||
{
|
||||
createFromFile(filename, j2c_lowest_mip_only);
|
||||
}
|
||||
}*/
|
||||
|
||||
LLImageRaw::~LLImageRaw()
|
||||
{
|
||||
@@ -346,10 +370,11 @@ BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
|
||||
{
|
||||
LLMemType mt1((LLMemType::EMemType)mMemType);
|
||||
U8 *data = new (std::nothrow) U8[width*height*getComponents()];
|
||||
LLMemType mt1(mMemType);
|
||||
U8 *data = new U8[width*height*getComponents()];
|
||||
|
||||
// Should do some simple bounds checking
|
||||
if (!data)
|
||||
@@ -366,6 +391,7 @@ U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
|
||||
}
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
|
||||
const U8 *data, U32 stride, BOOL reverse_y)
|
||||
@@ -856,11 +882,11 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
|
||||
delete[] temp_buffer;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
//scale down image by not blending a pixel with its neighbors.
|
||||
BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
|
||||
{
|
||||
LLMemType mt1((LLMemType::EMemType)mMemType);
|
||||
LLMemType mt1(mMemType);
|
||||
|
||||
S8 c = getComponents() ;
|
||||
llassert((1 == c) || (3 == c) || (4 == c) );
|
||||
@@ -880,7 +906,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
|
||||
ratio_x -= 1.0f ;
|
||||
ratio_y -= 1.0f ;
|
||||
|
||||
U8* new_data = new (std::nothrow) U8[new_data_size] ;
|
||||
U8* new_data = allocateMemory(new_data_size) ;
|
||||
llassert_always(new_data != NULL) ;
|
||||
|
||||
U8* old_data = getData() ;
|
||||
@@ -902,6 +928,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
|
||||
|
||||
return TRUE ;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
|
||||
{
|
||||
@@ -1222,7 +1249,7 @@ file_extensions[] =
|
||||
{ "png", IMG_CODEC_PNG }
|
||||
};
|
||||
#define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions)
|
||||
|
||||
#if 0
|
||||
static std::string find_file(std::string &name, S8 *codec)
|
||||
{
|
||||
std::string tname;
|
||||
@@ -1240,7 +1267,7 @@ static std::string find_file(std::string &name, S8 *codec)
|
||||
}
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
#endif
|
||||
EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
|
||||
{
|
||||
for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
|
||||
@@ -1250,7 +1277,7 @@ EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
|
||||
}
|
||||
return IMG_CODEC_INVALID;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only)
|
||||
{
|
||||
std::string name = filename;
|
||||
@@ -1336,7 +1363,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
//---------------------------------------------------------------------------
|
||||
// LLImageFormatted
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -1568,7 +1595,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size)
|
||||
S32 newsize = cursize + size;
|
||||
reallocateData(newsize);
|
||||
memcpy(getData() + cursize, data, size);
|
||||
delete[] data; //Fixing leak from CommentCacheReadResponder
|
||||
FREE_MEM(LLImageBase::getPrivatePool(), data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ const S32 MAX_IMG_PACKET_SIZE = 1000;
|
||||
class LLImageFormatted;
|
||||
class LLImageRaw;
|
||||
class LLColor4U;
|
||||
class LLPrivateMemoryPool;
|
||||
|
||||
typedef enum e_image_codec
|
||||
{
|
||||
@@ -144,6 +145,9 @@ public:
|
||||
|
||||
static EImageCodec getCodecFromExtension(const std::string& exten);
|
||||
|
||||
static void createPrivatePool() ;
|
||||
static void destroyPrivatePool() ;
|
||||
static LLPrivateMemoryPool* getPrivatePool() {return sPrivatePoolp;}
|
||||
private:
|
||||
U8 *mData;
|
||||
S32 mDataSize;
|
||||
@@ -155,6 +159,8 @@ private:
|
||||
|
||||
bool mBadBufferAllocation ;
|
||||
bool mAllowOverSize ;
|
||||
|
||||
static LLPrivateMemoryPool* sPrivatePoolp ;
|
||||
public:
|
||||
S16 mMemType; // debug
|
||||
};
|
||||
@@ -170,7 +176,7 @@ public:
|
||||
LLImageRaw(U16 width, U16 height, S8 components);
|
||||
LLImageRaw(U8 *data, U16 width, U16 height, S8 components);
|
||||
// Construct using createFromFile (used by tools)
|
||||
LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
|
||||
//LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
|
||||
|
||||
/*virtual*/ void deleteData();
|
||||
/*virtual*/ U8* allocateData(S32 size = -1);
|
||||
@@ -178,7 +184,7 @@ public:
|
||||
|
||||
BOOL resize(U16 width, U16 height, S8 components);
|
||||
|
||||
U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const;
|
||||
//U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const;
|
||||
BOOL setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
|
||||
const U8 *data, U32 stride = 0, BOOL reverse_y = FALSE);
|
||||
|
||||
@@ -190,7 +196,7 @@ public:
|
||||
void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
|
||||
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
|
||||
BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
|
||||
BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
|
||||
//BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
|
||||
|
||||
// Fill the buffer with a constant color
|
||||
void fill( const LLColor4U& color );
|
||||
@@ -232,7 +238,7 @@ public:
|
||||
|
||||
protected:
|
||||
// Create an image from a local file (generally used in tools)
|
||||
bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false);
|
||||
//bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false);
|
||||
|
||||
void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step );
|
||||
void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len );
|
||||
|
||||
@@ -435,7 +435,7 @@ bool LLImageDXT::convertToDXR()
|
||||
S32 nmips = calcNumMips(width,height);
|
||||
S32 total_bytes = getDataSize();
|
||||
U8* olddata = getData();
|
||||
U8* newdata = new (std::nothrow) U8[total_bytes];
|
||||
U8* newdata = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_bytes);
|
||||
if (!newdata)
|
||||
{
|
||||
llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl;
|
||||
|
||||
@@ -501,14 +501,14 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
|
||||
}
|
||||
else
|
||||
{
|
||||
U8 *data = new U8[file_size];
|
||||
U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size);
|
||||
apr_size_t bytes_read = file_size;
|
||||
apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
|
||||
infile.close() ;
|
||||
|
||||
if (s != APR_SUCCESS || (S32)bytes_read != file_size)
|
||||
{
|
||||
delete[] data;
|
||||
FREE_MEM(LLImageBase::getPrivatePool(), data);
|
||||
setLastError("Unable to read entire file");
|
||||
res = FALSE;
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
|
||||
}
|
||||
|
||||
// exportFile should be replaced with exportLegacyStream
|
||||
// not sure whether exportLegacyStream(llofstream(fp)) would work, fp may need to get icramented...
|
||||
// not sure whether exportLegacyStream(llofstream(fp)) would work, fp may need to get incremented...
|
||||
BOOL LLInventoryObject::exportFile(LLFILE* fp, BOOL) const
|
||||
{
|
||||
std::string uuid_str;
|
||||
|
||||
@@ -75,10 +75,6 @@ set(llmath_HEADER_FILES
|
||||
llvector4a.h
|
||||
llvector4a.inl
|
||||
llvector4logical.h
|
||||
llv4math.h
|
||||
llv4matrix3.h
|
||||
llv4matrix4.h
|
||||
llv4vector3.h
|
||||
llvolume.h
|
||||
llvolumemgr.h
|
||||
llvolumeoctree.h
|
||||
|
||||
@@ -60,7 +60,7 @@ inline void LLMatrix3a::setTranspose(const LLMatrix3a& src)
|
||||
const LLQuad srcCol1 = src.mColumns[1];
|
||||
const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 );
|
||||
mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] );
|
||||
mColumns[1] = _mm_shuffle_ps( _mm_movehl_ps( srcCol0, unpacklo ), src.mColumns[2], _MM_SHUFFLE(0, 1, 1, 0) );
|
||||
mColumns[1] = _mm_shuffle_ps( unpacklo, src.mColumns[2], _MM_SHUFFLE(0, 1, 3, 2) );
|
||||
mColumns[2] = _mm_shuffle_ps( _mm_unpackhi_ps( srcCol0, srcCol1 ), src.mColumns[2], _MM_SHUFFLE(0, 2, 1, 0) );
|
||||
}
|
||||
|
||||
|
||||
@@ -104,25 +104,45 @@ public:
|
||||
mMatrix[2].setAdd(a.mMatrix[2],d2);
|
||||
mMatrix[3].setAdd(a.mMatrix[3],d3);
|
||||
}
|
||||
|
||||
inline void rotate(const LLVector4a& v, LLVector4a& res)
|
||||
|
||||
//Singu Note: Don't mess with this. It's intentionally different from LL's.
|
||||
// Note how res isn't manipulated until the very end.
|
||||
inline void rotate(const LLVector4a& v, LLVector4a& res) const
|
||||
{
|
||||
res = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
res.mul(mMatrix[0]);
|
||||
|
||||
LLVector4a y;
|
||||
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
y.mul(mMatrix[1]);
|
||||
LLVector4a x,y,z;
|
||||
|
||||
LLVector4a z;
|
||||
x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
x.mul(mMatrix[0]);
|
||||
y.mul(mMatrix[1]);
|
||||
z.mul(mMatrix[2]);
|
||||
|
||||
res.add(y);
|
||||
res.add(z);
|
||||
x.add(y);
|
||||
res.setAdd(x,z);
|
||||
}
|
||||
|
||||
inline void rotate4(const LLVector4a& v, LLVector4a& res) const
|
||||
{
|
||||
LLVector4a x,y,z,w;
|
||||
|
||||
x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
w = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
x.mul(mMatrix[0]);
|
||||
y.mul(mMatrix[1]);
|
||||
z.mul(mMatrix[2]);
|
||||
w.mul(mMatrix[3]);
|
||||
|
||||
x.add(y);
|
||||
z.add(w);
|
||||
res.setAdd(x,z);
|
||||
}
|
||||
|
||||
inline void affineTransform(const LLVector4a& v, LLVector4a& res)
|
||||
inline void affineTransform(const LLVector4a& v, LLVector4a& res) const
|
||||
{
|
||||
LLVector4a x,y,z;
|
||||
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
/**
|
||||
* @file llv4math.h
|
||||
* @brief LLV4* class header file - vector processor enabled math
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLV4MATH_H
|
||||
#define LL_LLV4MATH_H
|
||||
|
||||
// *NOTE: We do not support SSE acceleration on Windows builds.
|
||||
// Our minimum specification for the viewer includes 1 GHz Athlon processors,
|
||||
// which covers the Athlon Thunderbird series that does not support SSE.
|
||||
//
|
||||
// Our header files include statements like this
|
||||
// const F32 HAVOK_TIMESTEP = 1.f / 45.f;
|
||||
// This creates "globals" that are included in each .obj file. If a single
|
||||
// .cpp file has SSE code generation turned on (eg, llviewerjointmesh_sse.cpp)
|
||||
// these globals will be initialized using SSE instructions. This causes SL
|
||||
// to crash before main() on processors without SSE. Untangling all these
|
||||
// headers/variables is too much work for the small performance gains of
|
||||
// vectorization.
|
||||
//
|
||||
// Therefore we only support vectorization on builds where the everything is
|
||||
// built with SSE or Altivec. See https://jira.secondlife.com/browse/VWR-1610
|
||||
// and https://jira.lindenlab.com/browse/SL-47720 for details.
|
||||
//
|
||||
// Sorry the code is such a mess. JC
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4MATH - GNUC
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if LL_GNUC && __GNUC__ >= 4 && __SSE__
|
||||
|
||||
#define LL_VECTORIZE 1
|
||||
|
||||
#if LL_DARWIN
|
||||
|
||||
#include <Accelerate/Accelerate.h>
|
||||
#include <xmmintrin.h>
|
||||
typedef vFloat V4F32;
|
||||
|
||||
#else
|
||||
|
||||
#include <xmmintrin.h>
|
||||
typedef float V4F32 __attribute__((vector_size(16)));
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#if LL_GNUC
|
||||
|
||||
#define LL_LLV4MATH_ALIGN_PREFIX
|
||||
#define LL_LLV4MATH_ALIGN_POSTFIX __attribute__((aligned(16)))
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4MATH - MSVC
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Only vectorize if the entire Windows build uses SSE.
|
||||
// _M_IX86_FP is set when SSE code generation is turned on, and I have
|
||||
// confirmed this in VS2003, VS2003 SP1, and VS2005. JC
|
||||
#if LL_MSVC && _M_IX86_FP
|
||||
|
||||
#define LL_VECTORIZE 1
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
typedef __m128 V4F32;
|
||||
|
||||
#endif
|
||||
#if LL_MSVC
|
||||
|
||||
#define LL_LLV4MATH_ALIGN_PREFIX __declspec(align(16))
|
||||
#define LL_LLV4MATH_ALIGN_POSTFIX
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4MATH - default - no vectorization
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if !LL_VECTORIZE
|
||||
|
||||
#define LL_VECTORIZE 0
|
||||
|
||||
struct V4F32 { F32 __pad__[4]; };
|
||||
|
||||
inline F32 llv4lerp(F32 a, F32 b, F32 w) { return ( b - a ) * w + a; }
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef LL_LLV4MATH_ALIGN_PREFIX
|
||||
# define LL_LLV4MATH_ALIGN_PREFIX
|
||||
#endif
|
||||
#ifndef LL_LLV4MATH_ALIGN_POSTFIX
|
||||
# define LL_LLV4MATH_ALIGN_POSTFIX
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4MATH
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define LLV4_NUM_AXIS 4
|
||||
|
||||
class LLV4Vector3;
|
||||
class LLV4Matrix3;
|
||||
class LLV4Matrix4;
|
||||
|
||||
#endif
|
||||
@@ -1,226 +0,0 @@
|
||||
/**
|
||||
* @file llviewerjointmesh.cpp
|
||||
* @brief LLV4* class header file - vector processor enabled math
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLV4MATRIX3_H
|
||||
#define LL_LLV4MATRIX3_H
|
||||
|
||||
#include "llv4math.h"
|
||||
#include "llv4vector3.h"
|
||||
#include "m3math.h" // for operator LLMatrix3()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LL_LLV4MATH_ALIGN_PREFIX
|
||||
|
||||
class LLV4Matrix3
|
||||
{
|
||||
public:
|
||||
union {
|
||||
F32 mMatrix[LLV4_NUM_AXIS][LLV4_NUM_AXIS];
|
||||
V4F32 mV[LLV4_NUM_AXIS];
|
||||
};
|
||||
|
||||
void lerp(const LLV4Matrix3 &a, const LLV4Matrix3 &b, const F32 &w);
|
||||
void multiply(const LLVector3 &a, LLVector3& out) const;
|
||||
void multiply(const LLVector4 &a, LLV4Vector3& out) const;
|
||||
void multiply(const LLVector3 &a, LLV4Vector3& out) const;
|
||||
|
||||
const LLV4Matrix3& transpose();
|
||||
const LLV4Matrix3& operator=(const LLMatrix3& a);
|
||||
|
||||
operator LLMatrix3() const { return (reinterpret_cast<const LLMatrix4*>(const_cast<const F32*>(&mMatrix[0][0])))->getMat3(); }
|
||||
|
||||
friend LLVector3 operator*(const LLVector3& a, const LLV4Matrix3& b);
|
||||
}
|
||||
|
||||
LL_LLV4MATH_ALIGN_POSTFIX;
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix3 - SSE
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if LL_VECTORIZE
|
||||
|
||||
inline void LLV4Matrix3::lerp(const LLV4Matrix3 &a, const LLV4Matrix3 &b, const F32 &w)
|
||||
{
|
||||
__m128 vw = _mm_set1_ps(w);
|
||||
mV[VX] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VX], a.mV[VX]), vw), a.mV[VX]); // ( b - a ) * w + a
|
||||
mV[VY] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VY], a.mV[VY]), vw), a.mV[VY]);
|
||||
mV[VZ] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VZ], a.mV[VZ]), vw), a.mV[VZ]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector3 &a, LLVector3& o) const
|
||||
{
|
||||
LLV4Vector3 j;
|
||||
j.v = _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX]); // ( ax * vx ) + ...
|
||||
j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
o.setVec(j.mV);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector4 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.v = _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX]); // ( ax * vx ) + ...
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector3 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.v = _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX]); // ( ax * vx ) + ...
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#else
|
||||
|
||||
inline void LLV4Matrix3::lerp(const LLV4Matrix3 &a, const LLV4Matrix3 &b, const F32 &w)
|
||||
{
|
||||
mMatrix[VX][VX] = llv4lerp(a.mMatrix[VX][VX], b.mMatrix[VX][VX], w);
|
||||
mMatrix[VX][VY] = llv4lerp(a.mMatrix[VX][VY], b.mMatrix[VX][VY], w);
|
||||
mMatrix[VX][VZ] = llv4lerp(a.mMatrix[VX][VZ], b.mMatrix[VX][VZ], w);
|
||||
|
||||
mMatrix[VY][VX] = llv4lerp(a.mMatrix[VY][VX], b.mMatrix[VY][VX], w);
|
||||
mMatrix[VY][VY] = llv4lerp(a.mMatrix[VY][VY], b.mMatrix[VY][VY], w);
|
||||
mMatrix[VY][VZ] = llv4lerp(a.mMatrix[VY][VZ], b.mMatrix[VY][VZ], w);
|
||||
|
||||
mMatrix[VZ][VX] = llv4lerp(a.mMatrix[VZ][VX], b.mMatrix[VZ][VX], w);
|
||||
mMatrix[VZ][VY] = llv4lerp(a.mMatrix[VZ][VY], b.mMatrix[VZ][VY], w);
|
||||
mMatrix[VZ][VZ] = llv4lerp(a.mMatrix[VZ][VZ], b.mMatrix[VZ][VZ], w);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector3 &a, LLVector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector4 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector3 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ]);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
|
||||
inline const LLV4Matrix3& LLV4Matrix3::transpose()
|
||||
{
|
||||
#if LL_VECTORIZE && defined(_MM_TRANSPOSE4_PS)
|
||||
_MM_TRANSPOSE4_PS(mV[VX], mV[VY], mV[VZ], mV[VW]);
|
||||
return *this;
|
||||
#else
|
||||
F32 temp;
|
||||
temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp;
|
||||
temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp;
|
||||
temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const LLV4Matrix3& LLV4Matrix3::operator=(const LLMatrix3& a)
|
||||
{
|
||||
memcpy(mMatrix[VX], a.mMatrix[VX], sizeof(F32) * 3 );
|
||||
memcpy(mMatrix[VY], a.mMatrix[VY], sizeof(F32) * 3 );
|
||||
memcpy(mMatrix[VZ], a.mMatrix[VZ], sizeof(F32) * 3 );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline LLVector3 operator*(const LLVector3& a, const LLV4Matrix3& b)
|
||||
{
|
||||
return LLVector3(
|
||||
a.mV[VX] * b.mMatrix[VX][VX] +
|
||||
a.mV[VY] * b.mMatrix[VY][VX] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VX],
|
||||
|
||||
a.mV[VX] * b.mMatrix[VX][VY] +
|
||||
a.mV[VY] * b.mMatrix[VY][VY] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VY],
|
||||
|
||||
a.mV[VX] * b.mMatrix[VX][VZ] +
|
||||
a.mV[VY] * b.mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VZ] );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,255 +0,0 @@
|
||||
/**
|
||||
* @file llviewerjointmesh.cpp
|
||||
* @brief LLV4* class header file - vector processor enabled math
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLV4MATRIX4_H
|
||||
#define LL_LLV4MATRIX4_H
|
||||
|
||||
#include "llv4math.h"
|
||||
#include "llv4matrix3.h" // just for operator LLV4Matrix3()
|
||||
#include "llv4vector3.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix4
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LL_LLV4MATH_ALIGN_PREFIX
|
||||
|
||||
class LLV4Matrix4
|
||||
{
|
||||
public:
|
||||
union {
|
||||
F32 mMatrix[LLV4_NUM_AXIS][LLV4_NUM_AXIS];
|
||||
V4F32 mV[LLV4_NUM_AXIS];
|
||||
};
|
||||
|
||||
void lerp(const LLV4Matrix4 &a, const LLV4Matrix4 &b, const F32 &w);
|
||||
void multiply(const LLVector3 &a, LLVector3& o) const;
|
||||
void multiply(const LLVector3 &a, LLV4Vector3& o) const;
|
||||
|
||||
const LLV4Matrix4& transpose();
|
||||
const LLV4Matrix4& translate(const LLVector3 &vec);
|
||||
const LLV4Matrix4& translate(const LLV4Vector3 &vec);
|
||||
const LLV4Matrix4& operator=(const LLMatrix4& a);
|
||||
|
||||
operator LLMatrix4() const { return *(reinterpret_cast<const LLMatrix4*>(const_cast<const F32*>(&mMatrix[0][0]))); }
|
||||
operator LLV4Matrix3() const { return *(reinterpret_cast<const LLV4Matrix3*>(const_cast<const F32*>(&mMatrix[0][0]))); }
|
||||
|
||||
friend LLVector3 operator*(const LLVector3 &a, const LLV4Matrix4 &b);
|
||||
}
|
||||
|
||||
LL_LLV4MATH_ALIGN_POSTFIX;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix4 - SSE
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if LL_VECTORIZE
|
||||
|
||||
inline void LLV4Matrix4::lerp(const LLV4Matrix4 &a, const LLV4Matrix4 &b, const F32 &w)
|
||||
{
|
||||
__m128 vw = _mm_set1_ps(w);
|
||||
mV[VX] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VX], a.mV[VX]), vw), a.mV[VX]); // ( b - a ) * w + a
|
||||
mV[VY] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VY], a.mV[VY]), vw), a.mV[VY]);
|
||||
mV[VZ] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VZ], a.mV[VZ]), vw), a.mV[VZ]);
|
||||
mV[VW] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VW], a.mV[VW]), vw), a.mV[VW]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix4::multiply(const LLVector3 &a, LLVector3& o) const
|
||||
{
|
||||
LLV4Vector3 j;
|
||||
j.v = _mm_add_ps(mV[VW], _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX])); // ( ax * vx ) + vw
|
||||
j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
o.setVec(j.mV);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix4::multiply(const LLVector3 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.v = _mm_add_ps(mV[VW], _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX])); // ( ax * vx ) + vw
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
}
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::translate(const LLV4Vector3 &vec)
|
||||
{
|
||||
mV[VW] = _mm_add_ps(mV[VW], vec.v);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix4
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#else
|
||||
|
||||
inline void LLV4Matrix4::lerp(const LLV4Matrix4 &a, const LLV4Matrix4 &b, const F32 &w)
|
||||
{
|
||||
mMatrix[VX][VX] = llv4lerp(a.mMatrix[VX][VX], b.mMatrix[VX][VX], w);
|
||||
mMatrix[VX][VY] = llv4lerp(a.mMatrix[VX][VY], b.mMatrix[VX][VY], w);
|
||||
mMatrix[VX][VZ] = llv4lerp(a.mMatrix[VX][VZ], b.mMatrix[VX][VZ], w);
|
||||
|
||||
mMatrix[VY][VX] = llv4lerp(a.mMatrix[VY][VX], b.mMatrix[VY][VX], w);
|
||||
mMatrix[VY][VY] = llv4lerp(a.mMatrix[VY][VY], b.mMatrix[VY][VY], w);
|
||||
mMatrix[VY][VZ] = llv4lerp(a.mMatrix[VY][VZ], b.mMatrix[VY][VZ], w);
|
||||
|
||||
mMatrix[VZ][VX] = llv4lerp(a.mMatrix[VZ][VX], b.mMatrix[VZ][VX], w);
|
||||
mMatrix[VZ][VY] = llv4lerp(a.mMatrix[VZ][VY], b.mMatrix[VZ][VY], w);
|
||||
mMatrix[VZ][VZ] = llv4lerp(a.mMatrix[VZ][VZ], b.mMatrix[VZ][VZ], w);
|
||||
|
||||
mMatrix[VW][VX] = llv4lerp(a.mMatrix[VW][VX], b.mMatrix[VW][VX], w);
|
||||
mMatrix[VW][VY] = llv4lerp(a.mMatrix[VW][VY], b.mMatrix[VW][VY], w);
|
||||
mMatrix[VW][VZ] = llv4lerp(a.mMatrix[VW][VZ], b.mMatrix[VW][VZ], w);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix4::multiply(const LLVector3 &a, LLVector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX] +
|
||||
mMatrix[VW][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY] +
|
||||
mMatrix[VW][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ] +
|
||||
mMatrix[VW][VZ]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix4::multiply(const LLVector3 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX] +
|
||||
mMatrix[VW][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY] +
|
||||
mMatrix[VW][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ] +
|
||||
mMatrix[VW][VZ]);
|
||||
}
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::translate(const LLV4Vector3 &vec)
|
||||
{
|
||||
mMatrix[3][0] += vec.mV[0];
|
||||
mMatrix[3][1] += vec.mV[1];
|
||||
mMatrix[3][2] += vec.mV[2];
|
||||
return (*this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix4
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::operator=(const LLMatrix4& a)
|
||||
{
|
||||
memcpy(mMatrix, a.mMatrix, sizeof(F32) * 16 );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::transpose()
|
||||
{
|
||||
#if LL_VECTORIZE && defined(_MM_TRANSPOSE4_PS)
|
||||
_MM_TRANSPOSE4_PS(mV[VX], mV[VY], mV[VZ], mV[VW]);
|
||||
#else
|
||||
LLV4Matrix4 mat;
|
||||
mat.mMatrix[0][0] = mMatrix[0][0];
|
||||
mat.mMatrix[1][0] = mMatrix[0][1];
|
||||
mat.mMatrix[2][0] = mMatrix[0][2];
|
||||
mat.mMatrix[3][0] = mMatrix[0][3];
|
||||
|
||||
mat.mMatrix[0][1] = mMatrix[1][0];
|
||||
mat.mMatrix[1][1] = mMatrix[1][1];
|
||||
mat.mMatrix[2][1] = mMatrix[1][2];
|
||||
mat.mMatrix[3][1] = mMatrix[1][3];
|
||||
|
||||
mat.mMatrix[0][2] = mMatrix[2][0];
|
||||
mat.mMatrix[1][2] = mMatrix[2][1];
|
||||
mat.mMatrix[2][2] = mMatrix[2][2];
|
||||
mat.mMatrix[3][2] = mMatrix[2][3];
|
||||
|
||||
mat.mMatrix[0][3] = mMatrix[3][0];
|
||||
mat.mMatrix[1][3] = mMatrix[3][1];
|
||||
mat.mMatrix[2][3] = mMatrix[3][2];
|
||||
mat.mMatrix[3][3] = mMatrix[3][3];
|
||||
|
||||
*this = mat;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::translate(const LLVector3 &vec)
|
||||
{
|
||||
mMatrix[3][0] += vec.mV[0];
|
||||
mMatrix[3][1] += vec.mV[1];
|
||||
mMatrix[3][2] += vec.mV[2];
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline LLVector3 operator*(const LLVector3 &a, const LLV4Matrix4 &b)
|
||||
{
|
||||
return LLVector3(a.mV[VX] * b.mMatrix[VX][VX] +
|
||||
a.mV[VY] * b.mMatrix[VY][VX] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VX] +
|
||||
b.mMatrix[VW][VX],
|
||||
|
||||
a.mV[VX] * b.mMatrix[VX][VY] +
|
||||
a.mV[VY] * b.mMatrix[VY][VY] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VY] +
|
||||
b.mMatrix[VW][VY],
|
||||
|
||||
a.mV[VX] * b.mMatrix[VX][VZ] +
|
||||
a.mV[VY] * b.mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VZ] +
|
||||
b.mMatrix[VW][VZ]);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* @file llviewerjointmesh.cpp
|
||||
* @brief LLV4* class header file - vector processor enabled math
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLV4VECTOR3_H
|
||||
#define LL_LLV4VECTOR3_H
|
||||
|
||||
#include "llv4math.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Vector3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LL_LLV4MATH_ALIGN_PREFIX
|
||||
|
||||
class LLV4Vector3
|
||||
{
|
||||
public:
|
||||
union {
|
||||
F32 mV[LLV4_NUM_AXIS];
|
||||
V4F32 v;
|
||||
};
|
||||
|
||||
enum {
|
||||
ALIGNMENT = 16
|
||||
};
|
||||
|
||||
void setVec(F32 x, F32 y, F32 z);
|
||||
void setVec(F32 a);
|
||||
}
|
||||
|
||||
LL_LLV4MATH_ALIGN_POSTFIX;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Vector3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline void LLV4Vector3::setVec(F32 x, F32 y, F32 z)
|
||||
{
|
||||
mV[VX] = x;
|
||||
mV[VY] = y;
|
||||
mV[VZ] = z;
|
||||
}
|
||||
|
||||
inline void LLV4Vector3::setVec(F32 a)
|
||||
{
|
||||
#if LL_VECTORIZE
|
||||
v = _mm_set1_ps(a);
|
||||
#else
|
||||
setVec(a, a, a);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2079,15 +2079,13 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge
|
||||
mFaceMask = 0x0;
|
||||
mDetail = detail;
|
||||
mSculptLevel = -2;
|
||||
#if MESH_ENABLED
|
||||
mIsMeshAssetLoaded = FALSE;
|
||||
mLODScaleBias.setVec(1,1,1);
|
||||
mHullPoints = NULL;
|
||||
mHullIndices = NULL;
|
||||
mNumHullPoints = 0;
|
||||
mNumHullIndices = 0;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
|
||||
// set defaults
|
||||
if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
|
||||
{
|
||||
@@ -2139,12 +2137,10 @@ LLVolume::~LLVolume()
|
||||
mProfilep = NULL;
|
||||
mVolumeFaces.clear();
|
||||
|
||||
#if MESH_ENABLED
|
||||
ll_aligned_free_16(mHullPoints);
|
||||
mHullPoints = NULL;
|
||||
ll_aligned_free_16(mHullIndices);
|
||||
mHullIndices = NULL;
|
||||
#endif //MESH_ENABLED
|
||||
}
|
||||
|
||||
BOOL LLVolume::generate()
|
||||
@@ -2406,7 +2402,6 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
|
||||
{
|
||||
//input stream is now pointing at a zlib compressed block of LLSD
|
||||
@@ -2736,7 +2731,7 @@ void LLVolume::cacheOptimize()
|
||||
mVolumeFaces[i].cacheOptimize();
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
|
||||
S32 LLVolume::getNumFaces() const
|
||||
{
|
||||
@@ -3205,12 +3200,10 @@ bool LLVolumeParams::isSculpt() const
|
||||
return mSculptID.notNull();
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
bool LLVolumeParams::isMeshSculpt() const
|
||||
{
|
||||
return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const
|
||||
{
|
||||
@@ -4320,15 +4313,25 @@ S32 LLVolume::getNumTriangleIndices() const
|
||||
}
|
||||
|
||||
|
||||
S32 LLVolume::getNumTriangles() const
|
||||
S32 LLVolume::getNumTriangles(S32* vcount) const
|
||||
{
|
||||
U32 triangle_count = 0;
|
||||
U32 vertex_count = 0;
|
||||
|
||||
for (S32 i = 0; i < getNumVolumeFaces(); ++i)
|
||||
{
|
||||
triangle_count += getVolumeFace(i).mNumIndices/3;
|
||||
const LLVolumeFace& face = getVolumeFace(i);
|
||||
triangle_count += face.mNumIndices/3;
|
||||
|
||||
vertex_count += face.mNumVertices;
|
||||
}
|
||||
|
||||
|
||||
if (vcount)
|
||||
{
|
||||
*vcount = vertex_count;
|
||||
}
|
||||
|
||||
return triangle_count;
|
||||
}
|
||||
|
||||
@@ -4357,13 +4360,11 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
||||
vertices.clear();
|
||||
normals.clear();
|
||||
|
||||
#if MESH_ENABLED
|
||||
if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
|
||||
S32 cur_index = 0;
|
||||
//for each face
|
||||
for (face_list_t::iterator iter = mVolumeFaces.begin();
|
||||
@@ -5414,9 +5415,7 @@ LLVolumeFace::LLVolumeFace() :
|
||||
mBinormals(NULL),
|
||||
mTexCoords(NULL),
|
||||
mIndices(NULL),
|
||||
#if MESH_ENABLED
|
||||
mWeights(NULL),
|
||||
#endif //MESH_ENABLED
|
||||
mOctree(NULL)
|
||||
{
|
||||
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
||||
@@ -5439,9 +5438,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
|
||||
mBinormals(NULL),
|
||||
mTexCoords(NULL),
|
||||
mIndices(NULL),
|
||||
#if MESH_ENABLED
|
||||
mWeights(NULL),
|
||||
#endif //MESH_ENABLED
|
||||
mOctree(NULL)
|
||||
{
|
||||
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
||||
@@ -5507,7 +5504,6 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
||||
mBinormals = NULL;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (src.mWeights)
|
||||
{
|
||||
allocateWeights(src.mNumVertices);
|
||||
@@ -5518,8 +5514,8 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = NULL;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
}
|
||||
|
||||
if (mNumIndices)
|
||||
{
|
||||
S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF;
|
||||
@@ -5551,10 +5547,8 @@ void LLVolumeFace::freeData()
|
||||
mIndices = NULL;
|
||||
ll_aligned_free_16(mBinormals);
|
||||
mBinormals = NULL;
|
||||
#if MESH_ENABLED
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = NULL;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
delete mOctree;
|
||||
mOctree = NULL;
|
||||
@@ -6125,13 +6119,11 @@ void LLVolumeFace::cacheOptimize()
|
||||
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
LLVector2* tc = (LLVector2*) ll_aligned_malloc_16(size);
|
||||
|
||||
#if MESH_ENABLED
|
||||
LLVector4a* wght = NULL;
|
||||
if (mWeights)
|
||||
{
|
||||
wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLVector4a* binorm = NULL;
|
||||
if (mBinormals)
|
||||
@@ -6155,12 +6147,10 @@ void LLVolumeFace::cacheOptimize()
|
||||
pos[cur_idx] = mPositions[idx];
|
||||
norm[cur_idx] = mNormals[idx];
|
||||
tc[cur_idx] = mTexCoords[idx];
|
||||
#if MESH_ENABLED
|
||||
if (mWeights)
|
||||
{
|
||||
wght[cur_idx] = mWeights[idx];
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
if (mBinormals)
|
||||
{
|
||||
binorm[cur_idx] = mBinormals[idx];
|
||||
@@ -6178,17 +6168,13 @@ void LLVolumeFace::cacheOptimize()
|
||||
ll_aligned_free_16(mPositions);
|
||||
ll_aligned_free_16(mNormals);
|
||||
ll_aligned_free_16(mTexCoords);
|
||||
#if MESH_ENABLED
|
||||
ll_aligned_free_16(mWeights);
|
||||
#endif //MESH_ENABLED
|
||||
ll_aligned_free_16(mBinormals);
|
||||
|
||||
mPositions = pos;
|
||||
mNormals = norm;
|
||||
mTexCoords = tc;
|
||||
#if MESH_ENABLED
|
||||
mWeights = wght;
|
||||
#endif //MESH_ENABLED
|
||||
mBinormals = binorm;
|
||||
|
||||
//std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
|
||||
@@ -6276,6 +6262,7 @@ void LLVolumeFace::swapData(LLVolumeFace& rhs)
|
||||
llswap(rhs.mNumVertices, mNumVertices);
|
||||
llswap(rhs.mNumIndices, mNumIndices);
|
||||
}
|
||||
|
||||
void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
|
||||
LLVolumeFace::VertexData& v1,
|
||||
LLVolumeFace::VertexData& v2,
|
||||
@@ -6971,14 +6958,11 @@ void LLVolumeFace::allocateBinormals(S32 num_verts)
|
||||
mBinormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
void LLVolumeFace::allocateWeights(S32 num_verts)
|
||||
{
|
||||
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
void LLVolumeFace::resizeIndices(S32 num_indices)
|
||||
{
|
||||
@@ -7141,9 +7125,8 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
|
||||
{
|
||||
resizeVertices(num_vertices);
|
||||
resizeIndices(num_indices);
|
||||
#if MESH_ENABLED
|
||||
|
||||
if (!volume->isMeshAssetLoaded())
|
||||
#endif //MESH_ENABLED
|
||||
{
|
||||
mEdge.resize(num_indices);
|
||||
}
|
||||
|
||||
@@ -191,21 +191,14 @@ const U8 LL_SCULPT_TYPE_SPHERE = 1;
|
||||
const U8 LL_SCULPT_TYPE_TORUS = 2;
|
||||
const U8 LL_SCULPT_TYPE_PLANE = 3;
|
||||
const U8 LL_SCULPT_TYPE_CYLINDER = 4;
|
||||
#if MESH_ENABLED
|
||||
const U8 LL_SCULPT_TYPE_MESH = 5;
|
||||
const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
|
||||
LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
|
||||
#endif //MESH_ENABLED
|
||||
#if !MESH_ENABLED
|
||||
const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER;
|
||||
#endif //!MESH_ENABLED
|
||||
|
||||
const U8 LL_SCULPT_FLAG_INVERT = 64;
|
||||
const U8 LL_SCULPT_FLAG_MIRROR = 128;
|
||||
|
||||
#if MESH_ENABLED
|
||||
const S32 LL_SCULPT_MESH_MAX_FACES = 8;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
class LLProfileParams
|
||||
{
|
||||
@@ -655,9 +648,7 @@ public:
|
||||
const LLUUID& getSculptID() const { return mSculptID; }
|
||||
const U8& getSculptType() const { return mSculptType; }
|
||||
bool isSculpt() const;
|
||||
#if MESH_ENABLED
|
||||
bool isMeshSculpt() const;
|
||||
#endif //MESH_ENABLED
|
||||
bool isMeshSculpt() const;
|
||||
BOOL isConvex() const;
|
||||
|
||||
// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
|
||||
@@ -865,9 +856,7 @@ public:
|
||||
|
||||
void resizeVertices(S32 num_verts);
|
||||
void allocateBinormals(S32 num_verts);
|
||||
#if MESH_ENABLED
|
||||
void allocateWeights(S32 num_verts);
|
||||
#endif //MESH_ENABLED
|
||||
void resizeIndices(S32 num_indices);
|
||||
void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
|
||||
|
||||
@@ -939,12 +928,10 @@ public:
|
||||
|
||||
std::vector<S32> mEdge;
|
||||
|
||||
#if MESH_ENABLED
|
||||
//list of skin weights for rigged volumes
|
||||
// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
|
||||
// mWeights.size() should be empty or match mVertices.size()
|
||||
LLVector4a* mWeights;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLOctreeNode<LLVolumeTriangle>* mOctree;
|
||||
|
||||
@@ -958,12 +945,7 @@ class LLVolume : public LLRefCount
|
||||
{
|
||||
friend class LLVolumeLODGroup;
|
||||
|
||||
#if MESH_ENABLED
|
||||
protected:
|
||||
#endif //MESH_ENABLED
|
||||
#if !MESH_ENABLED
|
||||
private:
|
||||
#endif //!MESH_ENABLED
|
||||
LLVolume(const LLVolume&); // Don't implement
|
||||
~LLVolume(); // use unref
|
||||
|
||||
@@ -1016,7 +998,7 @@ public:
|
||||
S32 getNumTriangleIndices() const;
|
||||
static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts);
|
||||
|
||||
S32 getNumTriangles() const;
|
||||
S32 getNumTriangles(S32* vcount = NULL) const;
|
||||
|
||||
void generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
||||
std::vector<LLVector3> &normals,
|
||||
@@ -1081,37 +1063,32 @@ private:
|
||||
protected:
|
||||
BOOL generate();
|
||||
void createVolumeFaces();
|
||||
#if MESH_ENABLED
|
||||
public:
|
||||
virtual bool unpackVolumeFaces(std::istream& is, S32 size);
|
||||
|
||||
virtual void setMeshAssetLoaded(BOOL loaded);
|
||||
virtual BOOL isMeshAssetLoaded();
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
protected:
|
||||
BOOL mUnique;
|
||||
F32 mDetail;
|
||||
S32 mSculptLevel;
|
||||
#if MESH_ENABLED
|
||||
BOOL mIsMeshAssetLoaded;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLVolumeParams mParams;
|
||||
LLPath *mPathp;
|
||||
LLProfile *mProfilep;
|
||||
std::vector<Point> mMesh;
|
||||
|
||||
|
||||
BOOL mGenerateSingleFace;
|
||||
typedef std::vector<LLVolumeFace> face_list_t;
|
||||
face_list_t mVolumeFaces;
|
||||
|
||||
#if MESH_ENABLED
|
||||
|
||||
public:
|
||||
LLVector4a* mHullPoints;
|
||||
U16* mHullIndices;
|
||||
S32 mNumHullPoints;
|
||||
S32 mNumHullIndices;
|
||||
#endif //MESH_ENABLED
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
|
||||
|
||||
@@ -154,7 +154,7 @@ void LLVolumeMgr::unrefVolume(LLVolume *volumep)
|
||||
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
|
||||
if( iter == mVolumeLODGroups.end() )
|
||||
{
|
||||
llwarns << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
|
||||
llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
|
||||
if (mDataMutex)
|
||||
{
|
||||
mDataMutex->unlock();
|
||||
|
||||
@@ -74,6 +74,7 @@ BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, c
|
||||
return (grt & 0x7) ? false : true;
|
||||
}
|
||||
|
||||
|
||||
LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node)
|
||||
{
|
||||
node->addListener(this);
|
||||
|
||||
@@ -39,13 +39,10 @@
|
||||
const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f
|
||||
const F32 MIN_OBJECT_Z = -256.f;
|
||||
const F32 DEFAULT_MAX_PRIM_SCALE = 256.f;
|
||||
#if MESH_ENABLED
|
||||
const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = DEFAULT_MAX_PRIM_SCALE;
|
||||
#endif //MESH_ENABLED
|
||||
const F32 MIN_PRIM_SCALE = 0.01f;
|
||||
const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX
|
||||
|
||||
|
||||
class LLXform
|
||||
{
|
||||
protected:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -90,7 +90,7 @@ int LLPluginInstance::load(std::string &plugin_file)
|
||||
#if LL_LINUX && defined(LL_STANDALONE)
|
||||
void *dso_handle = dlopen(plugin_file.c_str(), RTLD_NOW | RTLD_GLOBAL);
|
||||
int result = (!dso_handle)?APR_EDSOOPEN:apr_os_dso_handle_put(&mDSOHandle,
|
||||
dso_handle, AIAPRRootPool::get()());
|
||||
dso_handle, LLAPRRootPool::get()());
|
||||
#else
|
||||
int result = apr_dso_load(&mDSOHandle,
|
||||
plugin_file.c_str(),
|
||||
|
||||
@@ -277,6 +277,14 @@ LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl()
|
||||
|
||||
bool LLPluginSharedMemory::map(void)
|
||||
{
|
||||
llassert(mSize);
|
||||
if (!mSize)
|
||||
{
|
||||
LL_DEBUGS("Plugin") << "Tried to mmap zero length" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
llassert(mImpl->mSharedMemoryFD != -1);
|
||||
llassert(fcntl(mImpl->mSharedMemoryFD, F_GETFL) != -1);
|
||||
mMappedAddress = ::mmap(NULL, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, mImpl->mSharedMemoryFD, 0);
|
||||
if(mMappedAddress == NULL)
|
||||
{
|
||||
|
||||
@@ -82,10 +82,6 @@ if (DARWIN)
|
||||
)
|
||||
endif (DARWIN)
|
||||
|
||||
if (LINUX)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lrt")
|
||||
endif (LINUX)
|
||||
|
||||
if (WINDOWS)
|
||||
set_target_properties(SLPlugin
|
||||
PROPERTIES
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#if MESH_ENABLED
|
||||
#include "llmodel.h"
|
||||
#include "llmemory.h"
|
||||
#if MESH_IMPORT
|
||||
@@ -1020,16 +1019,10 @@ void LLModel::setVolumeFaceData(
|
||||
face.resizeVertices(num_verts);
|
||||
face.resizeIndices(num_indices);
|
||||
|
||||
if(!pos.isStrided())
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32));
|
||||
else
|
||||
for(U32 i=0;i<num_verts;++i) face.mPositions[i].load3(pos[i].mV);
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32));
|
||||
if (norm.get())
|
||||
{
|
||||
if(!norm.isStrided())
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
|
||||
else
|
||||
for(U32 i=0;i<num_verts;++i) face.mNormals[i].load3(norm[i].mV);
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1039,10 +1032,7 @@ void LLModel::setVolumeFaceData(
|
||||
|
||||
if (tc.get())
|
||||
{
|
||||
if(!tc.isStrided())
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
|
||||
else
|
||||
for(U32 i=0;i<num_verts;++i) face.mTexCoords[i] = tc[i].mV;
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2471,4 +2461,4 @@ void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs)
|
||||
mPhysicsShapeMesh = rhs->mPhysicsShapeMesh;
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
|
||||
@@ -109,10 +109,8 @@ public:
|
||||
PARAMS_LIGHT = 0x20,
|
||||
PARAMS_SCULPT = 0x30,
|
||||
PARAMS_LIGHT_IMAGE = 0x40,
|
||||
#if MESH_ENABLED
|
||||
PARAMS_RESERVED = 0x50, // Used on server-side
|
||||
PARAMS_MESH = 0x60,
|
||||
#endif //MESH_ENABLED
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
@@ -174,8 +174,8 @@ void LLTextureAnim::unpackTAMessage(LLDataPacker &dp)
|
||||
|
||||
mMode = data[0];
|
||||
mFace = data[1];
|
||||
mSizeX = llmax((U8)1, data[2]);
|
||||
mSizeY = llmax((U8)1, data[3]);
|
||||
mSizeX = data[2];
|
||||
mSizeY = data[3];
|
||||
htonmemcpy(&mStart, data + 4, MVT_F32, sizeof(F32));
|
||||
htonmemcpy(&mLength, data + 8, MVT_F32, sizeof(F32));
|
||||
htonmemcpy(&mRate, data + 12, MVT_F32, sizeof(F32));
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "m4math.h"
|
||||
|
||||
#include "llrender.h"
|
||||
#include "llglslshader.h"
|
||||
|
||||
#include "llglheaders.h"
|
||||
|
||||
@@ -201,7 +202,7 @@ void LLCubeMap::enableTexture(S32 stage)
|
||||
void LLCubeMap::enableTextureCoords(S32 stage)
|
||||
{
|
||||
mTextureCoordStage = stage;
|
||||
if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
|
||||
if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
|
||||
{
|
||||
if (stage > 0)
|
||||
{
|
||||
@@ -243,7 +244,7 @@ void LLCubeMap::disableTexture(void)
|
||||
|
||||
void LLCubeMap::disableTextureCoords(void)
|
||||
{
|
||||
if (gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
|
||||
if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
|
||||
{
|
||||
if (mTextureCoordStage > 0)
|
||||
{
|
||||
@@ -265,47 +266,47 @@ void LLCubeMap::setMatrix(S32 stage)
|
||||
|
||||
if (mMatrixStage < 0) return;
|
||||
|
||||
//if (stage > 0)
|
||||
if (stage > 0)
|
||||
{
|
||||
gGL.getTexUnit(stage)->activate();
|
||||
}
|
||||
|
||||
LLVector3 x(LLVector3d(gGLModelView+0));
|
||||
LLVector3 y(LLVector3d(gGLModelView+4));
|
||||
LLVector3 z(LLVector3d(gGLModelView+8));
|
||||
LLVector3 x(gGLModelView+0);
|
||||
LLVector3 y(gGLModelView+4);
|
||||
LLVector3 z(gGLModelView+8);
|
||||
|
||||
LLMatrix3 mat3;
|
||||
mat3.setRows(x,y,z);
|
||||
LLMatrix4 trans(mat3);
|
||||
trans.transpose();
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPushMatrix();
|
||||
glLoadMatrixf((F32 *)trans.mMatrix);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
gGL.matrixMode(LLRender::MM_TEXTURE);
|
||||
gGL.pushMatrix();
|
||||
gGL.loadMatrix((F32 *)trans.mMatrix);
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
|
||||
/*if (stage > 0)
|
||||
if (stage > 0)
|
||||
{
|
||||
gGL.getTexUnit(0)->activate();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
void LLCubeMap::restoreMatrix()
|
||||
{
|
||||
if (mMatrixStage < 0) return;
|
||||
|
||||
//if (mMatrixStage > 0)
|
||||
if (mMatrixStage > 0)
|
||||
{
|
||||
gGL.getTexUnit(mMatrixStage)->activate();
|
||||
}
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
gGL.matrixMode(LLRender::MM_TEXTURE);
|
||||
gGL.popMatrix();
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
|
||||
/*if (mMatrixStage > 0)
|
||||
if (mMatrixStage > 0)
|
||||
{
|
||||
gGL.getTexUnit(0)->activate();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
void LLCubeMap::setReflection (void)
|
||||
|
||||
@@ -83,48 +83,12 @@ F32 llfont_round_y(F32 y)
|
||||
return y;
|
||||
}
|
||||
|
||||
// static
|
||||
U8 LLFontGL::getStyleFromString(const std::string &style)
|
||||
{
|
||||
S32 ret = 0;
|
||||
if (style.find("NORMAL") != style.npos)
|
||||
{
|
||||
ret |= NORMAL;
|
||||
}
|
||||
if (style.find("BOLD") != style.npos)
|
||||
{
|
||||
ret |= BOLD;
|
||||
}
|
||||
if (style.find("ITALIC") != style.npos)
|
||||
{
|
||||
ret |= ITALIC;
|
||||
}
|
||||
if (style.find("UNDERLINE") != style.npos)
|
||||
{
|
||||
ret |= UNDERLINE;
|
||||
}
|
||||
if (style.find("SHADOW") != style.npos)
|
||||
{
|
||||
ret |= DROP_SHADOW;
|
||||
}
|
||||
if (style.find("SOFT_SHADOW") != style.npos)
|
||||
{
|
||||
ret |= DROP_SHADOW_SOFT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
LLFontGL::LLFontGL()
|
||||
: LLFont()
|
||||
{
|
||||
clearEmbeddedChars();
|
||||
}
|
||||
|
||||
LLFontGL::LLFontGL(const LLFontGL &source)
|
||||
{
|
||||
llerrs << "Not implemented!" << llendl;
|
||||
}
|
||||
|
||||
LLFontGL::~LLFontGL()
|
||||
{
|
||||
clearEmbeddedChars();
|
||||
@@ -153,60 +117,6 @@ void LLFontGL::reset()
|
||||
resetBitmapCache();
|
||||
}
|
||||
|
||||
// static
|
||||
std::string LLFontGL::getFontPathSystem()
|
||||
{
|
||||
std::string system_path;
|
||||
|
||||
// Try to figure out where the system's font files are stored.
|
||||
char *system_root = NULL;
|
||||
#if LL_WINDOWS
|
||||
system_root = getenv("SystemRoot"); /* Flawfinder: ignore */
|
||||
if (!system_root)
|
||||
{
|
||||
llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (system_root)
|
||||
{
|
||||
system_path = llformat("%s/fonts/", system_root);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
// HACK for windows 98/Me
|
||||
system_path = "/WINDOWS/FONTS/";
|
||||
#elif LL_DARWIN
|
||||
// HACK for Mac OS X
|
||||
system_path = "/System/Library/Fonts/";
|
||||
#endif
|
||||
}
|
||||
return system_path;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
std::string LLFontGL::getFontPathLocal()
|
||||
{
|
||||
std::string local_path;
|
||||
|
||||
// Backup files if we can't load from system fonts directory.
|
||||
// We could store this in an end-user writable directory to allow
|
||||
// end users to switch fonts.
|
||||
if (LLFontGL::sAppDir.length())
|
||||
{
|
||||
// use specified application dir to look for fonts
|
||||
local_path = LLFontGL::sAppDir + "/fonts/";
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume working directory is executable directory
|
||||
local_path = "./fonts/";
|
||||
}
|
||||
return local_path;
|
||||
}
|
||||
|
||||
bool findOrCreateFont(LLFontGL*& fontp, const LLFontDescriptor& desc)
|
||||
{
|
||||
// Don't delete existing fonts, if any, here, because they've
|
||||
@@ -215,86 +125,13 @@ bool findOrCreateFont(LLFontGL*& fontp, const LLFontDescriptor& desc)
|
||||
return (fontp != NULL);
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
|
||||
const std::string& app_dir,
|
||||
const std::vector<std::string>& xui_paths,
|
||||
bool create_gl_textures)
|
||||
{
|
||||
bool succ = true;
|
||||
sVertDPI = (F32)llfloor(screen_dpi * y_scale);
|
||||
sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
|
||||
sScaleX = x_scale;
|
||||
sScaleY = y_scale;
|
||||
sAppDir = app_dir;
|
||||
|
||||
// Font registry init
|
||||
if (!sFontRegistry)
|
||||
{
|
||||
sFontRegistry = new LLFontRegistry(xui_paths,create_gl_textures);
|
||||
sFontRegistry->parseFontInfo("fonts.xml");
|
||||
}
|
||||
else
|
||||
{
|
||||
sFontRegistry->reset();
|
||||
}
|
||||
|
||||
// Force standard fonts to get generated up front.
|
||||
// This is primarily for error detection purposes.
|
||||
succ &= (NULL != getFontSansSerifSmall());
|
||||
succ &= (NULL != getFontSansSerif());
|
||||
succ &= (NULL != getFontSansSerifBig());
|
||||
succ &= (NULL != getFontSansSerifHuge());
|
||||
succ &= (NULL != getFontSansSerifBold());
|
||||
succ &= (NULL != getFontMonospace());
|
||||
succ &= (NULL != getFontExtChar());
|
||||
|
||||
return succ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// static
|
||||
void LLFontGL::destroyDefaultFonts()
|
||||
{
|
||||
// Remove the actual fonts.
|
||||
delete sFontRegistry;
|
||||
sFontRegistry = NULL;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFontGL::destroyAllGL()
|
||||
{
|
||||
if (sFontRegistry)
|
||||
{
|
||||
if (LLFont::sOpenGLcrashOnRestart)
|
||||
{
|
||||
// This will leak memory but will prevent a crash...
|
||||
sFontRegistry = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sFontRegistry->destroyGL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontGL::destroyGL()
|
||||
{
|
||||
mFontBitmapCachep->destroyGL();
|
||||
}
|
||||
|
||||
|
||||
|
||||
LLFontGL &LLFontGL::operator=(const LLFontGL &source)
|
||||
{
|
||||
llerrs << "Not implemented" << llendl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOL LLFontGL::loadFace(const std::string& filename,
|
||||
const F32 point_size, const F32 vert_dpi, const F32 horz_dpi,
|
||||
const S32 components, BOOL is_fallback)
|
||||
BOOL LLFontGL::loadFace(const std::string& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback)
|
||||
{
|
||||
if (!LLFont::loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback))
|
||||
{
|
||||
@@ -303,53 +140,6 @@ BOOL LLFontGL::loadFace(const std::string& filename,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontMonospace()
|
||||
{
|
||||
return getFont(LLFontDescriptor("Monospace","Monospace",0));
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifSmall()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Small",0));
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerif()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Medium",0));
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifBig()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Large",0));
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifHuge()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Huge",0));
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifBold()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Medium",BOLD));
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontExtChar()
|
||||
{
|
||||
return getFontSansSerif();
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc)
|
||||
{
|
||||
return sFontRegistry->getFont(desc);
|
||||
}
|
||||
|
||||
BOOL LLFontGL::addChar(const llwchar wch) const
|
||||
{
|
||||
@@ -368,30 +158,33 @@ BOOL LLFontGL::addChar(const llwchar wch) const
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, const S32 offset,
|
||||
const F32 x, const F32 y,
|
||||
const LLColor4 &color,
|
||||
const HAlign halign, const VAlign valign,
|
||||
U8 style,
|
||||
const S32 max_chars, const S32 max_pixels,
|
||||
F32* right_x,
|
||||
BOOL use_ellipses) const
|
||||
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
|
||||
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_embedded, BOOL use_ellipses) const
|
||||
{
|
||||
LLWString wstr = utf8str_to_wstring(text);
|
||||
return render(wstr, offset, x, y, color, halign, valign, style, max_chars, max_pixels, right_x, FALSE, use_ellipses);
|
||||
F32 x = rect.mLeft;
|
||||
F32 y = 0.f;
|
||||
|
||||
switch(valign)
|
||||
{
|
||||
case TOP:
|
||||
y = rect.mTop;
|
||||
break;
|
||||
case VCENTER:
|
||||
y = rect.getCenterY();
|
||||
break;
|
||||
case BASELINE:
|
||||
case BOTTOM:
|
||||
y = rect.mBottom;
|
||||
break;
|
||||
default:
|
||||
y = rect.mBottom;
|
||||
break;
|
||||
}
|
||||
return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_embedded, use_ellipses);
|
||||
}
|
||||
|
||||
S32 LLFontGL::render(const LLWString &wstr,
|
||||
const S32 begin_offset,
|
||||
const F32 x, const F32 y,
|
||||
const LLColor4 &color,
|
||||
const HAlign halign, const VAlign valign,
|
||||
U8 style,
|
||||
const S32 max_chars, S32 max_pixels,
|
||||
F32* right_x,
|
||||
BOOL use_embedded,
|
||||
BOOL use_ellipses) const
|
||||
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
|
||||
ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_embedded, BOOL use_ellipses) const
|
||||
{
|
||||
if(!sDisplayFont) //do not display texts
|
||||
{
|
||||
@@ -411,19 +204,19 @@ S32 LLFontGL::render(const LLWString &wstr,
|
||||
style = style & (~getFontDesc().getStyle());
|
||||
|
||||
F32 drop_shadow_strength = 0.f;
|
||||
if (style & (DROP_SHADOW | DROP_SHADOW_SOFT))
|
||||
if (shadow != NO_SHADOW)
|
||||
{
|
||||
F32 luminance;
|
||||
color.calcHSL(NULL, NULL, &luminance);
|
||||
drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
|
||||
if (luminance < 0.35f)
|
||||
{
|
||||
style = style & ~(DROP_SHADOW | DROP_SHADOW_SOFT);
|
||||
shadow = NO_SHADOW;
|
||||
}
|
||||
}
|
||||
|
||||
gGL.pushMatrix();
|
||||
glLoadIdentity();
|
||||
gGL.loadIdentity();
|
||||
gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
|
||||
|
||||
// this code snaps the text origin to a pixel grid to start with
|
||||
@@ -557,19 +350,19 @@ S32 LLFontGL::render(const LLWString &wstr,
|
||||
|
||||
LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
|
||||
LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);
|
||||
drawGlyph(screen_rect, uv_rect, LLColor4::white, style, drop_shadow_strength);
|
||||
drawGlyph(screen_rect, uv_rect, LLColor4::white, style, shadow, drop_shadow_strength);
|
||||
|
||||
if (!label.empty())
|
||||
{
|
||||
gGL.pushMatrix();
|
||||
//glLoadIdentity();
|
||||
//gGL.loadIdentity();
|
||||
//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
|
||||
//glScalef(sScaleX, sScaleY, 1.f);
|
||||
//gGL.scalef(sScaleX, sScaleY, 1.f);
|
||||
getFontExtChar()->render(label, 0,
|
||||
/*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX),
|
||||
/*llfloor*/(cur_y / sScaleY),
|
||||
color,
|
||||
halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
|
||||
halign, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL,
|
||||
TRUE );
|
||||
gGL.popMatrix();
|
||||
}
|
||||
@@ -623,7 +416,7 @@ S32 LLFontGL::render(const LLWString &wstr,
|
||||
llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
|
||||
llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
|
||||
|
||||
drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength);
|
||||
drawGlyph(screen_rect, uv_rect, color, style, shadow, drop_shadow_strength);
|
||||
|
||||
chars_drawn++;
|
||||
cur_x += fgi->mXAdvance;
|
||||
@@ -672,15 +465,16 @@ S32 LLFontGL::render(const LLWString &wstr,
|
||||
// recursively render ellipses at end of string
|
||||
// we've already reserved enough room
|
||||
gGL.pushMatrix();
|
||||
//glLoadIdentity();
|
||||
//gGL.loadIdentity();
|
||||
//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
|
||||
//glScalef(sScaleX, sScaleY, 1.f);
|
||||
//gGL.scalef(sScaleX, sScaleY, 1.f);
|
||||
renderUTF8(std::string("..."),
|
||||
0,
|
||||
cur_x / sScaleX, (F32)y,
|
||||
color,
|
||||
LEFT, valign,
|
||||
style,
|
||||
LLFontGL::NO_SHADOW,
|
||||
S32_MAX, max_pixels,
|
||||
right_x,
|
||||
FALSE);
|
||||
@@ -692,6 +486,25 @@ S32 LLFontGL::render(const LLWString &wstr,
|
||||
return chars_drawn;
|
||||
}
|
||||
|
||||
S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const
|
||||
{
|
||||
return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
}
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
|
||||
{
|
||||
return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses);
|
||||
}
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const
|
||||
{
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
}
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const
|
||||
{
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
}
|
||||
|
||||
S32 LLFontGL::getWidth(const std::string& utf8text) const
|
||||
{
|
||||
@@ -781,7 +594,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S
|
||||
|
||||
// Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
|
||||
S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars,
|
||||
BOOL end_on_word_boundary, const BOOL use_embedded,
|
||||
EWordWrapStyle end_on_word_boundary, const BOOL use_embedded,
|
||||
F32* drawn_pixels) const
|
||||
{
|
||||
if (!wchars || !wchars[0] || max_chars == 0)
|
||||
@@ -882,10 +695,27 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
|
||||
drawn_x = cur_x;
|
||||
}
|
||||
|
||||
if( clip && end_on_word_boundary && (start_of_last_word != 0) )
|
||||
|
||||
if( clip )
|
||||
{
|
||||
i = start_of_last_word;
|
||||
switch (end_on_word_boundary)
|
||||
{
|
||||
case ONLY_WORD_BOUNDARIES:
|
||||
i = start_of_last_word;
|
||||
break;
|
||||
case WORD_BOUNDARY_IF_POSSIBLE:
|
||||
if (start_of_last_word != 0)
|
||||
{
|
||||
i = start_of_last_word;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case ANYWHERE:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (drawn_pixels)
|
||||
{
|
||||
*drawn_pixels = drawn_x;
|
||||
@@ -1101,100 +931,115 @@ void LLFontGL::removeEmbeddedChar( llwchar wc ) const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const
|
||||
// static
|
||||
void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector<std::string>& xui_paths, bool create_gl_textures)
|
||||
{
|
||||
gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
|
||||
gGL.vertex2f(llfont_round_x(screen_rect.mRight),
|
||||
llfont_round_y(screen_rect.mTop));
|
||||
sVertDPI = (F32)llfloor(screen_dpi * y_scale);
|
||||
sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
|
||||
sScaleX = x_scale;
|
||||
sScaleY = y_scale;
|
||||
sAppDir = app_dir;
|
||||
|
||||
gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
|
||||
gGL.vertex2f(llfont_round_x(screen_rect.mLeft),
|
||||
llfont_round_y(screen_rect.mTop));
|
||||
|
||||
gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
|
||||
gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt),
|
||||
llfont_round_y(screen_rect.mBottom));
|
||||
|
||||
gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
|
||||
gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt),
|
||||
llfont_round_y(screen_rect.mBottom));
|
||||
}
|
||||
|
||||
void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, F32 drop_shadow_strength) const
|
||||
{
|
||||
F32 slant_offset;
|
||||
slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f);
|
||||
|
||||
gGL.begin(LLRender::QUADS);
|
||||
// Font registry init
|
||||
if (!sFontRegistry)
|
||||
{
|
||||
//FIXME: bold and drop shadow are mutually exclusive only for convenience
|
||||
//Allow both when we need them.
|
||||
if (style & BOLD)
|
||||
{
|
||||
gGL.color4fv(color.mV);
|
||||
for (S32 pass = 0; pass < 2; pass++)
|
||||
{
|
||||
LLRectf screen_rect_offset = screen_rect;
|
||||
|
||||
screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
|
||||
renderQuad(screen_rect_offset, uv_rect, slant_offset);
|
||||
}
|
||||
}
|
||||
else if (style & DROP_SHADOW_SOFT)
|
||||
{
|
||||
LLColor4 shadow_color = LLFontGL::sShadowColor;
|
||||
shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH;
|
||||
gGL.color4fv(shadow_color.mV);
|
||||
for (S32 pass = 0; pass < 5; pass++)
|
||||
{
|
||||
LLRectf screen_rect_offset = screen_rect;
|
||||
|
||||
switch(pass)
|
||||
{
|
||||
case 0:
|
||||
screen_rect_offset.translate(-1.f, -1.f);
|
||||
break;
|
||||
case 1:
|
||||
screen_rect_offset.translate(1.f, -1.f);
|
||||
break;
|
||||
case 2:
|
||||
screen_rect_offset.translate(1.f, 1.f);
|
||||
break;
|
||||
case 3:
|
||||
screen_rect_offset.translate(-1.f, 1.f);
|
||||
break;
|
||||
case 4:
|
||||
screen_rect_offset.translate(0, -2.f);
|
||||
break;
|
||||
}
|
||||
|
||||
renderQuad(screen_rect_offset, uv_rect, slant_offset);
|
||||
}
|
||||
gGL.color4fv(color.mV);
|
||||
renderQuad(screen_rect, uv_rect, slant_offset);
|
||||
}
|
||||
else if (style & DROP_SHADOW)
|
||||
{
|
||||
LLColor4 shadow_color = LLFontGL::sShadowColor;
|
||||
shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
|
||||
gGL.color4fv(shadow_color.mV);
|
||||
LLRectf screen_rect_shadow = screen_rect;
|
||||
screen_rect_shadow.translate(1.f, -1.f);
|
||||
renderQuad(screen_rect_shadow, uv_rect, slant_offset);
|
||||
gGL.color4fv(color.mV);
|
||||
renderQuad(screen_rect, uv_rect, slant_offset);
|
||||
}
|
||||
else // normal rendering
|
||||
{
|
||||
gGL.color4fv(color.mV);
|
||||
renderQuad(screen_rect, uv_rect, slant_offset);
|
||||
}
|
||||
|
||||
sFontRegistry = new LLFontRegistry(xui_paths,create_gl_textures);
|
||||
sFontRegistry->parseFontInfo("fonts.xml");
|
||||
}
|
||||
else
|
||||
{
|
||||
sFontRegistry->reset();
|
||||
}
|
||||
gGL.end();
|
||||
}
|
||||
|
||||
// Force standard fonts to get generated up front.
|
||||
// This is primarily for error detection purposes.
|
||||
// Don't do this during initClass because it can be slow and we want to get
|
||||
// the viewer window on screen first. JC
|
||||
// static
|
||||
bool LLFontGL::loadDefaultFonts()
|
||||
{
|
||||
bool succ = true;
|
||||
succ &= (NULL != getFontSansSerifSmall());
|
||||
succ &= (NULL != getFontSansSerif());
|
||||
succ &= (NULL != getFontSansSerifBig());
|
||||
succ &= (NULL != getFontSansSerifHuge());
|
||||
succ &= (NULL != getFontSansSerifBold());
|
||||
succ &= (NULL != getFontMonospace());
|
||||
succ &= (NULL != getFontExtChar());
|
||||
return succ;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFontGL::destroyDefaultFonts()
|
||||
{
|
||||
// Remove the actual fonts.
|
||||
delete sFontRegistry;
|
||||
sFontRegistry = NULL;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFontGL::destroyAllGL()
|
||||
{
|
||||
if (sFontRegistry)
|
||||
{
|
||||
if (LLFont::sOpenGLcrashOnRestart)
|
||||
{
|
||||
// This will leak memory but will prevent a crash...
|
||||
sFontRegistry = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sFontRegistry->destroyGL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
U8 LLFontGL::getStyleFromString(const std::string &style)
|
||||
{
|
||||
S32 ret = 0;
|
||||
if (style.find("NORMAL") != style.npos)
|
||||
{
|
||||
ret |= NORMAL;
|
||||
}
|
||||
if (style.find("BOLD") != style.npos)
|
||||
{
|
||||
ret |= BOLD;
|
||||
}
|
||||
if (style.find("ITALIC") != style.npos)
|
||||
{
|
||||
ret |= ITALIC;
|
||||
}
|
||||
if (style.find("UNDERLINE") != style.npos)
|
||||
{
|
||||
ret |= UNDERLINE;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// static
|
||||
std::string LLFontGL::getStringFromStyle(U8 style)
|
||||
{
|
||||
std::string style_string;
|
||||
if (style & NORMAL)
|
||||
{
|
||||
style_string += "|NORMAL";
|
||||
}
|
||||
if (style & BOLD)
|
||||
{
|
||||
style_string += "|BOLD";
|
||||
}
|
||||
if (style & ITALIC)
|
||||
{
|
||||
style_string += "|ITALIC";
|
||||
}
|
||||
if (style & UNDERLINE)
|
||||
{
|
||||
style_string += "|UNDERLINE";
|
||||
}
|
||||
return style_string;
|
||||
}
|
||||
std::string LLFontGL::nameFromFont(const LLFontGL* fontp)
|
||||
{
|
||||
return fontp->getFontDesc().getName();
|
||||
@@ -1262,3 +1107,214 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
|
||||
//else leave baseline
|
||||
return gl_vfont_align;
|
||||
}
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontMonospace()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("Monospace","Monospace",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifSmall()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerif()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifBig()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifHuge()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifBold()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",BOLD));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontExtChar()
|
||||
{
|
||||
return getFontSansSerif();
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc)
|
||||
{
|
||||
return sFontRegistry->getFont(desc);
|
||||
}
|
||||
|
||||
// static
|
||||
std::string LLFontGL::getFontPathSystem()
|
||||
{
|
||||
std::string system_path;
|
||||
|
||||
// Try to figure out where the system's font files are stored.
|
||||
char *system_root = NULL;
|
||||
#if LL_WINDOWS
|
||||
system_root = getenv("SystemRoot"); /* Flawfinder: ignore */
|
||||
if (!system_root)
|
||||
{
|
||||
llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (system_root)
|
||||
{
|
||||
system_path = llformat("%s/fonts/", system_root);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
// HACK for windows 98/Me
|
||||
system_path = "/WINDOWS/FONTS/";
|
||||
#elif LL_DARWIN
|
||||
// HACK for Mac OS X
|
||||
system_path = "/System/Library/Fonts/";
|
||||
#endif
|
||||
}
|
||||
return system_path;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
std::string LLFontGL::getFontPathLocal()
|
||||
{
|
||||
std::string local_path;
|
||||
|
||||
// Backup files if we can't load from system fonts directory.
|
||||
// We could store this in an end-user writable directory to allow
|
||||
// end users to switch fonts.
|
||||
if (LLFontGL::sAppDir.length())
|
||||
{
|
||||
// use specified application dir to look for fonts
|
||||
local_path = LLFontGL::sAppDir + "/fonts/";
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume working directory is executable directory
|
||||
local_path = "./fonts/";
|
||||
}
|
||||
return local_path;
|
||||
}
|
||||
|
||||
LLFontGL::LLFontGL(const LLFontGL &source)
|
||||
{
|
||||
llerrs << "Not implemented!" << llendl;
|
||||
}
|
||||
|
||||
LLFontGL &LLFontGL::operator=(const LLFontGL &source)
|
||||
{
|
||||
llerrs << "Not implemented" << llendl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const
|
||||
{
|
||||
gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
|
||||
gGL.vertex2f(llfont_round_x(screen_rect.mRight),
|
||||
llfont_round_y(screen_rect.mTop));
|
||||
|
||||
gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
|
||||
gGL.vertex2f(llfont_round_x(screen_rect.mLeft),
|
||||
llfont_round_y(screen_rect.mTop));
|
||||
|
||||
gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
|
||||
gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt),
|
||||
llfont_round_y(screen_rect.mBottom));
|
||||
|
||||
gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
|
||||
gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt),
|
||||
llfont_round_y(screen_rect.mBottom));
|
||||
}
|
||||
|
||||
void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
|
||||
{
|
||||
F32 slant_offset;
|
||||
slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f);
|
||||
|
||||
gGL.begin(LLRender::QUADS);
|
||||
{
|
||||
//FIXME: bold and drop shadow are mutually exclusive only for convenience
|
||||
//Allow both when we need them.
|
||||
if (style & BOLD)
|
||||
{
|
||||
gGL.color4fv(color.mV);
|
||||
for (S32 pass = 0; pass < 2; pass++)
|
||||
{
|
||||
LLRectf screen_rect_offset = screen_rect;
|
||||
|
||||
screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
|
||||
renderQuad(screen_rect_offset, uv_rect, slant_offset);
|
||||
}
|
||||
}
|
||||
else if (shadow == DROP_SHADOW_SOFT)
|
||||
{
|
||||
LLColor4 shadow_color = LLFontGL::sShadowColor;
|
||||
shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH;
|
||||
gGL.color4fv(shadow_color.mV);
|
||||
for (S32 pass = 0; pass < 5; pass++)
|
||||
{
|
||||
LLRectf screen_rect_offset = screen_rect;
|
||||
|
||||
switch(pass)
|
||||
{
|
||||
case 0:
|
||||
screen_rect_offset.translate(-1.f, -1.f);
|
||||
break;
|
||||
case 1:
|
||||
screen_rect_offset.translate(1.f, -1.f);
|
||||
break;
|
||||
case 2:
|
||||
screen_rect_offset.translate(1.f, 1.f);
|
||||
break;
|
||||
case 3:
|
||||
screen_rect_offset.translate(-1.f, 1.f);
|
||||
break;
|
||||
case 4:
|
||||
screen_rect_offset.translate(0, -2.f);
|
||||
break;
|
||||
}
|
||||
|
||||
renderQuad(screen_rect_offset, uv_rect, slant_offset);
|
||||
}
|
||||
gGL.color4fv(color.mV);
|
||||
renderQuad(screen_rect, uv_rect, slant_offset);
|
||||
}
|
||||
else if (shadow == DROP_SHADOW)
|
||||
{
|
||||
LLColor4 shadow_color = LLFontGL::sShadowColor;
|
||||
shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
|
||||
gGL.color4fv(shadow_color.mV);
|
||||
LLRectf screen_rect_shadow = screen_rect;
|
||||
screen_rect_shadow.translate(1.f, -1.f);
|
||||
renderQuad(screen_rect_shadow, uv_rect, slant_offset);
|
||||
gGL.color4fv(color.mV);
|
||||
renderQuad(screen_rect, uv_rect, slant_offset);
|
||||
}
|
||||
else // normal rendering
|
||||
{
|
||||
gGL.color4fv(color.mV);
|
||||
renderQuad(screen_rect, uv_rect, slant_offset);
|
||||
}
|
||||
|
||||
}
|
||||
gGL.end();
|
||||
}
|
||||
@@ -73,126 +73,93 @@ public:
|
||||
enum StyleFlags
|
||||
{
|
||||
// text style to render. May be combined (these are bit flags)
|
||||
NORMAL = 0,
|
||||
BOLD = 1,
|
||||
ITALIC = 2,
|
||||
UNDERLINE = 4,
|
||||
DROP_SHADOW = 8,
|
||||
DROP_SHADOW_SOFT = 16
|
||||
// text style to render. May be combined (these are bit flags)
|
||||
NORMAL = 0x00,
|
||||
BOLD = 0x01,
|
||||
ITALIC = 0x02,
|
||||
UNDERLINE = 0x04,
|
||||
};
|
||||
|
||||
enum ShadowType
|
||||
{
|
||||
NO_SHADOW,
|
||||
DROP_SHADOW,
|
||||
DROP_SHADOW_SOFT
|
||||
};
|
||||
|
||||
// Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC"
|
||||
static U8 getStyleFromString(const std::string &style);
|
||||
|
||||
LLFontGL();
|
||||
LLFontGL(const LLFontGL &source);
|
||||
~LLFontGL();
|
||||
|
||||
void init(); // Internal init, or reinitialization
|
||||
|
||||
void reset(); // Reset a font after GL cleanup. ONLY works on an already loaded font.
|
||||
|
||||
LLFontGL &operator=(const LLFontGL &source);
|
||||
|
||||
static BOOL initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
|
||||
const std::string& app_dir,
|
||||
const std::vector<std::string>& xui_paths,
|
||||
bool create_gl_textures = true);
|
||||
|
||||
static void destroyDefaultFonts();
|
||||
static void destroyAllGL();
|
||||
void destroyGL();
|
||||
|
||||
/* virtual*/ BOOL loadFace(const std::string& filename,
|
||||
const F32 point_size, const F32 vert_dpi, const F32 horz_dpi,
|
||||
const S32 components, BOOL is_fallback);
|
||||
/* virtual*/ BOOL loadFace(const std::string& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback);
|
||||
|
||||
S32 render(const LLWString &text, S32 begin_offset,
|
||||
const LLRect& rect,
|
||||
const LLColor4 &color,
|
||||
HAlign halign = LEFT, VAlign valign = BASELINE,
|
||||
U8 style = NORMAL, ShadowType shadow = NO_SHADOW,
|
||||
S32 max_chars = S32_MAX,
|
||||
F32* right_x=NULL,
|
||||
BOOL use_embedded = FALSE,
|
||||
BOOL use_ellipses = FALSE) const;
|
||||
|
||||
S32 render(const LLWString &text, S32 begin_offset,
|
||||
F32 x, F32 y,
|
||||
const LLColor4 &color,
|
||||
HAlign halign = LEFT, VAlign valign = BASELINE,
|
||||
U8 style = NORMAL, ShadowType shadow = NO_SHADOW,
|
||||
S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,
|
||||
F32* right_x=NULL,
|
||||
BOOL use_embedded = FALSE,
|
||||
BOOL use_ellipses = FALSE) const;
|
||||
|
||||
S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const;
|
||||
|
||||
S32 renderUTF8(const std::string &text, const S32 begin_offset,
|
||||
S32 x, S32 y,
|
||||
const LLColor4 &color) const
|
||||
{
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color,
|
||||
LEFT, BASELINE, NORMAL,
|
||||
S32_MAX, S32_MAX, NULL, FALSE);
|
||||
}
|
||||
|
||||
S32 renderUTF8(const std::string &text, const S32 begin_offset,
|
||||
S32 x, S32 y,
|
||||
const LLColor4 &color,
|
||||
HAlign halign, VAlign valign, U8 style = NORMAL) const
|
||||
{
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color,
|
||||
halign, valign, style,
|
||||
S32_MAX, S32_MAX, NULL, FALSE);
|
||||
}
|
||||
|
||||
// renderUTF8 does a conversion, so is slower!
|
||||
S32 renderUTF8(const std::string &text,
|
||||
S32 begin_offset,
|
||||
F32 x, F32 y,
|
||||
const LLColor4 &color,
|
||||
HAlign halign,
|
||||
VAlign valign,
|
||||
U8 style,
|
||||
S32 max_chars,
|
||||
S32 max_pixels,
|
||||
F32* right_x,
|
||||
BOOL use_ellipses) const;
|
||||
|
||||
S32 render(const LLWString &text, const S32 begin_offset,
|
||||
F32 x, F32 y,
|
||||
const LLColor4 &color) const
|
||||
{
|
||||
return render(text, begin_offset, x, y, color,
|
||||
LEFT, BASELINE, NORMAL,
|
||||
S32_MAX, S32_MAX, NULL, FALSE, FALSE);
|
||||
}
|
||||
|
||||
|
||||
S32 render(const LLWString &text,
|
||||
S32 begin_offset,
|
||||
F32 x, F32 y,
|
||||
const LLColor4 &color,
|
||||
HAlign halign = LEFT,
|
||||
VAlign valign = BASELINE,
|
||||
U8 style = NORMAL,
|
||||
S32 max_chars = S32_MAX,
|
||||
S32 max_pixels = S32_MAX,
|
||||
F32* right_x=NULL,
|
||||
BOOL use_embedded = FALSE,
|
||||
BOOL use_ellipses = FALSE) const;
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const;
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const;
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const;
|
||||
|
||||
// font metrics - override for LLFont that returns units of virtual pixels
|
||||
/*virtual*/ F32 getLineHeight() const { return (F32)llround(mLineHeight / sScaleY); }
|
||||
/*virtual*/ F32 getAscenderHeight() const { return (F32)llround(mAscender / sScaleY); }
|
||||
/*virtual*/ F32 getDescenderHeight() const { return (F32)llround(mDescender / sScaleY); }
|
||||
|
||||
virtual S32 getWidth(const std::string& utf8text) const;
|
||||
virtual S32 getWidth(const llwchar* wchars) const;
|
||||
virtual S32 getWidth(const std::string& utf8text, const S32 offset, const S32 max_chars ) const;
|
||||
virtual S32 getWidth(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE) const;
|
||||
S32 getWidth(const std::string& utf8text) const;
|
||||
S32 getWidth(const llwchar* wchars) const;
|
||||
S32 getWidth(const std::string& utf8text, const S32 offset, const S32 max_chars ) const;
|
||||
S32 getWidth(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE) const;
|
||||
|
||||
virtual F32 getWidthF32(const std::string& utf8text) const;
|
||||
virtual F32 getWidthF32(const llwchar* wchars) const;
|
||||
virtual F32 getWidthF32(const std::string& text, const S32 offset, const S32 max_chars ) const;
|
||||
virtual F32 getWidthF32(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE ) const;
|
||||
F32 getWidthF32(const std::string& utf8text) const;
|
||||
F32 getWidthF32(const llwchar* wchars) const;
|
||||
F32 getWidthF32(const std::string& text, const S32 offset, const S32 max_chars ) const;
|
||||
F32 getWidthF32(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE ) const;
|
||||
|
||||
// The following are called often, frequently with large buffers, so do not use a string interface
|
||||
|
||||
// Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
|
||||
virtual S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX,
|
||||
BOOL end_on_word_boundary = FALSE, const BOOL use_embedded = FALSE,
|
||||
F32* drawn_pixels = NULL) const;
|
||||
typedef enum e_word_wrap_style
|
||||
{
|
||||
ONLY_WORD_BOUNDARIES,
|
||||
WORD_BOUNDARY_IF_POSSIBLE,
|
||||
ANYWHERE
|
||||
} EWordWrapStyle ;
|
||||
S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, EWordWrapStyle end_on_word_boundary = ANYWHERE,
|
||||
const BOOL use_embedded = FALSE, F32* drawn_pixels = NULL) const;
|
||||
|
||||
// Returns the index of the first complete characters from text that can be drawn in max_pixels
|
||||
// given that the character at start_pos should be the last character (or as close to last as possible).
|
||||
virtual S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const;
|
||||
S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const;
|
||||
|
||||
// Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars)
|
||||
virtual S32 charFromPixelOffset(const llwchar* wchars, const S32 char_offset,
|
||||
F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX,
|
||||
BOOL round = TRUE, BOOL use_embedded = FALSE) const;
|
||||
S32 charFromPixelOffset(const llwchar* wchars, const S32 char_offset, F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX, BOOL round = TRUE, BOOL use_embedded = FALSE) const;
|
||||
|
||||
const LLFontDescriptor &getFontDesc() const { return mFontDesc; }
|
||||
void setFontDesc(const LLFontDescriptor& font_desc) { mFontDesc = font_desc; }
|
||||
|
||||
LLTexture *getTexture() const;
|
||||
|
||||
@@ -200,6 +167,17 @@ public:
|
||||
void addEmbeddedChar( llwchar wc, LLTexture* image, const LLWString& label) const;
|
||||
void removeEmbeddedChar( llwchar wc ) const;
|
||||
|
||||
static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector<std::string>& xui_paths, bool create_gl_textures = true);
|
||||
|
||||
// Load sans-serif, sans-serif-small, etc.
|
||||
// Slow, requires multiple seconds to load fonts.
|
||||
static bool loadDefaultFonts();
|
||||
static void destroyDefaultFonts();
|
||||
static void destroyAllGL();
|
||||
|
||||
// Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC"
|
||||
static U8 getStyleFromString(const std::string &style);
|
||||
static std::string getStringFromStyle(U8 style);
|
||||
static std::string nameFromFont(const LLFontGL* fontp);
|
||||
|
||||
static std::string nameFromHAlign(LLFontGL::HAlign align);
|
||||
@@ -220,16 +198,7 @@ protected:
|
||||
const embedded_data_t* getEmbeddedCharData(const llwchar wch) const;
|
||||
F32 getEmbeddedCharAdvance(const embedded_data_t* ext_data) const;
|
||||
void clearEmbeddedChars();
|
||||
void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const;
|
||||
void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, F32 drop_shadow_fade) const;
|
||||
|
||||
public:
|
||||
static F32 sVertDPI;
|
||||
static F32 sHorizDPI;
|
||||
static F32 sScaleX;
|
||||
static F32 sScaleY;
|
||||
static BOOL sDisplayFont ;
|
||||
static std::string sAppDir; // For loading fonts
|
||||
|
||||
static LLFontGL* getFontMonospace();
|
||||
static LLFontGL* getFontSansSerifSmall();
|
||||
@@ -240,11 +209,25 @@ public:
|
||||
static LLFontGL* getFontExtChar();
|
||||
static LLFontGL* getFont(const LLFontDescriptor& desc);
|
||||
|
||||
static std::string getFontPathLocal();
|
||||
static std::string getFontPathSystem();
|
||||
|
||||
static LLCoordFont sCurOrigin;
|
||||
static std::vector<LLCoordFont> sOriginStack;
|
||||
|
||||
static LLColor4 sShadowColor;
|
||||
|
||||
static F32 sVertDPI;
|
||||
static F32 sHorizDPI;
|
||||
static F32 sScaleX;
|
||||
static F32 sScaleY;
|
||||
static BOOL sDisplayFont ;
|
||||
static std::string sAppDir; // For loading fonts
|
||||
friend class LLTextBillboard;
|
||||
friend class LLHUDText;
|
||||
|
||||
LLFontGL(const LLFontGL &source);
|
||||
LLFontGL &operator=(const LLFontGL &source);
|
||||
protected:
|
||||
/*virtual*/ BOOL addChar(const llwchar wch) const;
|
||||
|
||||
@@ -254,18 +237,12 @@ protected:
|
||||
|
||||
LLFontDescriptor mFontDesc;
|
||||
|
||||
void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const;
|
||||
void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const;
|
||||
|
||||
// Registry holds all instantiated fonts.
|
||||
static LLFontRegistry* sFontRegistry;
|
||||
|
||||
public:
|
||||
static std::string getFontPathLocal();
|
||||
static std::string getFontPathSystem();
|
||||
|
||||
static LLCoordFont sCurOrigin;
|
||||
static std::vector<LLCoordFont> sOriginStack;
|
||||
|
||||
const LLFontDescriptor &getFontDesc() const { return mFontDesc; }
|
||||
void setFontDesc(const LLFontDescriptor& font_desc) { mFontDesc = font_desc; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -68,6 +68,7 @@ BOOL gGLActive = FALSE;
|
||||
|
||||
std::ofstream gFailLog;
|
||||
|
||||
#if !LL_DARWIN //Darwin doesn't load extensions that way! -SG
|
||||
void* gl_get_proc_address(const char *pStr)
|
||||
{
|
||||
void* pPtr = (void*)GLH_EXT_GET_PROC_ADDRESS(pStr);
|
||||
@@ -77,6 +78,37 @@ void* gl_get_proc_address(const char *pStr)
|
||||
}
|
||||
#undef GLH_EXT_GET_PROC_ADDRESS
|
||||
#define GLH_EXT_GET_PROC_ADDRESS(p) gl_get_proc_address(p)
|
||||
#endif //!LL_DARWIN
|
||||
|
||||
#if GL_ARB_debug_output
|
||||
|
||||
#ifndef APIENTRY
|
||||
#define APIENTRY
|
||||
#endif
|
||||
|
||||
void APIENTRY gl_debug_callback(GLenum source,
|
||||
GLenum type,
|
||||
GLuint id,
|
||||
GLenum severity,
|
||||
GLsizei length,
|
||||
const GLchar* message,
|
||||
GLvoid* userParam)
|
||||
{
|
||||
if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
|
||||
{
|
||||
llwarns << "----- GL ERROR --------" << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "----- GL WARNING -------" << llendl;
|
||||
}
|
||||
llwarns << "Type: " << std::hex << type << llendl;
|
||||
llwarns << "ID: " << std::hex << id << llendl;
|
||||
llwarns << "Severity: " << std::hex << severity << llendl;
|
||||
llwarns << "Message: " << message << llendl;
|
||||
llwarns << "-----------------------" << llendl;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ll_init_fail_log(std::string filename)
|
||||
{
|
||||
@@ -112,6 +144,7 @@ void ll_close_fail_log()
|
||||
{
|
||||
gFailLog.close();
|
||||
}
|
||||
|
||||
LLMatrix4 gGLObliqueProjectionInverse;
|
||||
|
||||
#define LL_GL_NAME_POOLING 0
|
||||
@@ -120,6 +153,11 @@ std::list<LLGLUpdate*> LLGLUpdate::sGLQ;
|
||||
|
||||
#if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS
|
||||
// ATI prototypes
|
||||
|
||||
#if LL_WINDOWS
|
||||
PFNGLGETSTRINGIPROC glGetStringi = NULL;
|
||||
#endif
|
||||
|
||||
// vertex blending prototypes
|
||||
PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB = NULL;
|
||||
PFNGLVERTEXBLENDARBPROC glVertexBlendARB = NULL;
|
||||
@@ -138,6 +176,12 @@ PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
|
||||
PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL;
|
||||
PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL;
|
||||
|
||||
//GL_ARB_vertex_array_object
|
||||
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = NULL;
|
||||
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = NULL;
|
||||
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = NULL;
|
||||
PFNGLISVERTEXARRAYPROC glIsVertexArray = NULL;
|
||||
|
||||
// GL_ARB_map_buffer_range
|
||||
PFNGLMAPBUFFERRANGEPROC glMapBufferRange = NULL;
|
||||
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = NULL;
|
||||
@@ -207,10 +251,16 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL;
|
||||
|
||||
//GL_ARB_texture_multisample
|
||||
PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
|
||||
PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
|
||||
PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
|
||||
PFNGLSAMPLEMASKIPROC glSampleMaski;
|
||||
PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample = NULL;
|
||||
PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL;
|
||||
PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL;
|
||||
PFNGLSAMPLEMASKIPROC glSampleMaski = NULL;
|
||||
|
||||
//GL_ARB_debug_output
|
||||
PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL;
|
||||
PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL;
|
||||
PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB = NULL;
|
||||
PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB = NULL;
|
||||
|
||||
// GL_EXT_blend_func_separate
|
||||
PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
|
||||
@@ -259,6 +309,10 @@ PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL;
|
||||
PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;
|
||||
PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;
|
||||
|
||||
#if LL_WINDOWS
|
||||
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
|
||||
#endif
|
||||
|
||||
// vertex shader prototypes
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB = NULL;
|
||||
@@ -331,7 +385,7 @@ PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL;
|
||||
PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL;
|
||||
|
||||
#if LL_WINDOWS
|
||||
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
|
||||
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
|
||||
#endif
|
||||
|
||||
#if LL_LINUX_NV_GL_HEADERS
|
||||
@@ -360,6 +414,7 @@ LLGLManager::LLGLManager() :
|
||||
mHasBlendFuncSeparate(FALSE),
|
||||
mHasSync(FALSE),
|
||||
mHasVertexBufferObject(FALSE),
|
||||
mHasVertexArrayObject(FALSE),
|
||||
mHasMapBufferRange(FALSE),
|
||||
mHasFlushBufferRange(FALSE),
|
||||
mHasPBuffer(FALSE),
|
||||
@@ -381,6 +436,7 @@ LLGLManager::LLGLManager() :
|
||||
mHasAnisotropic(FALSE),
|
||||
mHasARBEnvCombine(FALSE),
|
||||
mHasCubeMap(FALSE),
|
||||
mHasDebugOutput(FALSE),
|
||||
|
||||
mIsATI(FALSE),
|
||||
mIsNVIDIA(FALSE),
|
||||
@@ -420,6 +476,15 @@ void LLGLManager::initWGL()
|
||||
LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL;
|
||||
}
|
||||
|
||||
if (ExtensionExists("WGL_ARB_create_context",gGLHExts.mSysExts))
|
||||
{
|
||||
GLH_EXT_NAME(wglCreateContextAttribsARB) = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB");
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL;
|
||||
}
|
||||
|
||||
if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts))
|
||||
{
|
||||
GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT");
|
||||
@@ -449,13 +514,45 @@ bool LLGLManager::initGL()
|
||||
LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL;
|
||||
}
|
||||
|
||||
GLint alpha_bits;
|
||||
glGetIntegerv( GL_ALPHA_BITS, &alpha_bits );
|
||||
if( 8 != alpha_bits )
|
||||
stop_glerror();
|
||||
|
||||
#if LL_WINDOWS
|
||||
if (!glGetStringi)
|
||||
{
|
||||
LL_WARNS("RenderInit") << "Frame buffer has less than 8 bits of alpha. Avatar texture compositing will fail." << LL_ENDL;
|
||||
glGetStringi = (PFNGLGETSTRINGIPROC) GLH_EXT_GET_PROC_ADDRESS("glGetStringi");
|
||||
}
|
||||
|
||||
//reload extensions string (may have changed after using wglCreateContextAttrib)
|
||||
if (glGetStringi)
|
||||
{
|
||||
std::stringstream str;
|
||||
|
||||
GLint count = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &count);
|
||||
for (GLint i = 0; i < count; ++i)
|
||||
{
|
||||
std::string ext((const char*) glGetStringi(GL_EXTENSIONS, i));
|
||||
str << ext << " ";
|
||||
LL_DEBUGS("GLExtensions") << ext << llendl;
|
||||
}
|
||||
|
||||
{
|
||||
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
|
||||
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
|
||||
if(wglGetExtensionsStringARB)
|
||||
{
|
||||
str << (const char*) wglGetExtensionsStringARB(wglGetCurrentDC());
|
||||
}
|
||||
}
|
||||
|
||||
free(gGLHExts.mSysExts);
|
||||
std::string extensions = str.str();
|
||||
gGLHExts.mSysExts = strdup(extensions.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
stop_glerror();
|
||||
|
||||
// Extract video card strings and convert to upper case to
|
||||
// work around driver-to-driver variation in capitalization.
|
||||
mGLVendor = std::string((const char *)glGetString(GL_VENDOR));
|
||||
@@ -470,7 +567,7 @@ bool LLGLManager::initGL()
|
||||
&mDriverVersionVendorString );
|
||||
|
||||
mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
|
||||
|
||||
|
||||
// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
|
||||
// from being recognized as ATI.
|
||||
if (mGLVendor.substr(0,4) == "ATI ")
|
||||
@@ -542,8 +639,10 @@ bool LLGLManager::initGL()
|
||||
mGLVendorShort = "MISC";
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
// This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture.
|
||||
initExtensions();
|
||||
stop_glerror();
|
||||
|
||||
S32 old_vram = mVRAM;
|
||||
|
||||
@@ -565,13 +664,23 @@ bool LLGLManager::initGL()
|
||||
{ //something likely went wrong using the above extensions, fall back to old method
|
||||
mVRAM = old_vram;
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
|
||||
stop_glerror();
|
||||
|
||||
if (mHasFragmentShader)
|
||||
{
|
||||
GLint num_tex_image_units;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units);
|
||||
mNumTextureImageUnits = llmin(num_tex_image_units, 32);
|
||||
}
|
||||
if (mHasMultitexture)
|
||||
|
||||
if (LLRender::sGLCoreProfile)
|
||||
{
|
||||
mNumTextureUnits = llmin(mNumTextureImageUnits, MAX_GL_TEXTURE_UNITS);
|
||||
}
|
||||
else if (mHasMultitexture)
|
||||
{
|
||||
GLint num_tex_units;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num_tex_units);
|
||||
@@ -590,6 +699,7 @@ bool LLGLManager::initGL()
|
||||
return false;
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
|
||||
if (mHasTextureMultisample)
|
||||
{
|
||||
@@ -599,6 +709,16 @@ bool LLGLManager::initGL()
|
||||
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
#if LL_WINDOWS
|
||||
if (mHasDebugOutput && gDebugGL)
|
||||
{ //setup debug output callback
|
||||
glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
||||
}
|
||||
#endif
|
||||
stop_glerror();
|
||||
mHasTextureMultisample = FALSE;
|
||||
#if LL_WINDOWS
|
||||
if (mIsATI)
|
||||
{ //using multisample textures on ATI results in black screen for some reason
|
||||
@@ -610,10 +730,17 @@ bool LLGLManager::initGL()
|
||||
{
|
||||
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
|
||||
setToDebugGPU();
|
||||
|
||||
stop_glerror();
|
||||
|
||||
initGLStates();
|
||||
|
||||
stop_glerror();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -712,47 +839,47 @@ void LLGLManager::initExtensions()
|
||||
mHasMultitexture = TRUE;
|
||||
# else
|
||||
mHasMultitexture = FALSE;
|
||||
# endif
|
||||
# endif // GL_ARB_multitexture
|
||||
# ifdef GL_ARB_texture_env_combine
|
||||
mHasARBEnvCombine = TRUE;
|
||||
# else
|
||||
mHasARBEnvCombine = FALSE;
|
||||
# endif
|
||||
# endif // GL_ARB_texture_env_combine
|
||||
# ifdef GL_ARB_texture_compression
|
||||
mHasCompressedTextures = TRUE;
|
||||
# else
|
||||
mHasCompressedTextures = FALSE;
|
||||
# endif
|
||||
# endif // GL_ARB_texture_compression
|
||||
# ifdef GL_ARB_vertex_buffer_object
|
||||
mHasVertexBufferObject = TRUE;
|
||||
# else
|
||||
mHasVertexBufferObject = FALSE;
|
||||
# endif
|
||||
# endif // GL_ARB_vertex_buffer_object
|
||||
# ifdef GL_EXT_framebuffer_object
|
||||
mHasFramebufferObject = TRUE;
|
||||
# else
|
||||
mHasFramebufferObject = FALSE;
|
||||
# endif
|
||||
# endif // GL_EXT_framebuffer_object
|
||||
# ifdef GL_EXT_framebuffer_multisample
|
||||
mHasFramebufferMultisample = TRUE;
|
||||
# else
|
||||
mHasFramebufferMultisample = FALSE;
|
||||
# endif
|
||||
# endif // GL_EXT_framebuffer_multisample
|
||||
# ifdef GL_ARB_draw_buffers
|
||||
mHasDrawBuffers = TRUE;
|
||||
#else
|
||||
mHasDrawBuffers = FALSE;
|
||||
# endif
|
||||
# endif // GL_ARB_draw_buffers
|
||||
# if defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
|
||||
mHasDepthClamp = TRUE;
|
||||
#else
|
||||
mHasDepthClamp = FALSE;
|
||||
#endif
|
||||
#endif // defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
|
||||
# if GL_EXT_blend_func_separate
|
||||
mHasBlendFuncSeparate = TRUE;
|
||||
#else
|
||||
mHasBlendFuncSeparate = FALSE;
|
||||
# endif
|
||||
# endif // GL_EXT_blend_func_separate
|
||||
mHasMipMapGeneration = FALSE;
|
||||
mHasSeparateSpecularColor = FALSE;
|
||||
mHasAnisotropic = FALSE;
|
||||
@@ -763,7 +890,7 @@ void LLGLManager::initExtensions()
|
||||
mHasVertexShader = FALSE;
|
||||
mHasFragmentShader = FALSE;
|
||||
mHasTextureRectangle = FALSE;
|
||||
#else // LL_MESA_HEADLESS
|
||||
#else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called
|
||||
mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
|
||||
mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
|
||||
mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
|
||||
@@ -777,11 +904,12 @@ void LLGLManager::initExtensions()
|
||||
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);
|
||||
mHasVertexArrayObject = ExtensionExists("GL_ARB_vertex_array_object", gGLHExts.mSysExts);
|
||||
mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
|
||||
mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
|
||||
mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", 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
|
||||
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
|
||||
#ifdef GL_ARB_framebuffer_object
|
||||
mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts);
|
||||
#else
|
||||
@@ -795,13 +923,14 @@ void LLGLManager::initExtensions()
|
||||
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
|
||||
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
|
||||
mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);
|
||||
mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
|
||||
#if !LL_DARWIN
|
||||
mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
|
||||
#endif
|
||||
mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
|
||||
mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
|
||||
mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts)
|
||||
&& ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
|
||||
mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
|
||||
&& (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
|
||||
mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
|
||||
#endif
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
@@ -976,6 +1105,13 @@ void LLGLManager::initExtensions()
|
||||
mHasVertexBufferObject = FALSE;
|
||||
}
|
||||
}
|
||||
if (mHasVertexArrayObject)
|
||||
{
|
||||
glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glBindVertexArray");
|
||||
glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteVertexArrays");
|
||||
glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenVertexArrays");
|
||||
glIsVertexArray = (PFNGLISVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glIsVertexArray");
|
||||
}
|
||||
if (mHasSync)
|
||||
{
|
||||
glFenceSync = (PFNGLFENCESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glFenceSync");
|
||||
@@ -1030,6 +1166,13 @@ void LLGLManager::initExtensions()
|
||||
glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
|
||||
glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
|
||||
}
|
||||
if (mHasDebugOutput)
|
||||
{
|
||||
glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB");
|
||||
glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageInsertARB");
|
||||
glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageCallbackARB");
|
||||
glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetDebugMessageLogARB");
|
||||
}
|
||||
#if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS
|
||||
// This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah
|
||||
glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
|
||||
@@ -1184,7 +1327,7 @@ void rotate_quat(LLQuaternion& rotation)
|
||||
{
|
||||
F32 angle_radians, x, y, z;
|
||||
rotation.getAngleAxis(&angle_radians, &x, &y, &z);
|
||||
glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
|
||||
gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
|
||||
}
|
||||
|
||||
void flush_glerror()
|
||||
@@ -1221,10 +1364,6 @@ void log_glerror()
|
||||
|
||||
void do_assert_glerror()
|
||||
{
|
||||
if (LL_UNLIKELY(!gGLManager.mInited))
|
||||
{
|
||||
LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL;
|
||||
}
|
||||
// Create or update texture to be used with this data
|
||||
GLenum error;
|
||||
error = glGetError();
|
||||
@@ -1319,8 +1458,6 @@ void LLGLState::initClass()
|
||||
//make sure multisample defaults to disabled
|
||||
sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE;
|
||||
glDisable(GL_MULTISAMPLE_ARB);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -1370,6 +1507,8 @@ void LLGLState::checkStates(const std::string& msg)
|
||||
glGetIntegerv(GL_BLEND_SRC, &src);
|
||||
glGetIntegerv(GL_BLEND_DST, &dst);
|
||||
|
||||
stop_glerror();
|
||||
|
||||
BOOL error = FALSE;
|
||||
|
||||
if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA)
|
||||
@@ -1390,7 +1529,9 @@ void LLGLState::checkStates(const std::string& msg)
|
||||
{
|
||||
LLGLenum state = iter->first;
|
||||
LLGLboolean cur_state = iter->second;
|
||||
stop_glerror();
|
||||
LLGLboolean gl_state = glIsEnabled(state);
|
||||
stop_glerror();
|
||||
if(cur_state != gl_state)
|
||||
{
|
||||
dumpStates();
|
||||
@@ -1601,7 +1742,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
|
||||
error = TRUE;
|
||||
}
|
||||
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture);
|
||||
/*glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture);
|
||||
if (active_texture != GL_TEXTURE0_ARB)
|
||||
{
|
||||
llwarns << "Active texture corrupted: " << active_texture << llendl;
|
||||
@@ -1610,7 +1751,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
|
||||
gFailLog << "Active texture corrupted: " << active_texture << std::endl;
|
||||
}
|
||||
error = TRUE;
|
||||
}
|
||||
}*/
|
||||
|
||||
static const char* label[] =
|
||||
{
|
||||
@@ -1637,7 +1778,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
|
||||
};
|
||||
|
||||
|
||||
for (S32 j = 0; j < 4; j++)
|
||||
for (S32 j = 1; j < 4; j++)
|
||||
{
|
||||
if (glIsEnabled(value[j]))
|
||||
{
|
||||
@@ -1748,7 +1889,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_GL_ERRS << "GL client array corruption detected. " << msg << LL_ENDL;
|
||||
LL_GL_ERRS << "GL client array corruption detected. " << msg << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1759,17 +1900,26 @@ LLGLState::LLGLState(LLGLenum state, S32 enabled) :
|
||||
mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
|
||||
{
|
||||
if (LLGLSLShader::sNoFixedFunction)
|
||||
{ //always disable state that's deprecated post GL 3.0
|
||||
{ //always ignore state that's deprecated post GL 3.0
|
||||
switch (state)
|
||||
{
|
||||
case GL_ALPHA_TEST:
|
||||
enabled = 0;
|
||||
break;
|
||||
case GL_NORMALIZE:
|
||||
case GL_TEXTURE_GEN_R:
|
||||
case GL_TEXTURE_GEN_S:
|
||||
case GL_TEXTURE_GEN_T:
|
||||
case GL_TEXTURE_GEN_Q:
|
||||
case GL_LIGHTING:
|
||||
case GL_COLOR_MATERIAL:
|
||||
case GL_FOG:
|
||||
case GL_LINE_STIPPLE:
|
||||
mState = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stop_glerror();
|
||||
if (state)
|
||||
if (mState)
|
||||
{
|
||||
mWasEnabled = sStateMap[state];
|
||||
llassert(mWasEnabled == glIsEnabled(state));
|
||||
@@ -1812,7 +1962,7 @@ LLGLState::~LLGLState()
|
||||
{
|
||||
if (!gDebugSession)
|
||||
{
|
||||
llassert_always(sStateMap[mState] == glIsEnabled(mState));
|
||||
llassert_always(sStateMap[mState] == glIsEnabled(mState));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1851,79 +2001,6 @@ void LLGLManager::initGLStates()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void enable_vertex_weighting(const S32 index)
|
||||
{
|
||||
#if GL_ARB_vertex_program
|
||||
if (index > 0) glEnableVertexAttribArrayARB(index); // vertex weights
|
||||
#endif
|
||||
}
|
||||
|
||||
void disable_vertex_weighting(const S32 index)
|
||||
{
|
||||
#if GL_ARB_vertex_program
|
||||
if (index > 0) glDisableVertexAttribArrayARB(index); // vertex weights
|
||||
#endif
|
||||
}
|
||||
|
||||
void enable_binormals(const S32 index)
|
||||
{
|
||||
#if GL_ARB_vertex_program
|
||||
if (index > 0)
|
||||
{
|
||||
glEnableVertexAttribArrayARB(index); // binormals
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void disable_binormals(const S32 index)
|
||||
{
|
||||
#if GL_ARB_vertex_program
|
||||
if (index > 0)
|
||||
{
|
||||
glDisableVertexAttribArrayARB(index); // binormals
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void enable_cloth_weights(const S32 index)
|
||||
{
|
||||
#if GL_ARB_vertex_program
|
||||
if (index > 0) glEnableVertexAttribArrayARB(index);
|
||||
#endif
|
||||
}
|
||||
|
||||
void disable_cloth_weights(const S32 index)
|
||||
{
|
||||
#if GL_ARB_vertex_program
|
||||
if (index > 0) glDisableVertexAttribArrayARB(index);
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights)
|
||||
{
|
||||
#if GL_ARB_vertex_program
|
||||
if (index > 0) glVertexAttribPointerARB(index, 1, GL_FLOAT, FALSE, stride, weights);
|
||||
stop_glerror();
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights)
|
||||
{
|
||||
#if GL_ARB_vertex_program
|
||||
if (index > 0) glVertexAttribPointerARB(index, 4, GL_FLOAT, TRUE, stride, weights);
|
||||
stop_glerror();
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_binormals(const S32 index, const U32 stride,const LLVector3 *binormals)
|
||||
{
|
||||
#if GL_ARB_vertex_program
|
||||
if (index > 0) glVertexAttribPointerARB(index, 3, GL_FLOAT, FALSE, stride, binormals);
|
||||
stop_glerror();
|
||||
#endif
|
||||
}
|
||||
|
||||
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific )
|
||||
{
|
||||
// GL_VERSION returns a null-terminated string with the format:
|
||||
@@ -2036,20 +2113,20 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
|
||||
glh::matrix4f suffix;
|
||||
suffix.set_row(2, cplane);
|
||||
glh::matrix4f newP = suffix * P;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadMatrixf(newP.m);
|
||||
gGL.matrixMode(LLRender::MM_PROJECTION);
|
||||
gGL.pushMatrix();
|
||||
gGL.loadMatrix(newP.m);
|
||||
gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
}
|
||||
|
||||
LLGLUserClipPlane::~LLGLUserClipPlane()
|
||||
{
|
||||
if (mApply)
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
gGL.matrixMode(LLRender::MM_PROJECTION);
|
||||
gGL.popMatrix();
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2238,16 +2315,16 @@ LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P, U32 layer)
|
||||
P.element(2, i) = P.element(3, i) * depth;
|
||||
}
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadMatrixf(P.m);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
gGL.matrixMode(LLRender::MM_PROJECTION);
|
||||
gGL.pushMatrix();
|
||||
gGL.loadMatrix(P.m);
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
}
|
||||
|
||||
LLGLSquashToFarClip::~LLGLSquashToFarClip()
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
gGL.matrixMode(LLRender::MM_PROJECTION);
|
||||
gGL.popMatrix();
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ public:
|
||||
|
||||
// ARB Extensions
|
||||
BOOL mHasVertexBufferObject;
|
||||
BOOL mHasVertexArrayObject;
|
||||
BOOL mHasSync;
|
||||
BOOL mHasMapBufferRange;
|
||||
BOOL mHasFlushBufferRange;
|
||||
@@ -119,6 +120,7 @@ public:
|
||||
BOOL mHasAnisotropic;
|
||||
BOOL mHasARBEnvCombine;
|
||||
BOOL mHasCubeMap;
|
||||
BOOL mHasDebugOutput;
|
||||
|
||||
// Vendor-specific extensions
|
||||
BOOL mIsATI;
|
||||
@@ -259,7 +261,7 @@ public:
|
||||
static void dumpStates();
|
||||
static void checkStates(const std::string& msg = "");
|
||||
static void checkTextureChannels(const std::string& msg = "");
|
||||
static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0x0001);
|
||||
static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0);
|
||||
|
||||
protected:
|
||||
static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
|
||||
@@ -426,15 +428,7 @@ extern LLMatrix4 gGLObliqueProjectionInverse;
|
||||
#include "llglstates.h"
|
||||
|
||||
void init_glstates();
|
||||
void enable_vertex_weighting(const S32 index);
|
||||
void disable_vertex_weighting(const S32 index);
|
||||
void enable_binormals(const S32 index);
|
||||
void disable_binormals(const S32 index);
|
||||
void enable_cloth_weights(const S32 index);
|
||||
void disable_cloth_weights(const S32 index);
|
||||
void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights);
|
||||
void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights);
|
||||
void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals);
|
||||
|
||||
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
|
||||
|
||||
extern BOOL gClothRipple;
|
||||
|
||||
@@ -76,6 +76,12 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
|
||||
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
|
||||
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
|
||||
|
||||
// GL_ARB_vertex_array_object
|
||||
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
||||
extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
|
||||
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
|
||||
|
||||
// GL_ARB_sync
|
||||
extern PFNGLFENCESYNCPROC glFenceSync;
|
||||
extern PFNGLISSYNCPROC glIsSync;
|
||||
@@ -316,6 +322,12 @@ extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;
|
||||
extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
|
||||
#endif // LL_LINUX_NV_GL_HEADERS
|
||||
|
||||
// GL_ARB_vertex_array_object
|
||||
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
||||
extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
|
||||
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
|
||||
|
||||
// GL_ARB_vertex_buffer_object
|
||||
extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
|
||||
extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB;
|
||||
@@ -537,6 +549,9 @@ extern PFNGLSAMPLEMASKIPROC glSampleMaski;
|
||||
#include "GL/glext.h"
|
||||
#include "GL/glh_extensions.h"
|
||||
|
||||
// WGL_ARB_create_context
|
||||
extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
|
||||
extern PFNGLGETSTRINGIPROC glGetStringi;
|
||||
|
||||
// GL_ARB_vertex_buffer_object
|
||||
extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
|
||||
@@ -551,6 +566,12 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
|
||||
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
|
||||
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
|
||||
|
||||
// GL_ARB_vertex_array_object
|
||||
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
||||
extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
|
||||
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
|
||||
|
||||
// GL_ARB_sync
|
||||
extern PFNGLFENCESYNCPROC glFenceSync;
|
||||
extern PFNGLISSYNCPROC glIsSync;
|
||||
@@ -741,6 +762,11 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
|
||||
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
|
||||
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
|
||||
|
||||
//GL_ARB_debug_output
|
||||
extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
|
||||
extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
|
||||
extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
|
||||
extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB;
|
||||
#elif LL_DARWIN
|
||||
//----------------------------------------------------------------------------
|
||||
// LL_DARWIN
|
||||
@@ -904,6 +930,31 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
|
||||
#endif /* GL_GLEXT_FUNCTION_POINTERS */
|
||||
#endif
|
||||
|
||||
#ifndef GL_ARB_texture_rg
|
||||
#define GL_RG 0x8227
|
||||
#define GL_RG_INTEGER 0x8228
|
||||
#define GL_R8 0x8229
|
||||
#define GL_R16 0x822A
|
||||
#define GL_RG8 0x822B
|
||||
#define GL_RG16 0x822C
|
||||
#define GL_R16F 0x822D
|
||||
#define GL_R32F 0x822E
|
||||
#define GL_RG16F 0x822F
|
||||
#define GL_RG32F 0x8230
|
||||
#define GL_R8I 0x8231
|
||||
#define GL_R8UI 0x8232
|
||||
#define GL_R16I 0x8233
|
||||
#define GL_R16UI 0x8234
|
||||
#define GL_R32I 0x8235
|
||||
#define GL_R32UI 0x8236
|
||||
#define GL_RG8I 0x8237
|
||||
#define GL_RG8UI 0x8238
|
||||
#define GL_RG16I 0x8239
|
||||
#define GL_RG16UI 0x823A
|
||||
#define GL_RG32I 0x823B
|
||||
#define GL_RG32UI 0x823C
|
||||
#endif
|
||||
|
||||
// May be needed for DARWIN...
|
||||
// #ifndef GL_ARB_compressed_tex_image
|
||||
// #define GL_ARB_compressed_tex_image 1
|
||||
|
||||
@@ -58,6 +58,7 @@ using std::string;
|
||||
|
||||
GLhandleARB LLGLSLShader::sCurBoundShader = 0;
|
||||
LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
|
||||
S32 LLGLSLShader::sIndexedTextureChannels = 0;
|
||||
bool LLGLSLShader::sNoFixedFunction = false;
|
||||
|
||||
//UI shader -- declared here so llui_libtest will link properly
|
||||
@@ -73,12 +74,9 @@ BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
|
||||
|
||||
LLShaderFeatures::LLShaderFeatures()
|
||||
: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
|
||||
hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false),
|
||||
hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
|
||||
, mIndexedTextureChannels(0), disableTextureIndex(false), hasAlphaMask(false)
|
||||
#if MESH_ENABLED
|
||||
, hasObjectSkinning(false)
|
||||
#endif //MESH_ENABLED
|
||||
hasTransport(false), hasSkinning(false), hasObjectSkinning(false), hasAtmospherics(false), isSpecular(false),
|
||||
hasGamma(false), hasLighting(false), isAlphaLighting(false), calculatesAtmospherics(false), mIndexedTextureChannels(0), disableTextureIndex(false),
|
||||
hasAlphaMask(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -125,6 +123,12 @@ void LLGLSLShader::unload()
|
||||
BOOL LLGLSLShader::createShader(vector<string> * attributes,
|
||||
vector<string> * uniforms)
|
||||
{
|
||||
//reloading, reset matrix hash values
|
||||
for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i)
|
||||
{
|
||||
mMatHash[i] = 0xFFFFFFFF;
|
||||
}
|
||||
mLightHash = 0xFFFFFFFF;
|
||||
llassert_always(!mShaderFiles.empty());
|
||||
BOOL success = TRUE;
|
||||
|
||||
@@ -134,8 +138,8 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
|
||||
mProgramObject = glCreateProgramObjectARB();
|
||||
|
||||
static const LLCachedControl<bool> no_texture_indexing("ShyotlUseLegacyTextureBatching",false);
|
||||
static const LLCachedControl<bool> use_legacy_path("ShyotlUseLegacyRenderPath", false); //Legacy does not jive with new batching.
|
||||
if (gGLManager.mGLVersion < 3.1f || no_texture_indexing || use_legacy_path)
|
||||
//static const LLCachedControl<bool> use_legacy_path("ShyotlUseLegacyRenderPath", false); //Legacy does not jive with new batching.
|
||||
if (gGLManager.mGLVersion < 3.1f || no_texture_indexing /*|| use_legacy_path*/)
|
||||
{ //force indexed texture channels to 1 if GL version is old (performance improvement for drivers with poor branching shader model support)
|
||||
mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
|
||||
}
|
||||
@@ -262,11 +266,11 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
|
||||
BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
|
||||
{
|
||||
//before linking, make sure reserved attributes always have consistent locations
|
||||
/*for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
|
||||
for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
|
||||
{
|
||||
const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str();
|
||||
glBindAttribLocationARB(mProgramObject, i, (const GLcharARB *) name);
|
||||
}*/
|
||||
}
|
||||
|
||||
//link the program
|
||||
BOOL res = link();
|
||||
@@ -807,13 +811,17 @@ GLint LLGLSLShader::getUniformLocation(const string& uniform)
|
||||
}
|
||||
}
|
||||
|
||||
/*if (gDebugGL)
|
||||
return ret;
|
||||
}
|
||||
|
||||
GLint LLGLSLShader::getUniformLocation(U32 index)
|
||||
{
|
||||
GLint ret = -1;
|
||||
if (mProgramObject > 0)
|
||||
{
|
||||
if (ret == -1 && ret != glGetUniformLocationARB(mProgramObject, uniform.c_str()))
|
||||
{
|
||||
llerrs << "Uniform map invalid." << llendl;
|
||||
}
|
||||
}*/
|
||||
llassert(index < mUniform.size());
|
||||
return mUniform[index];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -969,7 +977,9 @@ void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v
|
||||
std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
|
||||
if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
|
||||
{
|
||||
stop_glerror();
|
||||
glUniform4fvARB(location, count, v);
|
||||
stop_glerror();
|
||||
mValue[location] = vec;
|
||||
}
|
||||
}
|
||||
@@ -1007,12 +1017,6 @@ void LLGLSLShader::uniformMatrix4fv(const string& uniform, U32 count, GLboolean
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLGLSLShader::setAlphaRange(F32 minimum, F32 maximum)
|
||||
{
|
||||
uniform1f("minimum_alpha", minimum);
|
||||
uniform1f("maximum_alpha", maximum);
|
||||
}
|
||||
|
||||
void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
|
||||
{
|
||||
@@ -1029,3 +1033,9 @@ void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v)
|
||||
glVertexAttrib4fvARB(mAttribute[index], v);
|
||||
}
|
||||
}
|
||||
|
||||
void LLGLSLShader::setMinimumAlpha(F32 minimum)
|
||||
{
|
||||
gGL.flush();
|
||||
uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum);
|
||||
}
|
||||
|
||||
@@ -42,15 +42,14 @@ public:
|
||||
bool calculatesLighting;
|
||||
bool calculatesAtmospherics;
|
||||
bool hasLighting; // implies no transport (it's possible to have neither though)
|
||||
bool isAlphaLighting; // indicates lighting shaders need not be linked in (lighting performed directly in alpha shader to match deferred lighting functions
|
||||
bool isShiny;
|
||||
bool isFullbright; // implies no lighting
|
||||
bool isSpecular;
|
||||
bool hasWaterFog; // implies no gamma
|
||||
bool hasTransport; // implies no lighting (it's possible to have neither though)
|
||||
bool hasSkinning;
|
||||
#if MESH_ENABLED
|
||||
bool hasObjectSkinning;
|
||||
#endif //MESH_ENABLED
|
||||
bool hasAtmospherics;
|
||||
bool hasGamma;
|
||||
S32 mIndexedTextureChannels;
|
||||
@@ -77,6 +76,7 @@ public:
|
||||
|
||||
static GLhandleARB sCurBoundShader;
|
||||
static LLGLSLShader* sCurBoundShaderPtr;
|
||||
static S32 sIndexedTextureChannels;
|
||||
static bool sNoFixedFunction;
|
||||
|
||||
void unload();
|
||||
@@ -115,16 +115,17 @@ public:
|
||||
void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
|
||||
void uniformMatrix4fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
|
||||
|
||||
void setAlphaRange(F32 minimum, F32 maximum);
|
||||
void setMinimumAlpha(F32 minimum);
|
||||
|
||||
void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
|
||||
void vertexAttrib4fv(U32 index, GLfloat* v);
|
||||
|
||||
GLint getUniformLocation(const std::string& uniform);
|
||||
GLint getUniformLocation(U32 index);
|
||||
|
||||
GLint getAttribLocation(U32 attrib);
|
||||
GLint mapUniformTextureChannel(GLint location, GLenum type);
|
||||
|
||||
|
||||
//enable/disable texture channel for specified uniform
|
||||
//if given texture uniform is active in the shader,
|
||||
//the corresponding channel will be active upon return
|
||||
@@ -139,6 +140,9 @@ public:
|
||||
// Unbinds any previously bound shader by explicitly binding no shader.
|
||||
static void bindNoShader(void);
|
||||
|
||||
U32 mMatHash[LLRender::NUM_MATRIX_MODES];
|
||||
U32 mLightHash;
|
||||
|
||||
GLhandleARB mProgramObject;
|
||||
std::vector<GLint> mAttribute; //lookup table of attribute enum to attribute channel
|
||||
std::vector<GLint> mUniform; //lookup table of uniform enum to uniform location
|
||||
|
||||
@@ -116,6 +116,7 @@ void LLImageGL::checkTexSize(bool forced) const
|
||||
glGetIntegerv(GL_VIEWPORT, vp) ;
|
||||
llcallstacks << "viewport: " << vp[0] << " : " << vp[1] << " : " << vp[2] << " : " << vp[3] << llcallstacksendl ;
|
||||
}
|
||||
|
||||
GLint texname;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname);
|
||||
BOOL error = FALSE;
|
||||
@@ -741,7 +742,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
||||
{
|
||||
if (mAutoGenMips)
|
||||
{
|
||||
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
|
||||
if (!gGLManager.mHasFramebufferObject)
|
||||
{
|
||||
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
|
||||
}
|
||||
stop_glerror();
|
||||
{
|
||||
// LLFastTimer t2(LLFastTimer::FTM_TEMP4);
|
||||
@@ -770,6 +774,12 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
|
||||
stop_glerror();
|
||||
}
|
||||
}
|
||||
|
||||
if (gGLManager.mHasFramebufferObject)
|
||||
{
|
||||
//GL_EXT_framebuffer_object implies glGenerateMipmap
|
||||
glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1031,8 +1041,75 @@ void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
|
||||
// static
|
||||
void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels)
|
||||
{
|
||||
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels);
|
||||
bool use_scratch = false;
|
||||
U32* scratch = NULL;
|
||||
if (LLRender::sGLCoreProfile)
|
||||
{
|
||||
if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
|
||||
{ //GL_ALPHA is deprecated, convert to RGBA
|
||||
use_scratch = true;
|
||||
scratch = new U32[width*height];
|
||||
|
||||
U32 pixel_count = (U32) (width*height);
|
||||
for (U32 i = 0; i < pixel_count; i++)
|
||||
{
|
||||
U8* pix = (U8*) &scratch[i];
|
||||
pix[0] = pix[1] = pix[2] = 0;
|
||||
pix[3] = ((U8*) pixels)[i];
|
||||
}
|
||||
|
||||
pixformat = GL_RGBA;
|
||||
intformat = GL_RGBA8;
|
||||
}
|
||||
|
||||
if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
|
||||
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
|
||||
use_scratch = true;
|
||||
scratch = new U32[width*height];
|
||||
|
||||
U32 pixel_count = (U32) (width*height);
|
||||
for (U32 i = 0; i < pixel_count; i++)
|
||||
{
|
||||
U8 lum = ((U8*) pixels)[i*2+0];
|
||||
U8 alpha = ((U8*) pixels)[i*2+1];
|
||||
|
||||
U8* pix = (U8*) &scratch[i];
|
||||
pix[0] = pix[1] = pix[2] = lum;
|
||||
pix[3] = alpha;
|
||||
}
|
||||
|
||||
pixformat = GL_RGBA;
|
||||
intformat = GL_RGBA8;
|
||||
}
|
||||
|
||||
if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
|
||||
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
|
||||
use_scratch = true;
|
||||
scratch = new U32[width*height];
|
||||
|
||||
U32 pixel_count = (U32) (width*height);
|
||||
for (U32 i = 0; i < pixel_count; i++)
|
||||
{
|
||||
U8 lum = ((U8*) pixels)[i];
|
||||
|
||||
U8* pix = (U8*) &scratch[i];
|
||||
pix[0] = pix[1] = pix[2] = lum;
|
||||
pix[3] = 255;
|
||||
}
|
||||
|
||||
pixformat = GL_RGBA;
|
||||
intformat = GL_RGB8;
|
||||
}
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
|
||||
stop_glerror();
|
||||
|
||||
if (use_scratch)
|
||||
{
|
||||
delete [] scratch;
|
||||
}
|
||||
}
|
||||
|
||||
//create an empty GL texture: just create a texture name
|
||||
@@ -1144,6 +1221,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
|
||||
BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
|
||||
{
|
||||
llassert(data_in);
|
||||
stop_glerror();
|
||||
|
||||
if (discard_level < 0)
|
||||
{
|
||||
@@ -1171,10 +1249,12 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
|
||||
LLImageGL::generateTextures(1, &mTexName);
|
||||
stop_glerror();
|
||||
{
|
||||
// LLFastTimer t1(LLFastTimer::FTM_TEMP6);
|
||||
llverify(gGL.getTexUnit(0)->bind(this));
|
||||
stop_glerror();
|
||||
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
|
||||
stop_glerror();
|
||||
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level);
|
||||
stop_glerror();
|
||||
}
|
||||
}
|
||||
if (!mTexName)
|
||||
@@ -1740,7 +1820,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
|
||||
// this to be an intentional effect and don't treat as a mask.
|
||||
|
||||
U32 midrangetotal = 0;
|
||||
for (U32 i = 4; i < 11; i++)
|
||||
for (U32 i = 2; i < 13; i++)
|
||||
{
|
||||
midrangetotal += sample[i];
|
||||
}
|
||||
@@ -1755,7 +1835,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
|
||||
upperhalftotal += sample[i];
|
||||
}
|
||||
|
||||
if (midrangetotal > length/16 || // lots of midrange, or
|
||||
if (midrangetotal > length/48 || // lots of midrange, or
|
||||
(lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or
|
||||
(upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque
|
||||
{
|
||||
|
||||
@@ -76,13 +76,14 @@ public:
|
||||
static S32 updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) ;
|
||||
|
||||
static bool checkSize(S32 width, S32 height);
|
||||
|
||||
|
||||
//for server side use only.
|
||||
// Not currently necessary for LLImageGL, but required in some derived classes,
|
||||
// so include for compatability
|
||||
static BOOL create(LLPointer<LLImageGL>& dest, BOOL usemipmaps = TRUE);
|
||||
static BOOL create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE);
|
||||
static BOOL create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps = TRUE);
|
||||
|
||||
|
||||
public:
|
||||
LLImageGL(BOOL usemipmaps = TRUE);
|
||||
LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE);
|
||||
|
||||
@@ -36,15 +36,13 @@
|
||||
#include "llglslshader.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llrender.h"
|
||||
#include "llvertexbuffer.h"
|
||||
|
||||
#include "lldir.h"
|
||||
extern LLGLSLShader gPostColorFilterProgram;
|
||||
extern LLGLSLShader gPostNightVisionProgram;
|
||||
extern LLGLSLShader gPostGaussianBlurProgram;
|
||||
|
||||
LLPostProcess * gPostProcess = NULL;
|
||||
|
||||
|
||||
static const unsigned int NOISE_SIZE = 512;
|
||||
|
||||
/// CALCULATING LUMINANCE (Using NTSC lum weights)
|
||||
@@ -56,13 +54,12 @@ static const float LUMINANCE_B = 0.114f;
|
||||
static const char * const XML_FILENAME = "postprocesseffects.xml";
|
||||
|
||||
LLPostProcess::LLPostProcess(void) :
|
||||
initialized(false),
|
||||
mVBO(NULL),
|
||||
mAllEffects(LLSD::emptyMap()),
|
||||
screenW(1), screenH(1)
|
||||
mScreenWidth(1), mScreenHeight(1)
|
||||
{
|
||||
mSceneRenderTexture = NULL ;
|
||||
mNoiseTexture = NULL ;
|
||||
mTempBloomTexture = NULL ;
|
||||
|
||||
/* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.*/
|
||||
std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
|
||||
@@ -82,7 +79,6 @@ LLPostProcess::LLPostProcess(void) :
|
||||
LLSD & defaultEffect = (mAllEffects["default"] = LLSD::emptyMap());
|
||||
|
||||
/*defaultEffect["enable_night_vision"] = LLSD::Boolean(false);
|
||||
defaultEffect["enable_bloom"] = LLSD::Boolean(false);
|
||||
defaultEffect["enable_color_filter"] = LLSD::Boolean(false);*/
|
||||
|
||||
/// NVG Defaults
|
||||
@@ -91,13 +87,7 @@ LLPostProcess::LLPostProcess(void) :
|
||||
defaultEffect["noise_strength"] = 0.4;
|
||||
|
||||
// TODO BTest potentially add this to tweaks?
|
||||
noiseTextureScale = 1.0f;
|
||||
|
||||
/// Bloom Defaults
|
||||
defaultEffect["extract_low"] = 0.95;
|
||||
defaultEffect["extract_high"] = 1.0;
|
||||
defaultEffect["bloom_width"] = 2.25;
|
||||
defaultEffect["bloom_strength"] = 1.5;
|
||||
mNoiseTextureScale = 1.0f;
|
||||
|
||||
/// Color Filter Defaults
|
||||
defaultEffect["gamma"] = 1.0;
|
||||
@@ -123,25 +113,10 @@ LLPostProcess::~LLPostProcess(void)
|
||||
invalidate() ;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLPostProcess::initClass(void)
|
||||
/*static*/void LLPostProcess::cleanupClass()
|
||||
{
|
||||
//this will cause system to crash at second time login
|
||||
//if first time login fails due to network connection --- bao
|
||||
//***llassert_always(gPostProcess == NULL);
|
||||
//replaced by the following line:
|
||||
if(gPostProcess)
|
||||
return ;
|
||||
|
||||
|
||||
gPostProcess = new LLPostProcess();
|
||||
}
|
||||
|
||||
// static
|
||||
void LLPostProcess::cleanupClass()
|
||||
{
|
||||
delete gPostProcess;
|
||||
gPostProcess = NULL;
|
||||
if(instanceExists())
|
||||
getInstance()->invalidate() ;
|
||||
}
|
||||
|
||||
void LLPostProcess::setSelectedEffect(std::string const & effectName)
|
||||
@@ -152,7 +127,6 @@ void LLPostProcess::setSelectedEffect(std::string const & effectName)
|
||||
|
||||
void LLPostProcess::saveEffect(std::string const & effectName)
|
||||
{
|
||||
/* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.*/
|
||||
mAllEffects[effectName] = tweaks;
|
||||
|
||||
std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
|
||||
@@ -163,38 +137,57 @@ void LLPostProcess::saveEffect(std::string const & effectName)
|
||||
LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
|
||||
|
||||
formatter->format(mAllEffects, effectsXML);
|
||||
//*/
|
||||
}
|
||||
void LLPostProcess::invalidate()
|
||||
{
|
||||
mSceneRenderTexture = NULL ;
|
||||
mNoiseTexture = NULL ;
|
||||
mTempBloomTexture = NULL ;
|
||||
initialized = FALSE ;
|
||||
mVBO = NULL ;
|
||||
}
|
||||
|
||||
void LLPostProcess::apply(unsigned int width, unsigned int height)
|
||||
{
|
||||
if (!initialized || width != screenW || height != screenH){
|
||||
initialize(width, height);
|
||||
}
|
||||
if (shadersEnabled()){
|
||||
if(shadersEnabled())
|
||||
{
|
||||
if (mVBO.isNull() || width != mScreenWidth || height != mScreenHeight)
|
||||
{
|
||||
initialize(width, height);
|
||||
}
|
||||
doEffects();
|
||||
}
|
||||
}
|
||||
|
||||
void LLPostProcess::initialize(unsigned int width, unsigned int height)
|
||||
{
|
||||
screenW = width;
|
||||
screenH = height;
|
||||
createTexture(mSceneRenderTexture, screenW, screenH);
|
||||
initialized = true;
|
||||
invalidate();
|
||||
mScreenWidth = width;
|
||||
mScreenHeight = height;
|
||||
|
||||
createScreenTexture();
|
||||
|
||||
//Setup our VBO.
|
||||
{
|
||||
mVBO = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1,3);
|
||||
mVBO->allocateBuffer(4,0,TRUE);
|
||||
|
||||
LLStrider<LLVector3> v;
|
||||
LLStrider<LLVector2> uv1;
|
||||
LLStrider<LLVector2> uv2;
|
||||
|
||||
mVBO->getVertexStrider(v);
|
||||
mVBO->getTexCoord0Strider(uv1);
|
||||
mVBO->getTexCoord1Strider(uv2);
|
||||
|
||||
v[0] = LLVector3( uv2[0] = uv1[0] = LLVector2(0, 0) );
|
||||
v[1] = LLVector3( uv2[1] = uv1[1] = LLVector2(0, mScreenHeight) );
|
||||
v[2] = LLVector3( uv2[2] = uv1[2] = LLVector2(mScreenWidth, 0) );
|
||||
v[3] = LLVector3( uv2[3] = uv1[3] = LLVector2(mScreenWidth, mScreenHeight) );
|
||||
|
||||
mVBO->flush();
|
||||
}
|
||||
|
||||
checkError();
|
||||
createNightVisionShader();
|
||||
//createBloomShader();
|
||||
createColorFilterShader();
|
||||
createGaussBlurShader();
|
||||
createNoiseTexture();
|
||||
checkError();
|
||||
}
|
||||
|
||||
@@ -202,9 +195,7 @@ inline bool LLPostProcess::shadersEnabled(void)
|
||||
{
|
||||
return (tweaks.useColorFilter().asBoolean() ||
|
||||
tweaks.useNightVisionShader().asBoolean() ||
|
||||
/*tweaks.useBloomShader().asBoolean() ||*/
|
||||
tweaks.useGaussBlurFilter().asBoolean() );
|
||||
|
||||
}
|
||||
|
||||
void LLPostProcess::applyShaders(void)
|
||||
@@ -220,7 +211,7 @@ void LLPostProcess::applyShaders(void)
|
||||
{
|
||||
/// If any of the above shaders have been called update the frame buffer;
|
||||
if (copy_buffer)
|
||||
copyFrameBuffer(mSceneRenderTexture->getTexName(), screenW, screenH);
|
||||
copyFrameBuffer();
|
||||
applyGaussBlurShader();
|
||||
checkError();
|
||||
copy_buffer = true;
|
||||
@@ -229,143 +220,65 @@ void LLPostProcess::applyShaders(void)
|
||||
{
|
||||
/// If any of the above shaders have been called update the frame buffer;
|
||||
if (copy_buffer)
|
||||
copyFrameBuffer(mSceneRenderTexture->getTexName(), screenW, screenH);
|
||||
copyFrameBuffer();
|
||||
applyNightVisionShader();
|
||||
checkError();
|
||||
copy_buffer = true;
|
||||
}
|
||||
/*if (tweaks.useBloomShader())
|
||||
{
|
||||
/// If any of the above shaders have been called update the frame buffer;
|
||||
if (copy_buffer)
|
||||
copyFrameBuffer(mSceneRenderTexture->getTexName(), screenW, screenH);
|
||||
applyBloomShader();
|
||||
checkError();
|
||||
copy_buffer = true;
|
||||
}*/
|
||||
}
|
||||
|
||||
void LLPostProcess::applyColorFilterShader(void)
|
||||
{
|
||||
if(gPostColorFilterProgram.mProgramObject == 0)
|
||||
return;
|
||||
/* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.*/
|
||||
|
||||
gPostColorFilterProgram.bind();
|
||||
|
||||
gGL.getTexUnit(0)->activate();
|
||||
gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
|
||||
gGL.getTexUnit(0)->bind(mSceneRenderTexture);
|
||||
|
||||
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mSceneRenderTexture.get()->getTexName());
|
||||
|
||||
getShaderUniforms(colorFilterUniforms, gPostColorFilterProgram.mProgramObject);
|
||||
glUniform1iARB(colorFilterUniforms["RenderTexture"], 0);
|
||||
glUniform1fARB(colorFilterUniforms["gamma"], tweaks.getGamma());
|
||||
glUniform1fARB(colorFilterUniforms["brightness"], tweaks.getBrightness());
|
||||
glUniform1fARB(colorFilterUniforms["contrast"], tweaks.getContrast());
|
||||
gPostColorFilterProgram.uniform1f("gamma", tweaks.getGamma());
|
||||
gPostColorFilterProgram.uniform1f("brightness", tweaks.getBrightness());
|
||||
gPostColorFilterProgram.uniform1f("contrast", tweaks.getContrast());
|
||||
float baseI = (tweaks.getContrastBaseR() + tweaks.getContrastBaseG() + tweaks.getContrastBaseB()) / 3.0f;
|
||||
baseI = tweaks.getContrastBaseIntensity() / ((baseI < 0.001f) ? 0.001f : baseI);
|
||||
float baseR = tweaks.getContrastBaseR() * baseI;
|
||||
float baseG = tweaks.getContrastBaseG() * baseI;
|
||||
float baseB = tweaks.getContrastBaseB() * baseI;
|
||||
glUniform3fARB(colorFilterUniforms["contrastBase"], baseR, baseG, baseB);
|
||||
glUniform1fARB(colorFilterUniforms["saturation"], tweaks.getSaturation());
|
||||
glUniform3fARB(colorFilterUniforms["lumWeights"], LUMINANCE_R, LUMINANCE_G, LUMINANCE_B);
|
||||
gPostColorFilterProgram.uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV);
|
||||
gPostColorFilterProgram.uniform1f("saturation", tweaks.getSaturation());
|
||||
gPostColorFilterProgram.uniform3fv("lumWeights", 1, LLVector3(LUMINANCE_R, LUMINANCE_G, LUMINANCE_B).mV);
|
||||
|
||||
LLGLEnable blend(GL_BLEND);
|
||||
gGL.setSceneBlendType(LLRender::BT_REPLACE);
|
||||
LLGLDepthTest depth(GL_FALSE);
|
||||
|
||||
/// Draw a screen space quad
|
||||
drawOrthoQuad(screenW, screenH, QUAD_NORMAL);
|
||||
drawOrthoQuad(QUAD_NORMAL);
|
||||
gPostColorFilterProgram.unbind();
|
||||
//*/
|
||||
}
|
||||
|
||||
void LLPostProcess::createColorFilterShader(void)
|
||||
{
|
||||
/// Define uniform names
|
||||
colorFilterUniforms["RenderTexture"] = 0;
|
||||
colorFilterUniforms["gamma"] = 0;
|
||||
colorFilterUniforms["brightness"] = 0;
|
||||
colorFilterUniforms["contrast"] = 0;
|
||||
colorFilterUniforms["contrastBase"] = 0;
|
||||
colorFilterUniforms["saturation"] = 0;
|
||||
colorFilterUniforms["lumWeights"] = 0;
|
||||
}
|
||||
|
||||
void LLPostProcess::applyNightVisionShader(void)
|
||||
{
|
||||
if(gPostNightVisionProgram.mProgramObject == 0)
|
||||
return;
|
||||
/* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.*/
|
||||
|
||||
gPostNightVisionProgram.bind();
|
||||
|
||||
gGL.getTexUnit(0)->activate();
|
||||
gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
|
||||
|
||||
getShaderUniforms(nightVisionUniforms, gPostNightVisionProgram.mProgramObject);
|
||||
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mSceneRenderTexture.get()->getTexName());
|
||||
glUniform1iARB(nightVisionUniforms["RenderTexture"], 0);
|
||||
|
||||
gGL.getTexUnit(1)->activate();
|
||||
gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
gGL.getTexUnit(1)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseTexture.get()->getTexName());
|
||||
glUniform1iARB(nightVisionUniforms["NoiseTexture"], 1);
|
||||
|
||||
gGL.getTexUnit(0)->bind(mSceneRenderTexture);
|
||||
gGL.getTexUnit(1)->bind(mNoiseTexture);
|
||||
|
||||
glUniform1fARB(nightVisionUniforms["brightMult"], tweaks.getBrightMult());
|
||||
glUniform1fARB(nightVisionUniforms["noiseStrength"], tweaks.getNoiseStrength());
|
||||
noiseTextureScale = 0.01f + ((101.f - tweaks.getNoiseSize()) / 100.f);
|
||||
noiseTextureScale *= (screenH / NOISE_SIZE);
|
||||
gPostNightVisionProgram.uniform1f("brightMult", tweaks.getBrightMult());
|
||||
gPostNightVisionProgram.uniform1f("noiseStrength", tweaks.getNoiseStrength());
|
||||
mNoiseTextureScale = 0.001f + ((100.f - tweaks.getNoiseSize()) / 100.f);
|
||||
mNoiseTextureScale *= (mScreenHeight / NOISE_SIZE);
|
||||
|
||||
|
||||
glUniform3fARB(nightVisionUniforms["lumWeights"], LUMINANCE_R, LUMINANCE_G, LUMINANCE_B);
|
||||
|
||||
LLGLEnable blend(GL_BLEND);
|
||||
gGL.setSceneBlendType(LLRender::BT_REPLACE);
|
||||
LLGLDepthTest depth(GL_FALSE);
|
||||
|
||||
/// Draw a screen space quad
|
||||
drawOrthoQuad(screenW, screenH, QUAD_NOISE);
|
||||
drawOrthoQuad(QUAD_NOISE);
|
||||
gPostNightVisionProgram.unbind();
|
||||
gGL.getTexUnit(0)->activate();
|
||||
//*/
|
||||
}
|
||||
|
||||
void LLPostProcess::createNightVisionShader(void)
|
||||
{
|
||||
/// Define uniform names
|
||||
nightVisionUniforms["RenderTexture"] = 0;
|
||||
nightVisionUniforms["NoiseTexture"] = 0;
|
||||
nightVisionUniforms["brightMult"] = 0;
|
||||
nightVisionUniforms["noiseStrength"] = 0;
|
||||
nightVisionUniforms["lumWeights"] = 0;
|
||||
|
||||
createNoiseTexture(mNoiseTexture);
|
||||
}
|
||||
|
||||
void LLPostProcess::applyBloomShader(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LLPostProcess::createBloomShader(void)
|
||||
{
|
||||
//createTexture(mTempBloomTexture, unsigned(screenW * 0.5), unsigned(screenH * 0.5));
|
||||
|
||||
/// Create Bloom Extract Shader
|
||||
bloomExtractUniforms["RenderTexture"] = 0;
|
||||
bloomExtractUniforms["extractLow"] = 0;
|
||||
bloomExtractUniforms["extractHigh"] = 0;
|
||||
bloomExtractUniforms["lumWeights"] = 0;
|
||||
|
||||
/// Create Bloom Blur Shader
|
||||
bloomBlurUniforms["RenderTexture"] = 0;
|
||||
bloomBlurUniforms["bloomStrength"] = 0;
|
||||
bloomBlurUniforms["texelSize"] = 0;
|
||||
bloomBlurUniforms["blurDirection"] = 0;
|
||||
bloomBlurUniforms["blurWidth"] = 0;
|
||||
}
|
||||
|
||||
void LLPostProcess::applyGaussBlurShader(void)
|
||||
@@ -374,56 +287,33 @@ void LLPostProcess::applyGaussBlurShader(void)
|
||||
if(!pass_count || gPostGaussianBlurProgram.mProgramObject == 0)
|
||||
return;
|
||||
|
||||
getShaderUniforms(gaussBlurUniforms, gPostGaussianBlurProgram.mProgramObject);
|
||||
gPostGaussianBlurProgram.bind();
|
||||
gGL.getTexUnit(0)->activate();
|
||||
gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
|
||||
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mSceneRenderTexture.get()->getTexName());
|
||||
|
||||
gGL.getTexUnit(0)->bind(mSceneRenderTexture);
|
||||
|
||||
LLGLEnable blend(GL_BLEND);
|
||||
LLGLDepthTest depth(GL_FALSE);
|
||||
gGL.setSceneBlendType(LLRender::BT_REPLACE);
|
||||
glUniform1iARB(gaussBlurUniforms["RenderTexture"], 0);
|
||||
GLint horiz_pass = gaussBlurUniforms["horizontalPass"];
|
||||
GLint horiz_pass = gPostGaussianBlurProgram.getUniformLocation("horizontalPass");
|
||||
for(int i = 0;i<pass_count;++i)
|
||||
{
|
||||
for(int j = 0;j<2;++j)
|
||||
{
|
||||
if(i || j)
|
||||
copyFrameBuffer(mSceneRenderTexture->getTexName(), screenW, screenH);
|
||||
copyFrameBuffer();
|
||||
glUniform1iARB(horiz_pass, j);
|
||||
drawOrthoQuad(screenW, screenH, QUAD_NORMAL);
|
||||
|
||||
drawOrthoQuad(QUAD_NORMAL);
|
||||
}
|
||||
}
|
||||
gPostGaussianBlurProgram.unbind();
|
||||
|
||||
}
|
||||
|
||||
void LLPostProcess::createGaussBlurShader(void)
|
||||
{
|
||||
gaussBlurUniforms["RenderTexture"] = 0;
|
||||
gaussBlurUniforms["horizontalPass"] = 0;
|
||||
}
|
||||
|
||||
void LLPostProcess::getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog)
|
||||
{
|
||||
/// Find uniform locations and insert into map
|
||||
std::map<const char *, GLuint>::iterator i;
|
||||
for (i = uniforms.begin(); i != uniforms.end(); ++i){
|
||||
i->second = glGetUniformLocationARB(prog, i->first);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPostProcess::doEffects(void)
|
||||
{
|
||||
/// Save GL State
|
||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||
glPushClientAttrib(GL_ALL_ATTRIB_BITS);
|
||||
LLVertexBuffer::unbind();
|
||||
|
||||
/// Copy the screen buffer to the render texture
|
||||
{
|
||||
copyFrameBuffer(mSceneRenderTexture->getTexName(), screenW, screenH);
|
||||
}
|
||||
copyFrameBuffer();
|
||||
|
||||
/// Clear the frame buffer.
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
@@ -431,146 +321,73 @@ void LLPostProcess::doEffects(void)
|
||||
LLGLDisable(GL_DEPTH_TEST);
|
||||
|
||||
/// Change to an orthogonal view
|
||||
viewOrthogonal(screenW, screenH);
|
||||
gGL.matrixMode(LLRender::MM_PROJECTION);
|
||||
gGL.pushMatrix();
|
||||
gGL.loadIdentity();
|
||||
gGL.ortho( 0.f, (GLdouble) mScreenWidth, 0.f, (GLdouble) mScreenHeight, -1.f, 1.f );
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
gGL.pushMatrix();
|
||||
gGL.loadIdentity();
|
||||
|
||||
checkError();
|
||||
applyShaders();
|
||||
|
||||
LLGLSLShader::bindNoShader();
|
||||
checkError();
|
||||
|
||||
LLGLSLShader::bindNoShader();
|
||||
|
||||
/// Change to a perspective view
|
||||
viewPerspective();
|
||||
gGL.flush();
|
||||
gGL.matrixMode( LLRender::MM_PROJECTION );
|
||||
gGL.popMatrix();
|
||||
gGL.matrixMode( LLRender::MM_MODELVIEW );
|
||||
gGL.popMatrix();
|
||||
|
||||
/// Reset GL State
|
||||
glPopClientAttrib();
|
||||
glPopAttrib();
|
||||
gGL.getTexUnit(1)->disable();
|
||||
checkError();
|
||||
}
|
||||
|
||||
void LLPostProcess::copyFrameBuffer(LLGLuint texture, unsigned int width, unsigned int height)
|
||||
void LLPostProcess::copyFrameBuffer()
|
||||
{
|
||||
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, texture);
|
||||
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, width, height, 0);
|
||||
gGL.getTexUnit(0)->bindManual(mSceneRenderTexture->getTarget(), mSceneRenderTexture->getTexName());
|
||||
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, mScreenWidth, mScreenHeight, 0);
|
||||
}
|
||||
|
||||
inline void InitQuadArray(F32 *arr, const F32 x, const F32 y, const F32 width, const F32 height)
|
||||
void LLPostProcess::drawOrthoQuad(QuadType type)
|
||||
{
|
||||
//Lower left
|
||||
*(arr++)=x;
|
||||
*(arr++)=y;
|
||||
//Upper left
|
||||
*(arr++)=x;
|
||||
*(arr++)=y+height;
|
||||
//Upper right
|
||||
*(arr++)=x+width;
|
||||
*(arr++)=y+height;
|
||||
//Lower right
|
||||
*(arr++)=x+width;
|
||||
*(arr++)=y;
|
||||
}
|
||||
void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadType type)
|
||||
{
|
||||
#if 1
|
||||
//Redid the logic here. Less cases. No longer using immediate mode.
|
||||
bool second_tex = true;
|
||||
//Vertex array used for all post-processing effects
|
||||
static F32 verts[8];
|
||||
//Texture coord array used for all post-processing effects
|
||||
static F32 tex0[8];
|
||||
//Texture coord array used for relevant post processing effects
|
||||
static F32 tex1[8];
|
||||
|
||||
//Set up vertex array
|
||||
InitQuadArray(verts, 0.f, 0.f, width, height);
|
||||
|
||||
//Set up first texture coords
|
||||
if(type == QUAD_BLOOM_EXTRACT)
|
||||
if(type == QUAD_NOISE)
|
||||
{
|
||||
InitQuadArray(tex0, 0.f, 0.f, width*2.f, height*2.f);
|
||||
second_tex = false;
|
||||
//This could also be done through uniforms.
|
||||
LLStrider<LLVector2> uv2;
|
||||
mVBO->getTexCoord1Strider(uv2);
|
||||
|
||||
float offs[2] = {(float) rand() / (float) RAND_MAX, (float) rand() / (float) RAND_MAX};
|
||||
float scale[2] = {mScreenWidth * mNoiseTextureScale / mScreenHeight, mNoiseTextureScale};
|
||||
uv2[0] = LLVector2(offs[0],offs[1]);
|
||||
uv2[1] = LLVector2(offs[0],offs[1]+scale[1]);
|
||||
uv2[2] = LLVector2(offs[0]+scale[0],offs[1]);
|
||||
uv2[3] = LLVector2(uv2[2].mV[0],uv2[1].mV[1]);
|
||||
mVBO->flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
InitQuadArray(tex0, 0.f, 0.f, width, height);
|
||||
//Set up second texture coords
|
||||
if( type == QUAD_BLOOM_COMBINE)
|
||||
InitQuadArray(tex1, 0.f, 0.f, width*.5, height*.5);
|
||||
else if( type == QUAD_NOISE )
|
||||
InitQuadArray(tex1, ((float) rand() / (float) RAND_MAX), ((float) rand() / (float) RAND_MAX),
|
||||
width * noiseTextureScale / height, noiseTextureScale);
|
||||
else
|
||||
second_tex = false;
|
||||
}
|
||||
|
||||
//Prepare to render
|
||||
glEnableClientState( GL_VERTEX_ARRAY );
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(F32)*2, verts);
|
||||
if(second_tex) //tex1 setup
|
||||
{
|
||||
glClientActiveTextureARB(GL_TEXTURE1);
|
||||
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(F32)*2, tex1);
|
||||
}
|
||||
glClientActiveTextureARB(GL_TEXTURE0);
|
||||
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(F32)*2, tex0);
|
||||
|
||||
//Render
|
||||
glDrawArrays(GL_QUADS, 0, sizeof(verts)/sizeof(verts[0]));
|
||||
|
||||
//Cleanup
|
||||
glDisableClientState( GL_VERTEX_ARRAY );
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY ); //for tex0
|
||||
if(second_tex)
|
||||
{
|
||||
glClientActiveTextureARB(GL_TEXTURE1);
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY ); //for tex1
|
||||
}
|
||||
#endif
|
||||
U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | (type == QUAD_NOISE ? LLVertexBuffer::MAP_TEXCOORD1 : 0);
|
||||
mVBO->setBuffer(mask);
|
||||
mVBO->drawArrays(LLRender::TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height)
|
||||
void LLPostProcess::createScreenTexture()
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho( 0.f, (GLdouble) width, 0.f, (GLdouble) height, -1.f, 1.f );
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
}
|
||||
std::vector<GLubyte> data(mScreenWidth * mScreenHeight * 3, 0) ;
|
||||
|
||||
void LLPostProcess::viewPerspective(void)
|
||||
{
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glPopMatrix();
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void LLPostProcess::changeOrthogonal(unsigned int width, unsigned int height)
|
||||
{
|
||||
viewPerspective();
|
||||
viewOrthogonal(width, height);
|
||||
}
|
||||
|
||||
void LLPostProcess::createTexture(LLPointer<LLImageGL>& texture, unsigned int width, unsigned int height)
|
||||
{
|
||||
std::vector<GLubyte> data(width * height * 4, 0) ;
|
||||
|
||||
texture = new LLImageGL(FALSE) ;
|
||||
if(texture->createGLTexture())
|
||||
mSceneRenderTexture = new LLImageGL(FALSE) ;
|
||||
if(mSceneRenderTexture->createGLTexture())
|
||||
{
|
||||
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, texture->getTexName());
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
|
||||
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mSceneRenderTexture->getTexName());
|
||||
LLImageGL::setManualImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, mScreenWidth, mScreenHeight, GL_RGB, GL_UNSIGNED_BYTE, &data[0]);
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
|
||||
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPostProcess::createNoiseTexture(LLPointer<LLImageGL>& texture)
|
||||
void LLPostProcess::createNoiseTexture()
|
||||
{
|
||||
std::vector<GLubyte> buffer(NOISE_SIZE * NOISE_SIZE);
|
||||
for (unsigned int i = 0; i < NOISE_SIZE; i++){
|
||||
@@ -579,10 +396,10 @@ void LLPostProcess::createNoiseTexture(LLPointer<LLImageGL>& texture)
|
||||
}
|
||||
}
|
||||
|
||||
texture = new LLImageGL(FALSE) ;
|
||||
if(texture->createGLTexture())
|
||||
mNoiseTexture = new LLImageGL(FALSE) ;
|
||||
if(mNoiseTexture->createGLTexture())
|
||||
{
|
||||
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName());
|
||||
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseTexture->getTexName());
|
||||
LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]);
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
|
||||
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
|
||||
@@ -617,30 +434,3 @@ bool LLPostProcess::checkError(void)
|
||||
return retCode;
|
||||
}
|
||||
|
||||
void LLPostProcess::checkShaderError(GLhandleARB shader)
|
||||
{
|
||||
GLint infologLength = 0;
|
||||
GLint charsWritten = 0;
|
||||
GLchar *infoLog;
|
||||
|
||||
checkError(); // Check for OpenGL errors
|
||||
|
||||
glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);
|
||||
|
||||
checkError(); // Check for OpenGL errors
|
||||
|
||||
if (infologLength > 0)
|
||||
{
|
||||
infoLog = (GLchar *)malloc(infologLength);
|
||||
if (infoLog == NULL)
|
||||
{
|
||||
/// Could not allocate infolog buffer
|
||||
return;
|
||||
}
|
||||
glGetInfoLogARB(shader, infologLength, &charsWritten, infoLog);
|
||||
// shaderErrorLog << (char *) infoLog << std::endl;
|
||||
mShaderErrorString = (char *) infoLog;
|
||||
free(infoLog);
|
||||
}
|
||||
checkError(); // Check for OpenGL errors
|
||||
}
|
||||
|
||||
@@ -38,19 +38,17 @@
|
||||
#include "llgl.h"
|
||||
#include "llglheaders.h"
|
||||
|
||||
class LLPostProcess
|
||||
class LLPostProcess : public LLSingleton<LLPostProcess>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef enum _QuadType {
|
||||
QUAD_NORMAL,
|
||||
QUAD_NOISE,
|
||||
QUAD_BLOOM_EXTRACT,
|
||||
QUAD_BLOOM_COMBINE
|
||||
QUAD_NOISE
|
||||
} QuadType;
|
||||
|
||||
/// GLSL Shader Encapsulation Struct
|
||||
typedef std::map<const char *, GLuint> glslUniforms;
|
||||
//typedef std::map<const char *, GLuint> glslUniforms;
|
||||
|
||||
struct PostProcessTweaks : public LLSD {
|
||||
inline PostProcessTweaks() : LLSD(LLSD::emptyMap())
|
||||
@@ -69,22 +67,6 @@ public:
|
||||
return (*this)["noise_size"];
|
||||
}
|
||||
|
||||
inline LLSD & extractLow() {
|
||||
return (*this)["extract_low"];
|
||||
}
|
||||
|
||||
inline LLSD & extractHigh() {
|
||||
return (*this)["extract_high"];
|
||||
}
|
||||
|
||||
inline LLSD & bloomWidth() {
|
||||
return (*this)["bloom_width"];
|
||||
}
|
||||
|
||||
inline LLSD & bloomStrength() {
|
||||
return (*this)["bloom_strength"];
|
||||
}
|
||||
|
||||
inline LLSD & brightness() {
|
||||
return (*this)["brightness"];
|
||||
}
|
||||
@@ -117,10 +99,6 @@ public:
|
||||
return (*this)["enable_night_vision"];
|
||||
}
|
||||
|
||||
/*inline LLSD & useBloomShader() {
|
||||
return (*this)["enable_bloom"];
|
||||
}*/
|
||||
|
||||
inline LLSD & useColorFilter() {
|
||||
return (*this)["enable_color_filter"];
|
||||
}
|
||||
@@ -141,22 +119,6 @@ public:
|
||||
return F32((*this)["noise_size"].asReal());
|
||||
}
|
||||
|
||||
inline F32 getExtractLow() const {
|
||||
return F32((*this)["extract_low"].asReal());
|
||||
}
|
||||
|
||||
inline F32 getExtractHigh() const {
|
||||
return F32((*this)["extract_high"].asReal());
|
||||
}
|
||||
|
||||
inline F32 getBloomWidth() const {
|
||||
return F32((*this)["bloom_width"].asReal());
|
||||
}
|
||||
|
||||
inline F32 getBloomStrength() const {
|
||||
return F32((*this)["bloom_strength"].asReal());
|
||||
}
|
||||
|
||||
inline F32 getGamma() const {
|
||||
return F32((*this)["gamma"].asReal());
|
||||
}
|
||||
@@ -193,17 +155,16 @@ public:
|
||||
return (*this)["gauss_blur_passes"];
|
||||
}
|
||||
};
|
||||
|
||||
bool initialized;
|
||||
|
||||
PostProcessTweaks tweaks;
|
||||
|
||||
// the map of all availible effects
|
||||
LLSD mAllEffects;
|
||||
|
||||
private:
|
||||
LLPointer<LLVertexBuffer> mVBO;
|
||||
LLPointer<LLImageGL> mSceneRenderTexture ;
|
||||
LLPointer<LLImageGL> mNoiseTexture ;
|
||||
LLPointer<LLImageGL> mTempBloomTexture ;
|
||||
|
||||
public:
|
||||
LLPostProcess(void);
|
||||
@@ -213,9 +174,6 @@ public:
|
||||
void apply(unsigned int width, unsigned int height);
|
||||
void invalidate() ;
|
||||
|
||||
/// Perform global initialization for this class.
|
||||
static void initClass(void);
|
||||
|
||||
// Cleanup of global data that's only inited once per class.
|
||||
static void cleanupClass();
|
||||
|
||||
@@ -230,18 +188,11 @@ public:
|
||||
private:
|
||||
/// read in from file
|
||||
std::string mShaderErrorString;
|
||||
unsigned int screenW;
|
||||
unsigned int screenH;
|
||||
unsigned int mScreenWidth;
|
||||
unsigned int mScreenHeight;
|
||||
|
||||
float noiseTextureScale;
|
||||
float mNoiseTextureScale;
|
||||
|
||||
/// Shader Uniforms
|
||||
glslUniforms nightVisionUniforms;
|
||||
glslUniforms bloomExtractUniforms;
|
||||
glslUniforms bloomBlurUniforms;
|
||||
glslUniforms colorFilterUniforms;
|
||||
glslUniforms gaussBlurUniforms;
|
||||
|
||||
// the name of currently selected effect in mAllEffects
|
||||
// invariant: tweaks == mAllEffects[mSelectedEffectName]
|
||||
std::string mSelectedEffectName;
|
||||
@@ -253,35 +204,19 @@ private:
|
||||
bool shadersEnabled(void);
|
||||
|
||||
/// Night Vision Functions
|
||||
void createNightVisionShader(void);
|
||||
void applyNightVisionShader(void);
|
||||
|
||||
/// Bloom Functions
|
||||
void createBloomShader(void);
|
||||
void applyBloomShader(void);
|
||||
|
||||
/// Color Filter Functions
|
||||
void createColorFilterShader(void);
|
||||
void applyColorFilterShader(void);
|
||||
|
||||
/// Gaussian blur Filter Functions
|
||||
void createGaussBlurShader(void);
|
||||
void applyGaussBlurShader(void);
|
||||
|
||||
/// OpenGL Helper Functions
|
||||
void getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog);
|
||||
void createTexture(LLPointer<LLImageGL>& texture, unsigned int width, unsigned int height);
|
||||
void copyFrameBuffer(LLGLuint texture, unsigned int width, unsigned int height);
|
||||
void createNoiseTexture(LLPointer<LLImageGL>& texture);
|
||||
void copyFrameBuffer();
|
||||
void createScreenTexture();
|
||||
void createNoiseTexture();
|
||||
bool checkError(void);
|
||||
void checkShaderError(GLhandleARB shader);
|
||||
void drawOrthoQuad(unsigned int width, unsigned int height, QuadType type);
|
||||
void viewOrthogonal(unsigned int width, unsigned int height);
|
||||
void changeOrthogonal(unsigned int width, unsigned int height);
|
||||
void viewPerspective(void);
|
||||
void drawOrthoQuad(QuadType type);
|
||||
};
|
||||
|
||||
extern LLPostProcess * gPostProcess;
|
||||
|
||||
|
||||
#endif // LL_POSTPROCESS_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,8 +45,10 @@
|
||||
#include "v4coloru.h"
|
||||
#include "v4math.h"
|
||||
#include "llstrider.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llglheaders.h"
|
||||
#include "llmatrix4a.h"
|
||||
#include "glh/glh_linear.h"
|
||||
|
||||
class LLVertexBuffer;
|
||||
class LLCubeMap;
|
||||
@@ -54,11 +56,14 @@ class LLImageGL;
|
||||
class LLRenderTarget;
|
||||
class LLTexture ;
|
||||
|
||||
#define LL_MATRIX_STACK_DEPTH 32
|
||||
|
||||
class LLTexUnit
|
||||
{
|
||||
friend class LLRender;
|
||||
public:
|
||||
static U32 sWhiteTexture;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TT_TEXTURE = 0, // Standard 2D Texture
|
||||
@@ -240,6 +245,8 @@ public:
|
||||
void setSpotDirection(const LLVector3& direction);
|
||||
|
||||
protected:
|
||||
friend class LLRender;
|
||||
|
||||
S32 mIndex;
|
||||
bool mEnabled;
|
||||
LLColor4 mDiffuse;
|
||||
@@ -312,6 +319,18 @@ public:
|
||||
BF_UNDEF
|
||||
} eBlendFactor;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MM_MODELVIEW = 0,
|
||||
MM_PROJECTION,
|
||||
MM_TEXTURE0,
|
||||
MM_TEXTURE1,
|
||||
MM_TEXTURE2,
|
||||
MM_TEXTURE3,
|
||||
NUM_MATRIX_MODES,
|
||||
MM_TEXTURE
|
||||
} eMatrixMode;
|
||||
|
||||
LLRender();
|
||||
~LLRender();
|
||||
void init() ;
|
||||
@@ -323,8 +342,29 @@ public:
|
||||
|
||||
void translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z);
|
||||
void scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z);
|
||||
void rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z);
|
||||
void ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar);
|
||||
|
||||
void pushMatrix();
|
||||
void popMatrix();
|
||||
void loadMatrix(const GLfloat* m);
|
||||
void loadIdentity();
|
||||
void multMatrix(const GLfloat* m);
|
||||
void matrixMode(U32 mode);
|
||||
|
||||
const glh::matrix4f& getModelviewMatrix();
|
||||
const glh::matrix4f& getProjectionMatrix();
|
||||
|
||||
void syncMatrices();
|
||||
void syncLightState();
|
||||
|
||||
void translateUI(F32 x, F32 y, F32 z);
|
||||
void scaleUI(F32 x, F32 y, F32 z);
|
||||
void pushUIMatrix();
|
||||
void popUIMatrix();
|
||||
void loadUIIdentity();
|
||||
LLVector3 getUITranslation();
|
||||
LLVector3 getUIScale();
|
||||
|
||||
void flush();
|
||||
|
||||
@@ -347,9 +387,16 @@ public:
|
||||
void color3fv(const GLfloat* c);
|
||||
void color4ubv(const GLubyte* c);
|
||||
|
||||
void diffuseColor3f(F32 r, F32 g, F32 b);
|
||||
void diffuseColor3fv(const F32* c);
|
||||
void diffuseColor4f(F32 r, F32 g, F32 b, F32 a);
|
||||
void diffuseColor4fv(const F32* c);
|
||||
void diffuseColor4ubv(const U8* c);
|
||||
|
||||
void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count);
|
||||
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count);
|
||||
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
|
||||
|
||||
void setColorMask(bool writeColor, bool writeAlpha);
|
||||
void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha);
|
||||
void setSceneBlendType(eBlendType type);
|
||||
@@ -363,6 +410,7 @@ public:
|
||||
eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor);
|
||||
|
||||
LLLightState* getLight(U32 index);
|
||||
void setAmbientLightColor(const LLColor4& color);
|
||||
|
||||
LLTexUnit* getTexUnit(U32 index);
|
||||
|
||||
@@ -382,9 +430,23 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static U32 sUICalls;
|
||||
static U32 sUIVerts;
|
||||
static bool sGLCoreProfile;
|
||||
|
||||
private:
|
||||
bool mDirty;
|
||||
friend class LLLightState;
|
||||
|
||||
U32 mMatrixMode;
|
||||
U32 mMatIdx[NUM_MATRIX_MODES];
|
||||
U32 mMatHash[NUM_MATRIX_MODES];
|
||||
glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH];
|
||||
U32 mCurMatHash[NUM_MATRIX_MODES];
|
||||
U32 mLightHash;
|
||||
LLColor4 mAmbientLightColor;
|
||||
|
||||
bool mDirty;
|
||||
U32 mQuadCycle;
|
||||
U32 mCount;
|
||||
U32 mMode;
|
||||
U32 mCurrTextureUnitIndex;
|
||||
@@ -406,12 +468,16 @@ private:
|
||||
eBlendFactor mCurrBlendAlphaDFactor;
|
||||
|
||||
F32 mMaxAnisotropy;
|
||||
|
||||
std::vector<LLVector3> mUIOffset;
|
||||
std::vector<LLVector3> mUIScale;
|
||||
|
||||
};
|
||||
|
||||
extern F64 gGLModelView[16];
|
||||
extern F64 gGLLastModelView[16];
|
||||
extern F64 gGLLastProjection[16];
|
||||
extern F64 gGLProjection[16];
|
||||
extern F32 gGLModelView[16];
|
||||
extern F32 gGLLastModelView[16];
|
||||
extern F32 gGLLastProjection[16];
|
||||
extern F32 gGLProjection[16];
|
||||
extern S32 gGLViewport[4];
|
||||
|
||||
extern LLRender gGL;
|
||||
|
||||
@@ -41,106 +41,12 @@
|
||||
|
||||
#include "llglheaders.h"
|
||||
|
||||
GLUquadricObj *gQuadObj2 = NULL;
|
||||
LLRenderSphere gSphere;
|
||||
|
||||
void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks);
|
||||
|
||||
void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks)
|
||||
{
|
||||
if (!gQuadObj2)
|
||||
{
|
||||
gQuadObj2 = gluNewQuadric();
|
||||
if (!gQuadObj2)
|
||||
{
|
||||
llwarns << "drawSolidSphere couldn't allocate quadric" << llendl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gluQuadricDrawStyle(gQuadObj2, GLU_FILL);
|
||||
gluQuadricNormals(gQuadObj2, GLU_SMOOTH);
|
||||
// If we ever changed/used the texture or orientation state
|
||||
// of quadObj, we'd need to change it to the defaults here
|
||||
// with gluQuadricTexture and/or gluQuadricOrientation.
|
||||
gluQuadricTexture(gQuadObj2, GL_TRUE);
|
||||
gluSphere(gQuadObj2, radius, slices, stacks);
|
||||
}
|
||||
|
||||
|
||||
// A couple thoughts on sphere drawing:
|
||||
// 1) You need more slices than stacks, but little less than 2:1
|
||||
// 2) At low LOD, setting stacks to an odd number avoids a "band" around the equator, making things look smoother
|
||||
void LLRenderSphere::prerender()
|
||||
{
|
||||
// Create a series of display lists for different LODs
|
||||
mDList[0] = glGenLists(1);
|
||||
glNewList(mDList[0], GL_COMPILE);
|
||||
drawSolidSphere(1.0, 30, 20);
|
||||
glEndList();
|
||||
|
||||
mDList[1] = glGenLists(1);
|
||||
glNewList(mDList[1], GL_COMPILE);
|
||||
drawSolidSphere(1.0, 20, 15);
|
||||
glEndList();
|
||||
|
||||
mDList[2] = glGenLists(1);
|
||||
glNewList(mDList[2], GL_COMPILE);
|
||||
drawSolidSphere(1.0, 12, 8);
|
||||
glEndList();
|
||||
|
||||
mDList[3] = glGenLists(1);
|
||||
glNewList(mDList[3], GL_COMPILE);
|
||||
drawSolidSphere(1.0, 8, 5);
|
||||
glEndList();
|
||||
}
|
||||
|
||||
void LLRenderSphere::cleanupGL()
|
||||
{
|
||||
for (S32 detail = 0; detail < 4; detail++)
|
||||
{
|
||||
glDeleteLists(mDList[detail], 1);
|
||||
mDList[detail] = 0;
|
||||
}
|
||||
|
||||
if (gQuadObj2)
|
||||
{
|
||||
gluDeleteQuadric(gQuadObj2);
|
||||
gQuadObj2 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Constants here are empirically derived from my eyeballs, JNC
|
||||
//
|
||||
// The toughest adjustment is the cutoff for the lowest LOD
|
||||
// Maybe we should have more LODs at the low end?
|
||||
void LLRenderSphere::render(F32 pixel_area)
|
||||
{
|
||||
S32 level_of_detail;
|
||||
|
||||
if (pixel_area > 10000.f)
|
||||
{
|
||||
level_of_detail = 0;
|
||||
}
|
||||
else if (pixel_area > 800.f)
|
||||
{
|
||||
level_of_detail = 1;
|
||||
}
|
||||
else if (pixel_area > 100.f)
|
||||
{
|
||||
level_of_detail = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
level_of_detail = 3;
|
||||
}
|
||||
glCallList(mDList[level_of_detail]);
|
||||
}
|
||||
|
||||
|
||||
void LLRenderSphere::render()
|
||||
{
|
||||
glCallList(mDList[0]);
|
||||
renderGGL();
|
||||
gGL.flush();
|
||||
}
|
||||
|
||||
inline LLVector3 polar_to_cart(F32 latitude, F32 longitude)
|
||||
|
||||
@@ -46,11 +46,6 @@ void lat2xyz(LLVector3 * result, F32 lat, F32 lon); // utility routine
|
||||
class LLRenderSphere
|
||||
{
|
||||
public:
|
||||
LLGLuint mDList[5];
|
||||
|
||||
void prerender();
|
||||
void cleanupGL();
|
||||
void render(F32 pixel_area); // of a box of size 1.0 at that position
|
||||
void render(); // render at highest LOD
|
||||
void renderGGL(); // render using LLRender
|
||||
|
||||
|
||||
@@ -37,8 +37,7 @@
|
||||
#include "llgl.h"
|
||||
|
||||
LLRenderTarget* LLRenderTarget::sBoundTarget = NULL;
|
||||
|
||||
|
||||
U32 LLRenderTarget::sBytesAllocated = 0;
|
||||
|
||||
void check_framebuffer_status()
|
||||
{
|
||||
@@ -69,7 +68,6 @@ LLRenderTarget::LLRenderTarget() :
|
||||
mUseDepth(false),
|
||||
mRenderDepth(false),
|
||||
mUsage(LLTexUnit::TT_TEXTURE),
|
||||
mSamples(0),
|
||||
mSampleBuffer(NULL)
|
||||
{
|
||||
}
|
||||
@@ -156,6 +154,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
|
||||
|
||||
stop_glerror();
|
||||
|
||||
|
||||
{
|
||||
clear_glerror();
|
||||
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
@@ -165,32 +164,33 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sBytesAllocated += mResX*mResY*4;
|
||||
|
||||
stop_glerror();
|
||||
|
||||
{
|
||||
if (offset == 0)
|
||||
{ //use bilinear filtering on single texture render targets that aren't multisampled
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
|
||||
stop_glerror();
|
||||
}
|
||||
else
|
||||
{ //don't filter data attachments
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
if (offset == 0)
|
||||
{ //use bilinear filtering on single texture render targets that aren't multisampled
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
|
||||
stop_glerror();
|
||||
}
|
||||
else
|
||||
{ //don't filter data attachments
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
|
||||
{
|
||||
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
|
||||
stop_glerror();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ATI doesn't support mirrored repeat for rectangular textures.
|
||||
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
|
||||
stop_glerror();
|
||||
}
|
||||
if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
|
||||
{
|
||||
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
|
||||
stop_glerror();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ATI doesn't support mirrored repeat for rectangular textures.
|
||||
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
if (mFBO)
|
||||
@@ -233,13 +233,16 @@ bool LLRenderTarget::allocateDepth()
|
||||
{
|
||||
LLImageGL::generateTextures(1, &mDepth);
|
||||
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
|
||||
|
||||
U32 internal_type = LLTexUnit::getInternalType(mUsage);
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
|
||||
stop_glerror();
|
||||
clear_glerror();
|
||||
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
|
||||
}
|
||||
|
||||
sBytesAllocated += mResX*mResY*4;
|
||||
|
||||
if (glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
llwarns << "Unable to allocate depth buffer for render target." << llendl;
|
||||
@@ -309,14 +312,16 @@ void LLRenderTarget::release()
|
||||
stop_glerror();
|
||||
}
|
||||
mDepth = 0;
|
||||
|
||||
sBytesAllocated -= mResX*mResY*4;
|
||||
}
|
||||
else if (mUseDepth && mFBO)
|
||||
{ //detach shared depth buffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
if (mStencil)
|
||||
{ //attached as a renderbuffer
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
mStencil = false;
|
||||
}
|
||||
else
|
||||
@@ -334,6 +339,7 @@ void LLRenderTarget::release()
|
||||
|
||||
if (mTex.size() > 0)
|
||||
{
|
||||
sBytesAllocated -= mResX*mResY*4*mTex.size();
|
||||
LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
|
||||
mTex.clear();
|
||||
}
|
||||
@@ -520,7 +526,8 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
|
||||
gGL.flush();
|
||||
if (!source.mFBO || !mFBO)
|
||||
{
|
||||
llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
|
||||
llwarns << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSampleBuffer)
|
||||
@@ -574,7 +581,8 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
|
||||
{
|
||||
if (!source.mFBO)
|
||||
{
|
||||
llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
|
||||
llwarns << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
|
||||
return;
|
||||
}
|
||||
{
|
||||
GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? TRUE : FALSE;
|
||||
@@ -616,7 +624,8 @@ void LLRenderTarget::getViewport(S32* viewport)
|
||||
//==================================================
|
||||
// LLMultisampleBuffer implementation
|
||||
//==================================================
|
||||
LLMultisampleBuffer::LLMultisampleBuffer()
|
||||
LLMultisampleBuffer::LLMultisampleBuffer() :
|
||||
mSamples(0)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -636,12 +645,15 @@ void LLMultisampleBuffer::release()
|
||||
|
||||
if (mTex.size() > 0)
|
||||
{
|
||||
sBytesAllocated -= mResX*mResY*4*mResX*mResY*4*mTex.size();
|
||||
glDeleteRenderbuffers(mTex.size(), (GLuint *) &mTex[0]);
|
||||
mTex.clear();
|
||||
|
||||
}
|
||||
|
||||
if (mDepth)
|
||||
{
|
||||
sBytesAllocated -= mResX*mResY*4;
|
||||
glDeleteRenderbuffers(1, (GLuint *) &mDepth);
|
||||
mDepth = 0;
|
||||
}
|
||||
@@ -736,6 +748,8 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth
|
||||
stop_glerror();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
stop_glerror();
|
||||
|
||||
|
||||
}
|
||||
|
||||
return addColorAttachment(color_fmt);
|
||||
@@ -766,6 +780,9 @@ bool LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
|
||||
llwarns << "Unable to allocate color buffer for multisample render target." << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
sBytesAllocated += mResX*mResY*4;
|
||||
|
||||
if (mFBO)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
@@ -797,6 +814,9 @@ bool LLMultisampleBuffer::allocateDepth()
|
||||
llwarns << "Unable to allocate depth buffer for multisample render target." << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
sBytesAllocated += mResX*mResY*4;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ class LLRenderTarget
|
||||
public:
|
||||
//whether or not to use FBO implementation
|
||||
static bool sUseFBO;
|
||||
static U32 sBytesAllocated;
|
||||
|
||||
LLRenderTarget();
|
||||
virtual ~LLRenderTarget();
|
||||
@@ -157,7 +158,6 @@ protected:
|
||||
bool mUseDepth;
|
||||
bool mRenderDepth;
|
||||
LLTexUnit::eTextureType mUsage;
|
||||
U32 mSamples;
|
||||
LLMultisampleBuffer* mSampleBuffer;
|
||||
|
||||
static LLRenderTarget* sBoundTarget;
|
||||
@@ -166,6 +166,7 @@ protected:
|
||||
|
||||
class LLMultisampleBuffer : public LLRenderTarget
|
||||
{
|
||||
U32 mSamples;
|
||||
public:
|
||||
LLMultisampleBuffer();
|
||||
virtual ~LLMultisampleBuffer();
|
||||
|
||||
@@ -2,31 +2,25 @@
|
||||
* @file llshadermgr.cpp
|
||||
* @brief Shader manager implementation.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2005&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2005-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* 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.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* 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$
|
||||
*/
|
||||
|
||||
@@ -36,6 +30,8 @@
|
||||
|
||||
#include "llfile.h"
|
||||
#include "llrender.h"
|
||||
#include "llcontrol.h" //for LLCachedControl
|
||||
#include "lldir.h" //for gDirUtilp
|
||||
|
||||
#if LL_DARWIN
|
||||
#include "OpenGL/OpenGL.h"
|
||||
@@ -87,7 +83,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
// NOTE order of shader object attaching is VERY IMPORTANT!!!
|
||||
if (features->calculatesAtmospherics)
|
||||
{
|
||||
if (!shader->attachObject("windlight/atmosphericsVarsV.glsl"))
|
||||
if (features->hasWaterFog)
|
||||
{
|
||||
if (!shader->attachObject("windlight/atmosphericsVarsWaterV.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (!shader->attachObject("windlight/atmosphericsVarsV.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -107,9 +110,13 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!shader->attachObject("lighting/sumLightsSpecularV.glsl"))
|
||||
if (!features->isAlphaLighting)
|
||||
{
|
||||
return FALSE;
|
||||
if (!shader->attachObject("lighting/sumLightsSpecularV.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!shader->attachObject("lighting/lightSpecularV.glsl"))
|
||||
@@ -124,9 +131,12 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!shader->attachObject("lighting/sumLightsV.glsl"))
|
||||
if (!features->isAlphaLighting)
|
||||
{
|
||||
return FALSE;
|
||||
if (!shader->attachObject("lighting/sumLightsV.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shader->attachObject("lighting/lightV.glsl"))
|
||||
@@ -153,7 +163,6 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
}
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (features->hasObjectSkinning)
|
||||
{
|
||||
if (!shader->attachObject("avatar/objectSkinV.glsl"))
|
||||
@@ -161,7 +170,6 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
///////////////////////////////////////
|
||||
// Attach Fragment Shader Features Next
|
||||
@@ -169,7 +177,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
|
||||
if(features->calculatesAtmospherics)
|
||||
{
|
||||
if (!shader->attachObject("windlight/atmosphericsVarsF.glsl"))
|
||||
if (features->hasWaterFog)
|
||||
{
|
||||
if (!shader->attachObject("windlight/atmosphericsVarsWaterF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (!shader->attachObject("windlight/atmosphericsVarsF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -250,7 +265,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,7 +304,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -313,7 +328,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
|
||||
}
|
||||
}
|
||||
else if (features->hasWaterFog)
|
||||
@@ -345,7 +360,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +379,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +419,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,7 +443,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,10 +462,26 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (features->mIndexedTextureChannels <= 1)
|
||||
{
|
||||
if (!shader->attachObject("objects/nonindexedTextureV.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("objects/indexedTextureV.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -540,23 +571,69 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
}
|
||||
|
||||
//we can't have any lines longer than 1024 characters
|
||||
//or any shaders longer than 1024 lines... deal - DaveP
|
||||
GLcharARB buff[1024] = {0};
|
||||
GLcharARB* text[1024] = {0};
|
||||
//or any shaders longer than 4096 lines... deal - DaveP
|
||||
GLcharARB buff[1024];
|
||||
GLcharARB* text[4096];
|
||||
GLuint count = 0;
|
||||
|
||||
if (gGLManager.mGLVersion < 2.1f)
|
||||
F32 version = gGLManager.mGLVersion;
|
||||
|
||||
//hack to never use GLSL > 1.20 on OSX
|
||||
#if LL_DARWIN
|
||||
version = llmin(version, 2.9f);
|
||||
#endif
|
||||
|
||||
if (version < 2.1f)
|
||||
{
|
||||
text[count++] = strdup("#version 110\n");
|
||||
text[count++] = strdup("#define ATTRIBUTE attribute\n");
|
||||
text[count++] = strdup("#define VARYING varying\n");
|
||||
}
|
||||
else if (gGLManager.mGLVersion < 3.f)
|
||||
else if (version < 3.3f)
|
||||
{
|
||||
//set version to 1.20
|
||||
text[count++] = strdup("#version 120\n");
|
||||
text[count++] = strdup("#define FXAA_GLSL_120 1\n");
|
||||
text[count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n");
|
||||
text[count++] = strdup("#define ATTRIBUTE attribute\n");
|
||||
text[count++] = strdup("#define VARYING varying\n");
|
||||
}
|
||||
else
|
||||
{ //set version to 1.30
|
||||
text[count++] = strdup("#version 130\n");
|
||||
{
|
||||
if (version < 4.f)
|
||||
{
|
||||
//set version to 1.30
|
||||
text[count++] = strdup("#version 130\n");
|
||||
}
|
||||
else
|
||||
{ //set version to 400
|
||||
text[count++] = strdup("#version 400\n");
|
||||
}
|
||||
|
||||
text[count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n");
|
||||
text[count++] = strdup("#define FXAA_GLSL_130 1\n");
|
||||
|
||||
text[count++] = strdup("#define ATTRIBUTE in\n");
|
||||
|
||||
if (type == GL_VERTEX_SHADER_ARB)
|
||||
{ //"varying" state is "out" in a vertex program, "in" in a fragment program
|
||||
// ("varying" is deprecated after version 1.20)
|
||||
text[count++] = strdup("#define VARYING out\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
text[count++] = strdup("#define VARYING in\n");
|
||||
}
|
||||
|
||||
//backwards compatibility with legacy texture lookup syntax
|
||||
text[count++] = strdup("#define textureCube texture\n");
|
||||
text[count++] = strdup("#define texture2DLod textureLod\n");
|
||||
text[count++] = strdup("#define shadow2D(a,b) vec2(texture(a,b))\n"); //Shadow lookups only return a single float.
|
||||
|
||||
//Also deprecated:
|
||||
text[count++] = strdup("#define texture2D texture\n");
|
||||
text[count++] = strdup("#define texture2DRect texture\n");
|
||||
text[count++] = strdup("#define shadow2DRect(a,b) vec2(texture(a,b))\n");
|
||||
}
|
||||
|
||||
//copy preprocessor definitions into buffer
|
||||
@@ -606,7 +683,11 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
text[count++] = strdup(decl.c_str());
|
||||
}
|
||||
|
||||
text[count++] = strdup("varying float vary_texture_index;\n");
|
||||
if (texture_index_channels > 1)
|
||||
{
|
||||
text[count++] = strdup("VARYING float vary_texture_index;\n");
|
||||
}
|
||||
|
||||
text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
|
||||
text[count++] = strdup("{\n");
|
||||
|
||||
@@ -629,7 +710,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
}
|
||||
|
||||
text[count++] = strdup("\t}\n");
|
||||
text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
|
||||
text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
|
||||
text[count++] = strdup("}\n");
|
||||
}
|
||||
else
|
||||
@@ -652,12 +733,13 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
text[count++] = strdup(if_str.c_str());
|
||||
}
|
||||
|
||||
text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
|
||||
text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
|
||||
text[count++] = strdup("}\n");
|
||||
}
|
||||
}
|
||||
|
||||
//copy file into memory
|
||||
while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) )
|
||||
while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(text) )
|
||||
{
|
||||
text[count++] = (GLcharARB *)strdup((char *)buff);
|
||||
}
|
||||
@@ -672,35 +754,46 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
ret=0;
|
||||
}
|
||||
}
|
||||
|
||||
//load source
|
||||
glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
|
||||
|
||||
if (gDebugGL)
|
||||
if(ret)
|
||||
{
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
|
||||
|
||||
if (gDebugGL)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
ret=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//compile source
|
||||
glCompileShaderARB(ret);
|
||||
|
||||
if (gDebugGL)
|
||||
if(ret)
|
||||
{
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
glCompileShaderARB(ret);
|
||||
|
||||
if (gDebugGL)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
ret=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string error_str;
|
||||
|
||||
if (error == GL_NO_ERROR)
|
||||
{
|
||||
//check for errors
|
||||
@@ -714,23 +807,60 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
//an error occured, print log
|
||||
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
|
||||
dumpObjectLog(ret);
|
||||
error_str = get_object_log(ret);
|
||||
|
||||
#if LL_WINDOWS
|
||||
std::stringstream ostr;
|
||||
//dump shader source for debugging
|
||||
for (GLuint i = 0; i < count; i++)
|
||||
{
|
||||
ostr << i << ": " << text[i];
|
||||
|
||||
if (i % 128 == 0)
|
||||
{ //dump every 128 lines
|
||||
|
||||
LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
|
||||
ostr.str("");
|
||||
ostr.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
|
||||
#endif // LL_WINDOWS
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
if(ret)
|
||||
dumpObjectLog(ret,false);
|
||||
}
|
||||
else
|
||||
|
||||
static const LLCachedControl<bool> dump_raw_shaders("ShyotlDumpRawShaders",false);
|
||||
if(dump_raw_shaders || !ret)
|
||||
{
|
||||
ret = 0;
|
||||
std::stringstream ostr;
|
||||
for (GLuint i = 0; i < count; i++)
|
||||
{
|
||||
ostr << text[i];
|
||||
}
|
||||
|
||||
std::string delim = gDirUtilp->getDirDelimiter();
|
||||
std::string shader_name = filename.substr(filename.find_last_of("/")+1); //shader_name.glsl
|
||||
shader_name = shader_name.substr(0,shader_name.find_last_of(".")); //shader_name
|
||||
std::string maindir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"shader_dump"+delim);
|
||||
//mkdir is NOT recursive. Step through the folders one by one.
|
||||
LLFile::mkdir(maindir); //..Roaming/SecondLife/logs/shader_dump/
|
||||
LLFile::mkdir(maindir+="class" + llformat("%i",gpu_class) + delim); //..shader_dump/class1/
|
||||
LLFile::mkdir(maindir+=filename.substr(0,filename.find_last_of("/")+1)); //..shader_dump/class1/windlight/
|
||||
|
||||
LLAPRFile file(maindir + shader_name + (ret ? "" : llformat("_FAILED(%i)",error)) + ".glsl", LL_APR_W);
|
||||
file.write(ostr.str().c_str(),ostr.str().length());
|
||||
if(!error_str.empty())
|
||||
{
|
||||
LLAPRFile file2(maindir + shader_name + "_ERROR.txt", LL_APR_W);
|
||||
file2.write(error_str.c_str(),error_str.length());
|
||||
}
|
||||
}
|
||||
stop_glerror();
|
||||
|
||||
@@ -771,28 +901,42 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors)
|
||||
LL_WARNS("ShaderLoading") << "GLSL Linker Error:" << LL_ENDL;
|
||||
}
|
||||
|
||||
// NOTE: Removing LL_DARWIN block as it doesn't seem to actually give the correct answer,
|
||||
// but want it for reference once I move it.
|
||||
#if 0
|
||||
// Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software
|
||||
// per Apple's suggestion
|
||||
glBegin(gGL.mMode);
|
||||
glEnd();
|
||||
#if LL_DARWIN
|
||||
|
||||
// Query whether the shader can or cannot run in hardware
|
||||
// http://developer.apple.com/qa/qa2007/qa1502.html
|
||||
long vertexGPUProcessing;
|
||||
CGLContextObj ctx = CGLGetCurrentContext();
|
||||
CGLGetParameter (ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing);
|
||||
long fragmentGPUProcessing;
|
||||
CGLGetParameter (ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
|
||||
if (!fragmentGPUProcessing || !vertexGPUProcessing)
|
||||
// For some reason this absolutely kills the frame rate when VBO's are enabled
|
||||
if (0)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL;
|
||||
success = GL_FALSE;
|
||||
suppress_errors = FALSE;
|
||||
// Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software
|
||||
// per Apple's suggestion
|
||||
LLGLSLShader::sNoFixedFunction = false;
|
||||
|
||||
glUseProgramObjectARB(obj);
|
||||
|
||||
gGL.begin(LLRender::TRIANGLES);
|
||||
gGL.vertex3f(0.0f, 0.0f, 0.0f);
|
||||
gGL.vertex3f(0.0f, 0.0f, 0.0f);
|
||||
gGL.vertex3f(0.0f, 0.0f, 0.0f);
|
||||
gGL.end();
|
||||
gGL.flush();
|
||||
|
||||
glUseProgramObjectARB(0);
|
||||
|
||||
LLGLSLShader::sNoFixedFunction = true;
|
||||
|
||||
// Query whether the shader can or cannot run in hardware
|
||||
// http://developer.apple.com/qa/qa2007/qa1502.html
|
||||
GLint vertexGPUProcessing, fragmentGPUProcessing;
|
||||
CGLContextObj ctx = CGLGetCurrentContext();
|
||||
CGLGetParameter(ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing);
|
||||
CGLGetParameter(ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
|
||||
if (!fragmentGPUProcessing || !vertexGPUProcessing)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL;
|
||||
success = GL_FALSE;
|
||||
suppress_errors = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
std::string log = get_object_log(obj);
|
||||
LLStringUtil::toLower(log);
|
||||
@@ -830,3 +974,181 @@ BOOL LLShaderMgr::validateProgramObject(GLhandleARB obj)
|
||||
return success;
|
||||
}
|
||||
|
||||
//virtual
|
||||
void LLShaderMgr::initAttribsAndUniforms()
|
||||
{
|
||||
//MUST match order of enum in LLVertexBuffer.h
|
||||
mReservedAttribs.push_back("position");
|
||||
mReservedAttribs.push_back("normal");
|
||||
mReservedAttribs.push_back("texcoord0");
|
||||
mReservedAttribs.push_back("texcoord1");
|
||||
mReservedAttribs.push_back("texcoord2");
|
||||
mReservedAttribs.push_back("texcoord3");
|
||||
mReservedAttribs.push_back("diffuse_color");
|
||||
mReservedAttribs.push_back("emissive");
|
||||
mReservedAttribs.push_back("binormal");
|
||||
mReservedAttribs.push_back("weight");
|
||||
mReservedAttribs.push_back("weight4");
|
||||
mReservedAttribs.push_back("clothing");
|
||||
mReservedAttribs.push_back("texture_index");
|
||||
|
||||
//matrix state
|
||||
mReservedUniforms.push_back("modelview_matrix");
|
||||
mReservedUniforms.push_back("projection_matrix");
|
||||
mReservedUniforms.push_back("inv_proj");
|
||||
mReservedUniforms.push_back("modelview_projection_matrix");
|
||||
mReservedUniforms.push_back("normal_matrix");
|
||||
mReservedUniforms.push_back("texture_matrix0");
|
||||
mReservedUniforms.push_back("texture_matrix1");
|
||||
mReservedUniforms.push_back("texture_matrix2");
|
||||
mReservedUniforms.push_back("texture_matrix3");
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::TEXTURE_MATRIX3+1);
|
||||
|
||||
mReservedUniforms.push_back("viewport");
|
||||
|
||||
mReservedUniforms.push_back("light_position");
|
||||
mReservedUniforms.push_back("light_direction");
|
||||
mReservedUniforms.push_back("light_attenuation");
|
||||
mReservedUniforms.push_back("light_diffuse");
|
||||
mReservedUniforms.push_back("light_ambient");
|
||||
mReservedUniforms.push_back("light_count");
|
||||
mReservedUniforms.push_back("light");
|
||||
mReservedUniforms.push_back("light_col");
|
||||
mReservedUniforms.push_back("far_z");
|
||||
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::MULTI_LIGHT_FAR_Z+1);
|
||||
|
||||
|
||||
mReservedUniforms.push_back("proj_mat");
|
||||
mReservedUniforms.push_back("proj_near");
|
||||
mReservedUniforms.push_back("proj_p");
|
||||
mReservedUniforms.push_back("proj_n");
|
||||
mReservedUniforms.push_back("proj_origin");
|
||||
mReservedUniforms.push_back("proj_range");
|
||||
mReservedUniforms.push_back("proj_ambiance");
|
||||
mReservedUniforms.push_back("proj_shadow_idx");
|
||||
mReservedUniforms.push_back("shadow_fade");
|
||||
mReservedUniforms.push_back("proj_focus");
|
||||
mReservedUniforms.push_back("proj_lod");
|
||||
mReservedUniforms.push_back("proj_ambient_lod");
|
||||
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::PROJECTOR_AMBIENT_LOD+1);
|
||||
|
||||
mReservedUniforms.push_back("color");
|
||||
|
||||
mReservedUniforms.push_back("diffuseMap");
|
||||
mReservedUniforms.push_back("specularMap");
|
||||
mReservedUniforms.push_back("bumpMap");
|
||||
mReservedUniforms.push_back("environmentMap");
|
||||
mReservedUniforms.push_back("cloude_noise_texture");
|
||||
mReservedUniforms.push_back("fullbright");
|
||||
mReservedUniforms.push_back("lightnorm");
|
||||
mReservedUniforms.push_back("sunlight_color_copy");
|
||||
mReservedUniforms.push_back("ambient");
|
||||
mReservedUniforms.push_back("blue_horizon");
|
||||
mReservedUniforms.push_back("blue_density");
|
||||
mReservedUniforms.push_back("haze_horizon");
|
||||
mReservedUniforms.push_back("haze_density");
|
||||
mReservedUniforms.push_back("cloud_shadow");
|
||||
mReservedUniforms.push_back("density_multiplier");
|
||||
mReservedUniforms.push_back("distance_multiplier");
|
||||
mReservedUniforms.push_back("max_y");
|
||||
mReservedUniforms.push_back("glow");
|
||||
mReservedUniforms.push_back("cloud_color");
|
||||
mReservedUniforms.push_back("cloud_pos_density1");
|
||||
mReservedUniforms.push_back("cloud_pos_density2");
|
||||
mReservedUniforms.push_back("cloud_scale");
|
||||
mReservedUniforms.push_back("gamma");
|
||||
mReservedUniforms.push_back("scene_light_strength");
|
||||
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::SCENE_LIGHT_STRENGTH+1);
|
||||
|
||||
mReservedUniforms.push_back("center");
|
||||
mReservedUniforms.push_back("size");
|
||||
mReservedUniforms.push_back("falloff");
|
||||
|
||||
|
||||
mReservedUniforms.push_back("minLuminance");
|
||||
mReservedUniforms.push_back("maxExtractAlpha");
|
||||
mReservedUniforms.push_back("lumWeights");
|
||||
mReservedUniforms.push_back("warmthWeights");
|
||||
mReservedUniforms.push_back("warmthAmount");
|
||||
mReservedUniforms.push_back("glowStrength");
|
||||
mReservedUniforms.push_back("glowDelta");
|
||||
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_DELTA+1);
|
||||
|
||||
|
||||
mReservedUniforms.push_back("minimum_alpha");
|
||||
|
||||
mReservedUniforms.push_back("shadow_matrix");
|
||||
mReservedUniforms.push_back("env_mat");
|
||||
mReservedUniforms.push_back("shadow_clip");
|
||||
mReservedUniforms.push_back("sun_wash");
|
||||
mReservedUniforms.push_back("shadow_noise");
|
||||
mReservedUniforms.push_back("blur_size");
|
||||
mReservedUniforms.push_back("ssao_radius");
|
||||
mReservedUniforms.push_back("ssao_max_radius");
|
||||
mReservedUniforms.push_back("ssao_factor");
|
||||
mReservedUniforms.push_back("ssao_factor_inv");
|
||||
mReservedUniforms.push_back("ssao_effect_mat");
|
||||
mReservedUniforms.push_back("screen_res");
|
||||
mReservedUniforms.push_back("near_clip");
|
||||
mReservedUniforms.push_back("shadow_offset");
|
||||
mReservedUniforms.push_back("shadow_bias");
|
||||
mReservedUniforms.push_back("spot_shadow_bias");
|
||||
mReservedUniforms.push_back("spot_shadow_offset");
|
||||
mReservedUniforms.push_back("sun_dir");
|
||||
mReservedUniforms.push_back("shadow_res");
|
||||
mReservedUniforms.push_back("proj_shadow_res");
|
||||
mReservedUniforms.push_back("depth_cutoff");
|
||||
mReservedUniforms.push_back("norm_cutoff");
|
||||
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_NORM_CUTOFF+1);
|
||||
|
||||
mReservedUniforms.push_back("tc_scale");
|
||||
mReservedUniforms.push_back("rcp_screen_res");
|
||||
mReservedUniforms.push_back("rcp_frame_opt");
|
||||
mReservedUniforms.push_back("rcp_frame_opt2");
|
||||
|
||||
mReservedUniforms.push_back("focal_distance");
|
||||
mReservedUniforms.push_back("blur_constant");
|
||||
mReservedUniforms.push_back("tan_pixel_angle");
|
||||
mReservedUniforms.push_back("magnification");
|
||||
mReservedUniforms.push_back("max_cof");
|
||||
mReservedUniforms.push_back("res_scale");
|
||||
|
||||
mReservedUniforms.push_back("depthMap");
|
||||
mReservedUniforms.push_back("shadowMap0");
|
||||
mReservedUniforms.push_back("shadowMap1");
|
||||
mReservedUniforms.push_back("shadowMap2");
|
||||
mReservedUniforms.push_back("shadowMap3");
|
||||
mReservedUniforms.push_back("shadowMap4");
|
||||
mReservedUniforms.push_back("shadowMap5");
|
||||
|
||||
llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1);
|
||||
|
||||
mReservedUniforms.push_back("normalMap");
|
||||
mReservedUniforms.push_back("positionMap");
|
||||
mReservedUniforms.push_back("diffuseRect");
|
||||
mReservedUniforms.push_back("specularRect");
|
||||
mReservedUniforms.push_back("noiseMap");
|
||||
mReservedUniforms.push_back("lightFunc");
|
||||
mReservedUniforms.push_back("lightMap");
|
||||
mReservedUniforms.push_back("bloomMap");
|
||||
mReservedUniforms.push_back("projectionMap");
|
||||
|
||||
llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
|
||||
|
||||
std::set<std::string> dupe_check;
|
||||
|
||||
for (U32 i = 0; i < mReservedUniforms.size(); ++i)
|
||||
{
|
||||
if (dupe_check.find(mReservedUniforms[i]) != dupe_check.end())
|
||||
{
|
||||
llerrs << "Duplicate reserved uniform name found: " << mReservedUniforms[i] << llendl;
|
||||
}
|
||||
dupe_check.insert(mReservedUniforms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,137 @@ public:
|
||||
LLShaderMgr();
|
||||
virtual ~LLShaderMgr();
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MODELVIEW_MATRIX = 0,
|
||||
PROJECTION_MATRIX,
|
||||
INVERSE_PROJECTION_MATRIX,
|
||||
MODELVIEW_PROJECTION_MATRIX,
|
||||
NORMAL_MATRIX,
|
||||
TEXTURE_MATRIX0,
|
||||
TEXTURE_MATRIX1,
|
||||
TEXTURE_MATRIX2,
|
||||
TEXTURE_MATRIX3,
|
||||
VIEWPORT,
|
||||
LIGHT_POSITION,
|
||||
LIGHT_DIRECTION,
|
||||
LIGHT_ATTENUATION,
|
||||
LIGHT_DIFFUSE,
|
||||
LIGHT_AMBIENT,
|
||||
MULTI_LIGHT_COUNT,
|
||||
MULTI_LIGHT,
|
||||
MULTI_LIGHT_COL,
|
||||
MULTI_LIGHT_FAR_Z,
|
||||
PROJECTOR_MATRIX,
|
||||
PROJECTOR_NEAR,
|
||||
PROJECTOR_P,
|
||||
PROJECTOR_N,
|
||||
PROJECTOR_ORIGIN,
|
||||
PROJECTOR_RANGE,
|
||||
PROJECTOR_AMBIANCE,
|
||||
PROJECTOR_SHADOW_INDEX,
|
||||
PROJECTOR_SHADOW_FADE,
|
||||
PROJECTOR_FOCUS,
|
||||
PROJECTOR_LOD,
|
||||
PROJECTOR_AMBIENT_LOD,
|
||||
DIFFUSE_COLOR,
|
||||
DIFFUSE_MAP,
|
||||
SPECULAR_MAP,
|
||||
BUMP_MAP,
|
||||
ENVIRONMENT_MAP,
|
||||
CLOUD_NOISE_MAP,
|
||||
FULLBRIGHT,
|
||||
LIGHTNORM,
|
||||
SUNLIGHT_COLOR,
|
||||
AMBIENT,
|
||||
BLUE_HORIZON,
|
||||
BLUE_DENSITY,
|
||||
HAZE_HORIZON,
|
||||
HAZE_DENSITY,
|
||||
CLOUD_SHADOW,
|
||||
DENSITY_MULTIPLIER,
|
||||
DISTANCE_MULTIPLIER,
|
||||
MAX_Y,
|
||||
GLOW,
|
||||
CLOUD_COLOR,
|
||||
CLOUD_POS_DENSITY1,
|
||||
CLOUD_POS_DENSITY2,
|
||||
CLOUD_SCALE,
|
||||
GAMMA,
|
||||
SCENE_LIGHT_STRENGTH,
|
||||
LIGHT_CENTER,
|
||||
LIGHT_SIZE,
|
||||
LIGHT_FALLOFF,
|
||||
|
||||
GLOW_MIN_LUMINANCE,
|
||||
GLOW_MAX_EXTRACT_ALPHA,
|
||||
GLOW_LUM_WEIGHTS,
|
||||
GLOW_WARMTH_WEIGHTS,
|
||||
GLOW_WARMTH_AMOUNT,
|
||||
GLOW_STRENGTH,
|
||||
GLOW_DELTA,
|
||||
|
||||
MINIMUM_ALPHA,
|
||||
|
||||
DEFERRED_SHADOW_MATRIX,
|
||||
DEFERRED_ENV_MAT,
|
||||
DEFERRED_SHADOW_CLIP,
|
||||
DEFERRED_SUN_WASH,
|
||||
DEFERRED_SHADOW_NOISE,
|
||||
DEFERRED_BLUR_SIZE,
|
||||
DEFERRED_SSAO_RADIUS,
|
||||
DEFERRED_SSAO_MAX_RADIUS,
|
||||
DEFERRED_SSAO_FACTOR,
|
||||
DEFERRED_SSAO_FACTOR_INV,
|
||||
DEFERRED_SSAO_EFFECT_MAT,
|
||||
DEFERRED_SCREEN_RES,
|
||||
DEFERRED_NEAR_CLIP,
|
||||
DEFERRED_SHADOW_OFFSET,
|
||||
DEFERRED_SHADOW_BIAS,
|
||||
DEFERRED_SPOT_SHADOW_BIAS,
|
||||
DEFERRED_SPOT_SHADOW_OFFSET,
|
||||
DEFERRED_SUN_DIR,
|
||||
DEFERRED_SHADOW_RES,
|
||||
DEFERRED_PROJ_SHADOW_RES,
|
||||
DEFERRED_DEPTH_CUTOFF,
|
||||
DEFERRED_NORM_CUTOFF,
|
||||
|
||||
FXAA_TC_SCALE,
|
||||
FXAA_RCP_SCREEN_RES,
|
||||
FXAA_RCP_FRAME_OPT,
|
||||
FXAA_RCP_FRAME_OPT2,
|
||||
|
||||
DOF_FOCAL_DISTANCE,
|
||||
DOF_BLUR_CONSTANT,
|
||||
DOF_TAN_PIXEL_ANGLE,
|
||||
DOF_MAGNIFICATION,
|
||||
DOF_MAX_COF,
|
||||
DOF_RES_SCALE,
|
||||
|
||||
DEFERRED_DEPTH,
|
||||
DEFERRED_SHADOW0,
|
||||
DEFERRED_SHADOW1,
|
||||
DEFERRED_SHADOW2,
|
||||
DEFERRED_SHADOW3,
|
||||
DEFERRED_SHADOW4,
|
||||
DEFERRED_SHADOW5,
|
||||
DEFERRED_NORMAL,
|
||||
DEFERRED_POSITION,
|
||||
DEFERRED_DIFFUSE,
|
||||
DEFERRED_SPECULAR,
|
||||
DEFERRED_NOISE,
|
||||
DEFERRED_LIGHTFUNC,
|
||||
DEFERRED_LIGHT,
|
||||
DEFERRED_BLOOM,
|
||||
DEFERRED_PROJECTION,
|
||||
END_RESERVED_UNIFORMS
|
||||
} eGLSLReservedUniforms;
|
||||
|
||||
// singleton pattern implementation
|
||||
static LLShaderMgr * instance();
|
||||
|
||||
virtual void initAttribsAndUniforms(void);
|
||||
|
||||
BOOL attachShaderFeatures(LLGLSLShader * shader);
|
||||
void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE);
|
||||
BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,8 @@
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#define LL_MAX_VERTEX_ATTRIB_LOCATION 64
|
||||
|
||||
//============================================================================
|
||||
// NOTES
|
||||
// Threading:
|
||||
@@ -56,12 +58,32 @@
|
||||
|
||||
//============================================================================
|
||||
// gl name pools for dynamic and streaming buffers
|
||||
|
||||
class LLVBOPool : public LLGLNamePool
|
||||
class LLVBOPool
|
||||
{
|
||||
protected:
|
||||
virtual GLuint allocateName();
|
||||
virtual void releaseName(GLuint name);
|
||||
public:
|
||||
static U32 sBytesPooled;
|
||||
|
||||
U32 mUsage;
|
||||
U32 mType;
|
||||
|
||||
//size MUST be a power of 2
|
||||
U8* allocate(U32& name, U32 size);
|
||||
|
||||
//size MUST be the size provided to allocate that returned the given name
|
||||
void release(U32 name, U8* buffer, U32 size);
|
||||
|
||||
//destroy all records in mFreeList
|
||||
void cleanup();
|
||||
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
U32 mGLName;
|
||||
U8* mClientData;
|
||||
};
|
||||
|
||||
typedef std::list<Record> record_list_t;
|
||||
std::vector<record_list_t> mFreeList;
|
||||
};
|
||||
|
||||
class LLGLFence
|
||||
@@ -72,11 +94,21 @@ public:
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
// base class
|
||||
|
||||
// base class
|
||||
class LLPrivateMemoryPool ;
|
||||
class LLVertexBuffer : public LLRefCount
|
||||
{
|
||||
public:
|
||||
class MappedRegion
|
||||
{
|
||||
public:
|
||||
S32 mType;
|
||||
S32 mIndex;
|
||||
S32 mCount;
|
||||
|
||||
MappedRegion(S32 type, S32 index, S32 count);
|
||||
};
|
||||
|
||||
LLVertexBuffer(const LLVertexBuffer& rhs)
|
||||
{
|
||||
*this = rhs;
|
||||
@@ -93,20 +125,17 @@ public:
|
||||
static LLVBOPool sStreamIBOPool;
|
||||
static LLVBOPool sDynamicIBOPool;
|
||||
|
||||
static S32 sWeight4Loc;
|
||||
|
||||
static BOOL sUseStreamDraw;
|
||||
static U32 sForceStrideMode;
|
||||
static BOOL sOmitBlank;
|
||||
static BOOL sUseVAO;
|
||||
static BOOL sPreferStreamDraw;
|
||||
|
||||
static void initClass(bool use_vbo, bool no_vbo_mapping);
|
||||
static void cleanupClass();
|
||||
static void setupClientArrays(U32 data_mask);
|
||||
static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
|
||||
static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
|
||||
|
||||
static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
|
||||
static void unbind(); //unbind any bound vertex buffer
|
||||
static void unbind(); //unbind any bound vertex buffer
|
||||
|
||||
//get the size of a vertex with the given typemask
|
||||
static S32 calcVertexSize(const U32& typemask);
|
||||
@@ -114,28 +143,32 @@ public:
|
||||
//get the size of a buffer with the given typemask and vertex count
|
||||
//fill offsets with the offset of each vertex component array into the buffer
|
||||
// indexed by the following enum
|
||||
//If strided, num_vertices will be ignored.
|
||||
S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices);
|
||||
static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices);
|
||||
|
||||
|
||||
//WARNING -- when updating these enums you MUST
|
||||
// 1 - update LLVertexBuffer::sTypeSize
|
||||
// 2 - add a strider accessor
|
||||
// 3 - modify LLVertexBuffer::setupVertexBuffer
|
||||
// 4 - modify LLVertexBuffer::setupClientArray
|
||||
// 5 - modify LLViewerShaderMgr::mReservedAttribs
|
||||
// 6 - update LLVertexBuffer::setupVertexArray
|
||||
enum {
|
||||
TYPE_VERTEX,
|
||||
TYPE_VERTEX = 0,
|
||||
TYPE_NORMAL,
|
||||
TYPE_TEXCOORD0,
|
||||
TYPE_TEXCOORD1,
|
||||
TYPE_TEXCOORD2,
|
||||
TYPE_TEXCOORD3,
|
||||
TYPE_COLOR,
|
||||
// These use VertexAttribPointer and should possibly be made generic
|
||||
TYPE_EMISSIVE,
|
||||
TYPE_BINORMAL,
|
||||
TYPE_WEIGHT,
|
||||
TYPE_WEIGHT4,
|
||||
TYPE_CLOTHWEIGHT,
|
||||
TYPE_MAX,
|
||||
TYPE_INDEX,
|
||||
|
||||
//no actual additional data, but indicates position.w is texture index
|
||||
TYPE_TEXTURE_INDEX,
|
||||
TYPE_MAX,
|
||||
TYPE_INDEX,
|
||||
};
|
||||
enum {
|
||||
MAP_VERTEX = (1<<TYPE_VERTEX),
|
||||
@@ -145,6 +178,7 @@ public:
|
||||
MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2),
|
||||
MAP_TEXCOORD3 = (1<<TYPE_TEXCOORD3),
|
||||
MAP_COLOR = (1<<TYPE_COLOR),
|
||||
MAP_EMISSIVE = (1<<TYPE_EMISSIVE),
|
||||
// These use VertexAttribPointer and should possibly be made generic
|
||||
MAP_BINORMAL = (1<<TYPE_BINORMAL),
|
||||
MAP_WEIGHT = (1<<TYPE_WEIGHT),
|
||||
@@ -158,37 +192,39 @@ protected:
|
||||
|
||||
virtual ~LLVertexBuffer(); // use unref()
|
||||
|
||||
virtual void setupVertexBuffer(U32 data_mask) const; // pure virtual, called from mapBuffer()
|
||||
virtual void setupVertexBuffer(U32 data_mask); // pure virtual, called from mapBuffer()
|
||||
void setupVertexArray();
|
||||
|
||||
void genBuffer();
|
||||
void genIndices();
|
||||
void genBuffer(U32 size);
|
||||
void genIndices(U32 size);
|
||||
bool bindGLBuffer(bool force_bind = false);
|
||||
bool bindGLIndices(bool force_bind = false);
|
||||
bool bindGLArray();
|
||||
void releaseBuffer();
|
||||
void releaseIndices();
|
||||
void createGLBuffer();
|
||||
void createGLIndices();
|
||||
void createGLBuffer(U32 size);
|
||||
void createGLIndices(U32 size);
|
||||
void destroyGLBuffer();
|
||||
void destroyGLIndices();
|
||||
void updateNumVerts(S32 nverts);
|
||||
void updateNumIndices(S32 nindices);
|
||||
virtual BOOL useVBOs() const;
|
||||
void unmapBuffer(S32 type);
|
||||
void freeClientBuffer() ;
|
||||
void allocateClientVertexBuffer() ;
|
||||
void allocateClientIndexBuffer() ;
|
||||
void unmapBuffer();
|
||||
|
||||
public:
|
||||
LLVertexBuffer(U32 typemask, S32 usage, bool strided=true);
|
||||
LLVertexBuffer(U32 typemask, S32 usage);
|
||||
|
||||
// map for data access
|
||||
volatile U8* mapVertexBuffer(S32 type, S32 index);
|
||||
volatile U8* mapIndexBuffer(S32 index);
|
||||
/*volatile */U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
|
||||
/*volatile */U8* mapIndexBuffer(S32 index, S32 count, bool map_range);
|
||||
|
||||
// set for rendering
|
||||
virtual void setBuffer(U32 data_mask, S32 type = -1); // calls setupVertexBuffer() if data_mask is not 0
|
||||
virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0
|
||||
void flush(); //flush pending data to GL memory
|
||||
// allocate buffer
|
||||
void allocateBuffer(S32 nverts, S32 nindices, bool create);
|
||||
virtual void resizeBuffer(S32 newnverts, S32 newnindices);
|
||||
|
||||
|
||||
// Only call each getVertexPointer, etc, once before calling unmapBuffer()
|
||||
// call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer()
|
||||
// example:
|
||||
@@ -196,33 +232,33 @@ public:
|
||||
// vb->getNormalStrider(norms);
|
||||
// setVertsNorms(verts, norms);
|
||||
// vb->unmapBuffer();
|
||||
bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0);
|
||||
bool getIndexStrider(LLStrider<U16>& strider, S32 index=0);
|
||||
bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0);
|
||||
bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0);
|
||||
bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0);
|
||||
bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0);
|
||||
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0);
|
||||
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0);
|
||||
bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0);
|
||||
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0);
|
||||
bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getVertexStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getIndexStrider(LLStrider<U16>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
||||
|
||||
|
||||
BOOL isEmpty() const { return mEmpty; }
|
||||
BOOL isLocked() const { return mVertexLocked || mIndexLocked; }
|
||||
S32 getNumVerts() const { return mNumVerts; }
|
||||
S32 getNumIndices() const { return mNumIndices; }
|
||||
S32 getRequestedVerts() const { return mRequestedNumVerts; }
|
||||
S32 getRequestedIndices() const { return mRequestedNumIndices; }
|
||||
|
||||
volatile U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
|
||||
volatile U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
|
||||
S32 getStride(S32 type) const { return mIsStrided ? mStride : sTypeSize[type]; }
|
||||
|
||||
/*volatile */U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
|
||||
/*volatile */U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
|
||||
U32 getTypeMask() const { return mTypeMask; }
|
||||
bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); }
|
||||
S32 getSize() const;
|
||||
S32 getIndicesSize() const { return mNumIndices * sizeof(U16); }
|
||||
volatile U8* getMappedData() const { return mMappedData; }
|
||||
volatile U8* getMappedIndices() const { return mMappedIndexData; }
|
||||
S32 getIndicesSize() const { return mIndicesSize; }
|
||||
/*volatile */U8* getMappedData() const { return mMappedData; }
|
||||
/*volatile */U8* getMappedIndices() const { return mMappedIndexData; }
|
||||
S32 getOffset(S32 type) const { return mOffsets[type]; }
|
||||
S32 getUsage() const { return mUsage; }
|
||||
|
||||
@@ -238,41 +274,42 @@ public:
|
||||
protected:
|
||||
S32 mNumVerts; // Number of vertices allocated
|
||||
S32 mNumIndices; // Number of indices allocated
|
||||
S32 mRequestedNumVerts; // Number of vertices requested
|
||||
S32 mRequestedNumIndices; // Number of indices requested
|
||||
|
||||
|
||||
ptrdiff_t mAlignedOffset;
|
||||
ptrdiff_t mAlignedIndexOffset;
|
||||
bool mIsStrided;
|
||||
S32 mStride; // Vertex size.
|
||||
S32 mSize; // Full array size
|
||||
S32 mSize;
|
||||
S32 mIndicesSize;
|
||||
U32 mTypeMask;
|
||||
S32 mUsage; // GL usage
|
||||
U32 mGLBuffer; // GL VBO handle
|
||||
U32 mGLIndices; // GL IBO handle
|
||||
volatile U8* mMappedData; // pointer to currently mapped data (NULL if unmapped)
|
||||
volatile U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped)
|
||||
U32 mGLArray; // GL VAO handle
|
||||
|
||||
/*volatile */U8* mMappedData; // pointer to currently mapped data (NULL if unmapped)
|
||||
/*volatile */U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped)
|
||||
BOOL mVertexLocked; // if TRUE, vertex buffer is being or has been written to in client memory
|
||||
BOOL mIndexLocked; // if TRUE, index buffer is being or has been written to in client memory
|
||||
BOOL mFinal; // if TRUE, buffer can not be mapped again
|
||||
BOOL mFilthy; // if TRUE, entire buffer must be copied (used to prevent redundant dirty flags)
|
||||
BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded.
|
||||
BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not
|
||||
BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded)
|
||||
S32 mOffsets[TYPE_MAX];
|
||||
|
||||
std::vector<MappedRegion> mMappedVertexRegions;
|
||||
std::vector<MappedRegion> mMappedIndexRegions;
|
||||
|
||||
mutable LLGLFence* mFence;
|
||||
|
||||
void placeFence() const;
|
||||
void waitFence() const;
|
||||
|
||||
|
||||
private:
|
||||
static LLPrivateMemoryPool* sPrivatePoolp ;
|
||||
|
||||
public:
|
||||
static S32 sCount;
|
||||
static S32 sGLCount;
|
||||
static S32 sMappedCount;
|
||||
static BOOL sMapped;
|
||||
static std::vector<U32> sDeleteList;
|
||||
typedef std::list<LLVertexBuffer*> buffer_list_t;
|
||||
|
||||
static BOOL sDisableVBOMapping; //disable glMapBufferARB
|
||||
@@ -280,6 +317,7 @@ public:
|
||||
static S32 sTypeSize[TYPE_MAX];
|
||||
static U32 sGLMode[LLRender::NUM_MODES];
|
||||
static U32 sGLRenderBuffer;
|
||||
static U32 sGLRenderArray;
|
||||
static U32 sGLRenderIndices;
|
||||
static BOOL sVBOActive;
|
||||
static BOOL sIBOActive;
|
||||
|
||||
@@ -41,6 +41,7 @@ set(llui_SOURCE_FILES
|
||||
lllineeditor.cpp
|
||||
llmenugl.cpp
|
||||
llmodaldialog.cpp
|
||||
llmultifloater.cpp
|
||||
llmultislider.cpp
|
||||
llmultisliderctrl.cpp
|
||||
llnotifications.cpp
|
||||
@@ -68,6 +69,7 @@ set(llui_SOURCE_FILES
|
||||
llui.cpp
|
||||
lluictrl.cpp
|
||||
lluictrlfactory.cpp
|
||||
lluiimage.cpp
|
||||
lluistring.cpp
|
||||
lluitrans.cpp
|
||||
llundo.cpp
|
||||
@@ -92,6 +94,7 @@ set(llui_HEADER_FILES
|
||||
llfloater.h
|
||||
llfocusmgr.h
|
||||
llfunctorregistry.h
|
||||
llhandle.h
|
||||
llhtmlhelp.h
|
||||
lliconctrl.h
|
||||
llkeywords.h
|
||||
@@ -99,6 +102,7 @@ set(llui_HEADER_FILES
|
||||
llmemberlistener.h
|
||||
llmenugl.h
|
||||
llmodaldialog.h
|
||||
llmultifloater.h
|
||||
llmultisliderctrl.h
|
||||
llmultislider.h
|
||||
llnotificationptr.h
|
||||
@@ -129,6 +133,7 @@ set(llui_HEADER_FILES
|
||||
lluictrl.h
|
||||
lluifwd.h
|
||||
llui.h
|
||||
lluiimage.h
|
||||
lluistring.h
|
||||
lluitrans.h
|
||||
lluixmltags.h
|
||||
|
||||
@@ -423,7 +423,7 @@ void LLButton::draw()
|
||||
// Unselected image assignments
|
||||
S32 local_mouse_x;
|
||||
S32 local_mouse_y;
|
||||
LLUI::getCursorPositionLocal(this, &local_mouse_x, &local_mouse_y);
|
||||
LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
|
||||
|
||||
BOOL pressed = pressed_by_keyboard
|
||||
|| (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y))
|
||||
@@ -688,7 +688,7 @@ void LLButton::draw()
|
||||
x = text_right;
|
||||
break;
|
||||
case LLFontGL::HCENTER:
|
||||
x = getRect().getWidth() / 2;
|
||||
x = text_left + (text_width / 2);
|
||||
break;
|
||||
case LLFontGL::LEFT:
|
||||
default:
|
||||
@@ -704,10 +704,13 @@ void LLButton::draw()
|
||||
x++;
|
||||
}
|
||||
|
||||
mGLFont->render(label, 0, (F32)x, (F32)(LLBUTTON_V_PAD + y_offset),
|
||||
mGLFont->render(label, 0,
|
||||
(F32)x,
|
||||
(F32)(LLBUTTON_V_PAD + y_offset),
|
||||
label_color,
|
||||
mHAlign, LLFontGL::BOTTOM,
|
||||
mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NORMAL,
|
||||
LLFontGL::NORMAL,
|
||||
mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,
|
||||
U32_MAX, text_width,
|
||||
NULL, FALSE, FALSE);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include "v4color.h"
|
||||
#include "llframetimer.h"
|
||||
#include "llfontgl.h"
|
||||
#include "llimage.h"
|
||||
#include "lluiimage.h"
|
||||
#include "lluistring.h"
|
||||
|
||||
//
|
||||
|
||||
@@ -117,7 +117,7 @@ void LLDragHandleTop::setTitle(const std::string& title)
|
||||
const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF );
|
||||
LLTextBox* titlebox = new LLTextBox( std::string("Drag Handle Title"), getRect(), trimmed_title, font );
|
||||
titlebox->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT);
|
||||
titlebox->setFontStyle(LLFontGL::DROP_SHADOW_SOFT);
|
||||
titlebox->setFontShadow(LLFontGL::DROP_SHADOW_SOFT);
|
||||
|
||||
setTitleBox(titlebox);
|
||||
reshapeTitleBox();
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llmultifloater.h"
|
||||
|
||||
#include "llfocusmgr.h"
|
||||
|
||||
@@ -2480,519 +2480,7 @@ void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLMultiFloater
|
||||
//
|
||||
|
||||
LLMultiFloater::LLMultiFloater() :
|
||||
mTabContainer(NULL),
|
||||
mTabPos(LLTabContainer::TOP),
|
||||
mAutoResize(TRUE),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LLMultiFloater::LLMultiFloater(LLTabContainer::TabPosition tab_pos) :
|
||||
mTabContainer(NULL),
|
||||
mTabPos(tab_pos),
|
||||
mAutoResize(TRUE),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LLMultiFloater::LLMultiFloater(const std::string &name) :
|
||||
LLFloater(name),
|
||||
mTabContainer(NULL),
|
||||
mTabPos(LLTabContainer::TOP),
|
||||
mAutoResize(FALSE),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
}
|
||||
|
||||
LLMultiFloater::LLMultiFloater(
|
||||
const std::string& name,
|
||||
const LLRect& rect,
|
||||
LLTabContainer::TabPosition tab_pos,
|
||||
BOOL auto_resize) :
|
||||
LLFloater(name, rect, name),
|
||||
mTabContainer(NULL),
|
||||
mTabPos(LLTabContainer::TOP),
|
||||
mAutoResize(auto_resize),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
mTabContainer = new LLTabContainer(std::string("Preview Tabs"),
|
||||
LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0),
|
||||
mTabPos,
|
||||
FALSE,
|
||||
FALSE);
|
||||
mTabContainer->setFollowsAll();
|
||||
if (isResizable())
|
||||
{
|
||||
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
|
||||
addChild(mTabContainer);
|
||||
}
|
||||
|
||||
LLMultiFloater::LLMultiFloater(
|
||||
const std::string& name,
|
||||
const std::string& rect_control,
|
||||
LLTabContainer::TabPosition tab_pos,
|
||||
BOOL auto_resize) :
|
||||
LLFloater(name, rect_control, name),
|
||||
mTabContainer(NULL),
|
||||
mTabPos(tab_pos),
|
||||
mAutoResize(auto_resize),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
mTabContainer = new LLTabContainer(std::string("Preview Tabs"),
|
||||
LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0),
|
||||
mTabPos,
|
||||
FALSE,
|
||||
FALSE);
|
||||
mTabContainer->setFollowsAll();
|
||||
if (isResizable() && mTabPos == LLTabContainer::BOTTOM)
|
||||
{
|
||||
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
|
||||
addChild(mTabContainer);
|
||||
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLXMLNodePtr LLMultiFloater::getXML(bool save_children) const
|
||||
{
|
||||
LLXMLNodePtr node = LLFloater::getXML();
|
||||
|
||||
node->setName(LL_MULTI_FLOATER_TAG);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void LLMultiFloater::open() /* Flawfinder: ignore */
|
||||
{
|
||||
if (mTabContainer->getTabCount() > 0)
|
||||
{
|
||||
LLFloater::open(); /* Flawfinder: ignore */
|
||||
}
|
||||
else
|
||||
{
|
||||
// for now, don't allow multifloaters
|
||||
// without any child floaters
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void LLMultiFloater::onClose(bool app_quitting)
|
||||
{
|
||||
if(closeAllFloaters() == TRUE)
|
||||
{
|
||||
LLFloater::onClose(app_quitting);
|
||||
}//else not all tabs could be closed...
|
||||
}
|
||||
|
||||
void LLMultiFloater::draw()
|
||||
{
|
||||
if (mTabContainer->getTabCount() == 0)
|
||||
{
|
||||
//RN: could this potentially crash in draw hierarchy?
|
||||
close();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (S32 i = 0; i < mTabContainer->getTabCount(); i++)
|
||||
{
|
||||
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i);
|
||||
if (floaterp->getShortTitle() != mTabContainer->getPanelTitle(i))
|
||||
{
|
||||
mTabContainer->setPanelTitle(i, floaterp->getShortTitle());
|
||||
}
|
||||
}
|
||||
LLFloater::draw();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLMultiFloater::closeAllFloaters()
|
||||
{
|
||||
S32 tabToClose = 0;
|
||||
S32 lastTabCount = mTabContainer->getTabCount();
|
||||
while (tabToClose < mTabContainer->getTabCount())
|
||||
{
|
||||
LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose);
|
||||
first_floater->close();
|
||||
if(lastTabCount == mTabContainer->getTabCount())
|
||||
{
|
||||
//Tab did not actually close, possibly due to a pending Save Confirmation dialog..
|
||||
//so try and close the next one in the list...
|
||||
tabToClose++;
|
||||
}else
|
||||
{
|
||||
//Tab closed ok.
|
||||
lastTabCount = mTabContainer->getTabCount();
|
||||
}
|
||||
}
|
||||
if( mTabContainer->getTabCount() != 0 )
|
||||
return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE.
|
||||
return TRUE; //else all tabs were successfully closed...
|
||||
}
|
||||
|
||||
void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
|
||||
{
|
||||
S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2);
|
||||
S32 new_height = llmax(getRect().getHeight(), content_height + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
|
||||
|
||||
if (isMinimized())
|
||||
{
|
||||
LLRect newrect;
|
||||
newrect.setLeftTopAndSize(getExpandedRect().mLeft, getExpandedRect().mTop, new_width, new_height);
|
||||
setExpandedRect(newrect);
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 old_height = getRect().getHeight();
|
||||
reshape(new_width, new_height);
|
||||
// keep top left corner in same position
|
||||
translate(0, old_height - new_height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
void addFloater(LLFloater* floaterp, BOOL select_added_floater)
|
||||
|
||||
Adds the LLFloater pointed to by floaterp to this.
|
||||
If floaterp is already hosted by this, then it is re-added to get
|
||||
new titles, etc.
|
||||
If select_added_floater is true, the LLFloater pointed to by floaterp will
|
||||
become the selected tab in this
|
||||
|
||||
Affects: mTabContainer, floaterp
|
||||
**/
|
||||
void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point)
|
||||
{
|
||||
if (!floaterp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mTabContainer)
|
||||
{
|
||||
llerrs << "Tab Container used without having been initialized." << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (floaterp->getHost() == this)
|
||||
{
|
||||
// already hosted by me, remove
|
||||
// do this so we get updated title, etc.
|
||||
mFloaterDataMap.erase(floaterp->getHandle());
|
||||
mTabContainer->removeTabPanel(floaterp);
|
||||
}
|
||||
else if (floaterp->getHost())
|
||||
{
|
||||
// floaterp is hosted by somebody else and
|
||||
// this is adding it, so remove it from it's old host
|
||||
floaterp->getHost()->removeFloater(floaterp);
|
||||
}
|
||||
else if (floaterp->getParent() == gFloaterView)
|
||||
{
|
||||
// rehost preview floater as child panel
|
||||
gFloaterView->removeChild(floaterp);
|
||||
}
|
||||
|
||||
// store original configuration
|
||||
LLFloaterData floater_data;
|
||||
floater_data.mWidth = floaterp->getRect().getWidth();
|
||||
floater_data.mHeight = floaterp->getRect().getHeight();
|
||||
floater_data.mCanMinimize = floaterp->isMinimizeable();
|
||||
floater_data.mCanResize = floaterp->isResizable();
|
||||
|
||||
// remove minimize and close buttons
|
||||
floaterp->setCanMinimize(FALSE);
|
||||
floaterp->setCanResize(FALSE);
|
||||
floaterp->setCanDrag(FALSE);
|
||||
floaterp->storeRectControl();
|
||||
// avoid double rendering of floater background (makes it more opaque)
|
||||
floaterp->setBackgroundVisible(FALSE);
|
||||
|
||||
if (mAutoResize)
|
||||
{
|
||||
growToFit(floater_data.mWidth, floater_data.mHeight);
|
||||
}
|
||||
|
||||
//add the panel, add it to proper maps
|
||||
mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point);
|
||||
mFloaterDataMap[floaterp->getHandle()] = floater_data;
|
||||
|
||||
updateResizeLimits();
|
||||
|
||||
if ( select_added_floater )
|
||||
{
|
||||
mTabContainer->selectTabPanel(floaterp);
|
||||
}
|
||||
else
|
||||
{
|
||||
// reassert visible tab (hiding new floater if necessary)
|
||||
mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
|
||||
}
|
||||
|
||||
floaterp->setHost(this);
|
||||
if (isMinimized())
|
||||
{
|
||||
floaterp->setVisible(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
BOOL selectFloater(LLFloater* floaterp)
|
||||
|
||||
If the LLFloater pointed to by floaterp is hosted by this,
|
||||
then its tab is selected and returns true. Otherwise returns false.
|
||||
|
||||
Affects: mTabContainer
|
||||
**/
|
||||
BOOL LLMultiFloater::selectFloater(LLFloater* floaterp)
|
||||
{
|
||||
return mTabContainer->selectTabPanel(floaterp);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLMultiFloater::selectNextFloater()
|
||||
{
|
||||
mTabContainer->selectNextTab();
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLMultiFloater::selectPrevFloater()
|
||||
{
|
||||
mTabContainer->selectPrevTab();
|
||||
}
|
||||
|
||||
void LLMultiFloater::showFloater(LLFloater* floaterp)
|
||||
{
|
||||
// we won't select a panel that already is selected
|
||||
// it is hard to do this internally to tab container
|
||||
// as tab selection is handled via index and the tab at a given
|
||||
// index might have changed
|
||||
if (floaterp != mTabContainer->getCurrentPanel() &&
|
||||
!mTabContainer->selectTabPanel(floaterp))
|
||||
{
|
||||
addFloater(floaterp, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLMultiFloater::removeFloater(LLFloater* floaterp)
|
||||
{
|
||||
if ( floaterp->getHost() != this )
|
||||
return;
|
||||
|
||||
floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle());
|
||||
if (found_data_it != mFloaterDataMap.end())
|
||||
{
|
||||
LLFloaterData& floater_data = found_data_it->second;
|
||||
floaterp->setCanMinimize(floater_data.mCanMinimize);
|
||||
if (!floater_data.mCanResize)
|
||||
{
|
||||
// restore original size
|
||||
floaterp->reshape(floater_data.mWidth, floater_data.mHeight);
|
||||
}
|
||||
floaterp->setCanResize(floater_data.mCanResize);
|
||||
mFloaterDataMap.erase(found_data_it);
|
||||
}
|
||||
mTabContainer->removeTabPanel(floaterp);
|
||||
floaterp->setBackgroundVisible(TRUE);
|
||||
floaterp->setCanDrag(TRUE);
|
||||
floaterp->setHost(NULL);
|
||||
floaterp->applyRectControl();
|
||||
|
||||
updateResizeLimits();
|
||||
|
||||
tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
|
||||
}
|
||||
|
||||
void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click)
|
||||
{
|
||||
// default implementation does nothing
|
||||
}
|
||||
|
||||
void LLMultiFloater::tabClose()
|
||||
{
|
||||
if (mTabContainer->getTabCount() == 0)
|
||||
{
|
||||
// no more children, close myself
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void LLMultiFloater::setVisible(BOOL visible)
|
||||
{
|
||||
// *FIX: shouldn't have to do this, fix adding to minimized multifloater
|
||||
LLFloater::setVisible(visible);
|
||||
|
||||
if (mTabContainer)
|
||||
{
|
||||
LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
|
||||
|
||||
if (cur_floaterp)
|
||||
{
|
||||
cur_floaterp->setVisible(visible);
|
||||
}
|
||||
|
||||
// if no tab selected, and we're being shown,
|
||||
// select last tab to be added
|
||||
if (visible && !cur_floaterp)
|
||||
{
|
||||
mTabContainer->selectLastTab();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask)
|
||||
{
|
||||
if (key == 'W' && mask == MASK_CONTROL)
|
||||
{
|
||||
LLFloater* floater = getActiveFloater();
|
||||
// is user closeable and is system closeable
|
||||
if (floater && floater->canClose() && floater->isCloseable())
|
||||
{
|
||||
floater->close();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return LLFloater::handleKeyHere(key, mask);
|
||||
}
|
||||
|
||||
LLFloater* LLMultiFloater::getActiveFloater()
|
||||
{
|
||||
return (LLFloater*)mTabContainer->getCurrentPanel();
|
||||
}
|
||||
|
||||
S32 LLMultiFloater::getFloaterCount()
|
||||
{
|
||||
return mTabContainer->getTabCount();
|
||||
}
|
||||
|
||||
/**
|
||||
BOOL isFloaterFlashing(LLFloater* floaterp)
|
||||
|
||||
Returns true if the LLFloater pointed to by floaterp
|
||||
is currently in a flashing state and is hosted by this.
|
||||
False otherwise.
|
||||
|
||||
Requires: floaterp != NULL
|
||||
**/
|
||||
BOOL LLMultiFloater::isFloaterFlashing(LLFloater* floaterp)
|
||||
{
|
||||
if ( floaterp && floaterp->getHost() == this )
|
||||
return mTabContainer->getTabPanelFlashing(floaterp);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
BOOL setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
|
||||
|
||||
Sets the current flashing state of the LLFloater pointed
|
||||
to by floaterp to be the BOOL flashing if the LLFloater pointed
|
||||
to by floaterp is hosted by this.
|
||||
|
||||
Requires: floaterp != NULL
|
||||
**/
|
||||
void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
|
||||
{
|
||||
if ( floaterp && floaterp->getHost() == this )
|
||||
mTabContainer->setTabPanelFlashing(floaterp, flashing);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLMultiFloater::onTabSelected(void* userdata, bool from_click)
|
||||
{
|
||||
LLMultiFloater* floaterp = (LLMultiFloater*)userdata;
|
||||
|
||||
floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(), from_click);
|
||||
}
|
||||
|
||||
void LLMultiFloater::setCanResize(BOOL can_resize)
|
||||
{
|
||||
LLFloater::setCanResize(can_resize);
|
||||
if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
|
||||
{
|
||||
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
mTabContainer->setRightTabBtnOffset(0);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLMultiFloater::postBuild()
|
||||
{
|
||||
// remember any original xml minimum size
|
||||
getResizeLimits(&mOrigMinWidth, &mOrigMinHeight);
|
||||
|
||||
if (mTabContainer)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
requires<LLTabContainer>("Preview Tabs");
|
||||
if (checkRequirements())
|
||||
{
|
||||
mTabContainer = getChild<LLTabContainer>("Preview Tabs");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void LLMultiFloater::updateResizeLimits()
|
||||
{
|
||||
// initialize minimum size constraint to the original xml values.
|
||||
S32 new_min_width = mOrigMinWidth;
|
||||
S32 new_min_height = mOrigMinHeight;
|
||||
// possibly increase minimum size constraint due to children's minimums.
|
||||
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
|
||||
{
|
||||
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
|
||||
if (floaterp)
|
||||
{
|
||||
new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
|
||||
new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
|
||||
}
|
||||
}
|
||||
setResizeLimits(new_min_width, new_min_height);
|
||||
|
||||
S32 cur_height = getRect().getHeight();
|
||||
S32 new_width = llmax(getRect().getWidth(), new_min_width);
|
||||
S32 new_height = llmax(getRect().getHeight(), new_min_height);
|
||||
|
||||
if (isMinimized())
|
||||
{
|
||||
const LLRect& expanded = getExpandedRect();
|
||||
LLRect newrect;
|
||||
newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height));
|
||||
setExpandedRect(newrect);
|
||||
}
|
||||
else
|
||||
{
|
||||
reshape(new_width, new_height);
|
||||
|
||||
// make sure upper left corner doesn't move
|
||||
translate(0, cur_height - getRect().getHeight());
|
||||
|
||||
// make sure this window is visible on screen when it has been modified
|
||||
// (tab added, etc)
|
||||
gFloaterView->adjustToFitScreen(this, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLXMLNodePtr LLFloater::getXML(bool save_children) const
|
||||
@@ -3129,3 +2617,15 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
|
||||
|
||||
moveResizeHandlesToFront();
|
||||
}
|
||||
|
||||
/*static */void VisibilityPolicy<LLFloater>::show(LLFloater* instance, const LLSD& key)
|
||||
{
|
||||
if (instance)
|
||||
{
|
||||
instance->open();
|
||||
if (instance->getHost())
|
||||
{
|
||||
instance->getHost()->open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,8 @@ private:
|
||||
|
||||
class LLFloater : public LLPanel
|
||||
{
|
||||
friend class LLFloaterView;
|
||||
friend class LLFloaterView;
|
||||
friend class LLMultiFloater;
|
||||
public:
|
||||
enum EFloaterButtons
|
||||
{
|
||||
@@ -395,69 +396,6 @@ private:
|
||||
S32 mSnapOffsetBottom;
|
||||
};
|
||||
|
||||
// https://wiki.lindenlab.com/mediawiki/index.php?title=LLMultiFloater&oldid=81376
|
||||
class LLMultiFloater : public LLFloater
|
||||
{
|
||||
public:
|
||||
LLMultiFloater();
|
||||
LLMultiFloater(LLTabContainer::TabPosition tab_pos);
|
||||
LLMultiFloater(const std::string& name);
|
||||
LLMultiFloater(const std::string& name, const LLRect& rect, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE);
|
||||
LLMultiFloater(const std::string& name, const std::string& rect_control, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE);
|
||||
virtual ~LLMultiFloater() {};
|
||||
|
||||
virtual BOOL postBuild();
|
||||
virtual LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
/*virtual*/ void open(); /* Flawfinder: ignore */
|
||||
/*virtual*/ void onClose(bool app_quitting);
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ void setVisible(BOOL visible);
|
||||
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
|
||||
|
||||
virtual void setCanResize(BOOL can_resize);
|
||||
virtual void growToFit(S32 content_width, S32 content_height);
|
||||
virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
|
||||
|
||||
virtual void showFloater(LLFloater* floaterp);
|
||||
virtual void removeFloater(LLFloater* floaterp);
|
||||
|
||||
virtual void tabOpen(LLFloater* opened_floater, bool from_click);
|
||||
virtual void tabClose();
|
||||
|
||||
virtual BOOL selectFloater(LLFloater* floaterp);
|
||||
virtual void selectNextFloater();
|
||||
virtual void selectPrevFloater();
|
||||
|
||||
virtual LLFloater* getActiveFloater();
|
||||
virtual BOOL isFloaterFlashing(LLFloater* floaterp);
|
||||
virtual S32 getFloaterCount();
|
||||
|
||||
virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing);
|
||||
virtual BOOL closeAllFloaters(); //Returns FALSE if the floater could not be closed due to pending confirmation dialogs
|
||||
void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; }
|
||||
static void onTabSelected(void* userdata, bool);
|
||||
|
||||
virtual void updateResizeLimits();
|
||||
|
||||
protected:
|
||||
struct LLFloaterData
|
||||
{
|
||||
S32 mWidth;
|
||||
S32 mHeight;
|
||||
BOOL mCanMinimize;
|
||||
BOOL mCanResize;
|
||||
};
|
||||
|
||||
LLTabContainer* mTabContainer;
|
||||
|
||||
typedef std::map<LLHandle<LLFloater>, LLFloaterData> floater_data_map_t;
|
||||
floater_data_map_t mFloaterDataMap;
|
||||
|
||||
LLTabContainer::TabPosition mTabPos;
|
||||
BOOL mAutoResize;
|
||||
S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late
|
||||
};
|
||||
|
||||
// visibility policy specialized for floaters
|
||||
template<>
|
||||
class VisibilityPolicy<LLFloater>
|
||||
@@ -473,17 +411,7 @@ public:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void show(LLFloater* instance, const LLSD& key)
|
||||
{
|
||||
if (instance)
|
||||
{
|
||||
instance->open();
|
||||
if (instance->getHost())
|
||||
{
|
||||
instance->getHost()->open();
|
||||
}
|
||||
}
|
||||
}
|
||||
static void show(LLFloater* instance, const LLSD& key);
|
||||
|
||||
static void hide(LLFloater* instance, const LLSD& key)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "llstring.h"
|
||||
#include "llframetimer.h"
|
||||
#include "llui.h"
|
||||
#include "llhandle.h"
|
||||
|
||||
class LLUICtrl;
|
||||
class LLMouseHandler;
|
||||
|
||||
164
indra/llui/llhandle.h
Normal file
164
indra/llui/llhandle.h
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @file llhandle.h
|
||||
* @brief "Handle" to an object (usually a floater) whose lifetime you don't
|
||||
* control.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLHANDLE_H
|
||||
#define LLHANDLE_H
|
||||
|
||||
#include "llpointer.h"
|
||||
|
||||
template <typename T>
|
||||
class LLTombStone : public LLRefCount
|
||||
{
|
||||
public:
|
||||
LLTombStone(T* target = NULL) : mTarget(target) {}
|
||||
|
||||
void setTarget(T* target) { mTarget = target; }
|
||||
T* getTarget() const { return mTarget; }
|
||||
private:
|
||||
T* mTarget;
|
||||
};
|
||||
|
||||
// LLHandles are used to refer to objects whose lifetime you do not control or influence.
|
||||
// Calling get() on a handle will return a pointer to the referenced object or NULL,
|
||||
// if the object no longer exists. Note that during the lifetime of the returned pointer,
|
||||
// you are assuming that the object will not be deleted by any action you perform,
|
||||
// or any other thread, as normal when using pointers, so avoid using that pointer outside of
|
||||
// the local code block.
|
||||
//
|
||||
// https://wiki.lindenlab.com/mediawiki/index.php?title=LLHandle&oldid=79669
|
||||
|
||||
template <typename T>
|
||||
class LLHandle
|
||||
{
|
||||
public:
|
||||
LLHandle() : mTombStone(getDefaultTombStone()) {}
|
||||
const LLHandle<T>& operator =(const LLHandle<T>& other)
|
||||
{
|
||||
mTombStone = other.mTombStone;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isDead() const
|
||||
{
|
||||
return mTombStone->getTarget() == NULL;
|
||||
}
|
||||
|
||||
void markDead()
|
||||
{
|
||||
mTombStone = getDefaultTombStone();
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return mTombStone->getTarget();
|
||||
}
|
||||
|
||||
friend bool operator== (const LLHandle<T>& lhs, const LLHandle<T>& rhs)
|
||||
{
|
||||
return lhs.mTombStone == rhs.mTombStone;
|
||||
}
|
||||
friend bool operator!= (const LLHandle<T>& lhs, const LLHandle<T>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
friend bool operator< (const LLHandle<T>& lhs, const LLHandle<T>& rhs)
|
||||
{
|
||||
return lhs.mTombStone < rhs.mTombStone;
|
||||
}
|
||||
friend bool operator> (const LLHandle<T>& lhs, const LLHandle<T>& rhs)
|
||||
{
|
||||
return lhs.mTombStone > rhs.mTombStone;
|
||||
}
|
||||
|
||||
protected:
|
||||
LLPointer<LLTombStone<T> > mTombStone;
|
||||
|
||||
private:
|
||||
static LLPointer<LLTombStone<T> >& getDefaultTombStone()
|
||||
{
|
||||
static LLPointer<LLTombStone<T> > sDefaultTombStone = new LLTombStone<T>;
|
||||
return sDefaultTombStone;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class LLRootHandle : public LLHandle<T>
|
||||
{
|
||||
public:
|
||||
LLRootHandle(T* object) { bind(object); }
|
||||
LLRootHandle() {};
|
||||
~LLRootHandle() { unbind(); }
|
||||
|
||||
// this is redundant, since a LLRootHandle *is* an LLHandle
|
||||
LLHandle<T> getHandle() { return LLHandle<T>(*this); }
|
||||
|
||||
void bind(T* object)
|
||||
{
|
||||
// unbind existing tombstone
|
||||
if (LLHandle<T>::mTombStone.notNull())
|
||||
{
|
||||
if (LLHandle<T>::mTombStone->getTarget() == object) return;
|
||||
LLHandle<T>::mTombStone->setTarget(NULL);
|
||||
}
|
||||
// tombstone reference counted, so no paired delete
|
||||
LLHandle<T>::mTombStone = new LLTombStone<T>(object);
|
||||
}
|
||||
|
||||
void unbind()
|
||||
{
|
||||
LLHandle<T>::mTombStone->setTarget(NULL);
|
||||
}
|
||||
|
||||
//don't allow copying of root handles, since there should only be one
|
||||
private:
|
||||
LLRootHandle(const LLRootHandle& other) {};
|
||||
};
|
||||
|
||||
// Use this as a mixin for simple classes that need handles and when you don't
|
||||
// want handles at multiple points of the inheritance hierarchy
|
||||
template <typename T>
|
||||
class LLHandleProvider
|
||||
{
|
||||
protected:
|
||||
typedef LLHandle<T> handle_type_t;
|
||||
LLHandleProvider()
|
||||
{
|
||||
// provided here to enforce T deriving from LLHandleProvider<T>
|
||||
}
|
||||
|
||||
LLHandle<T> getHandle()
|
||||
{
|
||||
// perform lazy binding to avoid small tombstone allocations for handle
|
||||
// providers whose handles are never referenced
|
||||
mHandle.bind(static_cast<T*>(this));
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
private:
|
||||
LLRootHandle<T> mHandle;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1964,6 +1964,7 @@ void LLLineEditor::draw()
|
||||
text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
select_left - mScrollHPos,
|
||||
mMaxHPixels - llround(rendered_pixels_right),
|
||||
&rendered_pixels_right);
|
||||
@@ -1983,6 +1984,7 @@ void LLLineEditor::draw()
|
||||
LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ),
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
select_right - mScrollHPos - rendered_text,
|
||||
mMaxHPixels - llround(rendered_pixels_right),
|
||||
&rendered_pixels_right);
|
||||
@@ -1997,6 +1999,7 @@ void LLLineEditor::draw()
|
||||
text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
S32_MAX,
|
||||
mMaxHPixels - llround(rendered_pixels_right),
|
||||
&rendered_pixels_right);
|
||||
@@ -2010,6 +2013,7 @@ void LLLineEditor::draw()
|
||||
text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
S32_MAX,
|
||||
mMaxHPixels - llround(rendered_pixels_right),
|
||||
&rendered_pixels_right);
|
||||
@@ -2050,6 +2054,7 @@ void LLLineEditor::draw()
|
||||
LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ),
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
1);
|
||||
}
|
||||
|
||||
@@ -2075,6 +2080,7 @@ void LLLineEditor::draw()
|
||||
LLFontGL::LEFT,
|
||||
LLFontGL::BOTTOM,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
S32_MAX,
|
||||
mMaxHPixels - llround(rendered_pixels_right),
|
||||
&rendered_pixels_right, FALSE);
|
||||
@@ -2099,6 +2105,7 @@ void LLLineEditor::draw()
|
||||
LLFontGL::LEFT,
|
||||
LLFontGL::BOTTOM,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
S32_MAX,
|
||||
mMaxHPixels - llround(rendered_pixels_right),
|
||||
&rendered_pixels_right, FALSE);
|
||||
@@ -2547,9 +2554,8 @@ BOOL LLLineEditor::evaluateFloat()
|
||||
else
|
||||
{
|
||||
// Replace the expression with the result
|
||||
std::ostringstream result_str;
|
||||
result_str << result;
|
||||
setText(result_str.str());
|
||||
std::string result_str = llformat("%f", result);
|
||||
setText(result_str);
|
||||
selectAll();
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
#include "lleditmenuhandler.h"
|
||||
#include "lluictrl.h"
|
||||
#include "lluiimage.h"
|
||||
#include "lluistring.h"
|
||||
#include "llviewborder.h"
|
||||
|
||||
|
||||
@@ -447,10 +447,10 @@ void LLMenuItemGL::draw( void )
|
||||
|
||||
LLColor4 color;
|
||||
|
||||
U8 font_style = mStyle;
|
||||
LLFontGL::ShadowType font_shadow = LLFontGL::NO_SHADOW;
|
||||
if (getEnabled() && !mDrawTextDisabled )
|
||||
{
|
||||
font_style |= LLFontGL::DROP_SHADOW_SOFT;
|
||||
font_shadow = LLFontGL::DROP_SHADOW_SOFT;
|
||||
}
|
||||
|
||||
if ( getEnabled() && getHighlight() )
|
||||
@@ -470,26 +470,26 @@ void LLMenuItemGL::draw( void )
|
||||
if (mBriefItem)
|
||||
{
|
||||
mFont->render( mLabel, 0, BRIEF_PAD_PIXELS / 2, 0, color,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, font_style );
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, mStyle );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !mDrawBoolLabel.empty() )
|
||||
{
|
||||
mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, mStyle, font_shadow, S32_MAX, S32_MAX, NULL, FALSE );
|
||||
}
|
||||
mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, mStyle, font_shadow, S32_MAX, S32_MAX, NULL, FALSE );
|
||||
if( !mDrawAccelLabel.empty() )
|
||||
{
|
||||
mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
|
||||
LLFontGL::RIGHT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
|
||||
LLFontGL::RIGHT, LLFontGL::BOTTOM, mStyle, font_shadow, S32_MAX, S32_MAX, NULL, FALSE );
|
||||
}
|
||||
if( !mDrawBranchLabel.empty() )
|
||||
{
|
||||
mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
|
||||
LLFontGL::RIGHT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
|
||||
LLFontGL::RIGHT, LLFontGL::BOTTOM, mStyle, font_shadow, S32_MAX, S32_MAX, NULL, FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1638,10 +1638,10 @@ void LLMenuItemBranchDownGL::draw( void )
|
||||
gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
|
||||
}
|
||||
|
||||
U8 font_style = getFontStyle();
|
||||
LLFontGL::ShadowType font_shadow = LLFontGL::NO_SHADOW;
|
||||
if (getEnabled() && !getDrawTextDisabled() )
|
||||
{
|
||||
font_style |= LLFontGL::DROP_SHADOW_SOFT;
|
||||
font_shadow = LLFontGL::DROP_SHADOW_SOFT;
|
||||
}
|
||||
|
||||
LLColor4 color;
|
||||
@@ -1658,7 +1658,7 @@ void LLMenuItemBranchDownGL::draw( void )
|
||||
color = getDisabledColor();
|
||||
}
|
||||
getFont()->render( mLabel.getWString(), 0, (F32)getRect().getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color,
|
||||
LLFontGL::HCENTER, LLFontGL::BOTTOM, font_style );
|
||||
LLFontGL::HCENTER, LLFontGL::BOTTOM, getFontStyle(), font_shadow );
|
||||
|
||||
|
||||
// underline navigation key only when keyboard navigation has been initiated
|
||||
@@ -3858,7 +3858,7 @@ void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
|
||||
center.mX = (getRect().mLeft + getRect().mRight) / 2;
|
||||
center.mY = (getRect().mTop + getRect().mBottom) / 2;
|
||||
|
||||
LLUI::setCursorPositionLocal(getParent(), center.mX, center.mY);
|
||||
LLUI::setMousePositionLocal(getParent(), center.mX, center.mY);
|
||||
}
|
||||
|
||||
// *FIX: what happens when mouse buttons reversed?
|
||||
|
||||
547
indra/llui/llmultifloater.cpp
Normal file
547
indra/llui/llmultifloater.cpp
Normal file
@@ -0,0 +1,547 @@
|
||||
/**
|
||||
* @file llmultifloater.cpp
|
||||
* @brief LLFloater that hosts other floaters
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Floating "windows" within the GL display, like the inventory floater,
|
||||
// mini-map floater, etc.
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llmultifloater.h"
|
||||
#include "llresizehandle.h"
|
||||
|
||||
//
|
||||
// LLMultiFloater
|
||||
//
|
||||
|
||||
LLMultiFloater::LLMultiFloater() :
|
||||
mTabContainer(NULL),
|
||||
mTabPos(LLTabContainer::TOP),
|
||||
mAutoResize(TRUE),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LLMultiFloater::LLMultiFloater(LLTabContainer::TabPosition tab_pos) :
|
||||
mTabContainer(NULL),
|
||||
mTabPos(tab_pos),
|
||||
mAutoResize(TRUE),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LLMultiFloater::LLMultiFloater(const std::string &name) :
|
||||
LLFloater(name),
|
||||
mTabContainer(NULL),
|
||||
mTabPos(LLTabContainer::TOP),
|
||||
mAutoResize(FALSE),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
}
|
||||
|
||||
LLMultiFloater::LLMultiFloater(
|
||||
const std::string& name,
|
||||
const LLRect& rect,
|
||||
LLTabContainer::TabPosition tab_pos,
|
||||
BOOL auto_resize) :
|
||||
LLFloater(name, rect, name),
|
||||
mTabContainer(NULL),
|
||||
mTabPos(LLTabContainer::TOP),
|
||||
mAutoResize(auto_resize),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
mTabContainer = new LLTabContainer(std::string("Preview Tabs"),
|
||||
LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0),
|
||||
mTabPos,
|
||||
FALSE,
|
||||
FALSE);
|
||||
mTabContainer->setFollowsAll();
|
||||
if (isResizable())
|
||||
{
|
||||
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
|
||||
addChild(mTabContainer);
|
||||
}
|
||||
|
||||
LLMultiFloater::LLMultiFloater(
|
||||
const std::string& name,
|
||||
const std::string& rect_control,
|
||||
LLTabContainer::TabPosition tab_pos,
|
||||
BOOL auto_resize) :
|
||||
LLFloater(name, rect_control, name),
|
||||
mTabContainer(NULL),
|
||||
mTabPos(tab_pos),
|
||||
mAutoResize(auto_resize),
|
||||
mOrigMinWidth(0),
|
||||
mOrigMinHeight(0)
|
||||
{
|
||||
mTabContainer = new LLTabContainer(std::string("Preview Tabs"),
|
||||
LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0),
|
||||
mTabPos,
|
||||
FALSE,
|
||||
FALSE);
|
||||
mTabContainer->setFollowsAll();
|
||||
if (isResizable() && mTabPos == LLTabContainer::BOTTOM)
|
||||
{
|
||||
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
|
||||
addChild(mTabContainer);
|
||||
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLXMLNodePtr LLMultiFloater::getXML(bool save_children) const
|
||||
{
|
||||
LLXMLNodePtr node = LLFloater::getXML();
|
||||
|
||||
node->setName(LL_MULTI_FLOATER_TAG);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void LLMultiFloater::open() /* Flawfinder: ignore */
|
||||
{
|
||||
if (mTabContainer->getTabCount() > 0)
|
||||
{
|
||||
LLFloater::open(); /* Flawfinder: ignore */
|
||||
}
|
||||
else
|
||||
{
|
||||
// for now, don't allow multifloaters
|
||||
// without any child floaters
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void LLMultiFloater::onClose(bool app_quitting)
|
||||
{
|
||||
if(closeAllFloaters() == TRUE)
|
||||
{
|
||||
LLFloater::onClose(app_quitting);
|
||||
}//else not all tabs could be closed...
|
||||
}
|
||||
|
||||
void LLMultiFloater::draw()
|
||||
{
|
||||
if (mTabContainer->getTabCount() == 0)
|
||||
{
|
||||
//RN: could this potentially crash in draw hierarchy?
|
||||
close();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (S32 i = 0; i < mTabContainer->getTabCount(); i++)
|
||||
{
|
||||
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i);
|
||||
if (floaterp->getShortTitle() != mTabContainer->getPanelTitle(i))
|
||||
{
|
||||
mTabContainer->setPanelTitle(i, floaterp->getShortTitle());
|
||||
}
|
||||
}
|
||||
LLFloater::draw();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLMultiFloater::closeAllFloaters()
|
||||
{
|
||||
S32 tabToClose = 0;
|
||||
S32 lastTabCount = mTabContainer->getTabCount();
|
||||
while (tabToClose < mTabContainer->getTabCount())
|
||||
{
|
||||
LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose);
|
||||
first_floater->close();
|
||||
if(lastTabCount == mTabContainer->getTabCount())
|
||||
{
|
||||
//Tab did not actually close, possibly due to a pending Save Confirmation dialog..
|
||||
//so try and close the next one in the list...
|
||||
tabToClose++;
|
||||
}else
|
||||
{
|
||||
//Tab closed ok.
|
||||
lastTabCount = mTabContainer->getTabCount();
|
||||
}
|
||||
}
|
||||
if( mTabContainer->getTabCount() != 0 )
|
||||
return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE.
|
||||
return TRUE; //else all tabs were successfully closed...
|
||||
}
|
||||
|
||||
void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
|
||||
{
|
||||
S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2);
|
||||
S32 new_height = llmax(getRect().getHeight(), content_height + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
|
||||
|
||||
if (isMinimized())
|
||||
{
|
||||
LLRect newrect;
|
||||
newrect.setLeftTopAndSize(getExpandedRect().mLeft, getExpandedRect().mTop, new_width, new_height);
|
||||
setExpandedRect(newrect);
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 old_height = getRect().getHeight();
|
||||
reshape(new_width, new_height);
|
||||
// keep top left corner in same position
|
||||
translate(0, old_height - new_height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
void addFloater(LLFloater* floaterp, BOOL select_added_floater)
|
||||
|
||||
Adds the LLFloater pointed to by floaterp to this.
|
||||
If floaterp is already hosted by this, then it is re-added to get
|
||||
new titles, etc.
|
||||
If select_added_floater is true, the LLFloater pointed to by floaterp will
|
||||
become the selected tab in this
|
||||
|
||||
Affects: mTabContainer, floaterp
|
||||
**/
|
||||
void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point)
|
||||
{
|
||||
if (!floaterp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mTabContainer)
|
||||
{
|
||||
llerrs << "Tab Container used without having been initialized." << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (floaterp->getHost() == this)
|
||||
{
|
||||
// already hosted by me, remove
|
||||
// do this so we get updated title, etc.
|
||||
mFloaterDataMap.erase(floaterp->getHandle());
|
||||
mTabContainer->removeTabPanel(floaterp);
|
||||
}
|
||||
else if (floaterp->getHost())
|
||||
{
|
||||
// floaterp is hosted by somebody else and
|
||||
// this is adding it, so remove it from it's old host
|
||||
floaterp->getHost()->removeFloater(floaterp);
|
||||
}
|
||||
else if (floaterp->getParent() == gFloaterView)
|
||||
{
|
||||
// rehost preview floater as child panel
|
||||
gFloaterView->removeChild(floaterp);
|
||||
}
|
||||
|
||||
// store original configuration
|
||||
LLFloaterData floater_data;
|
||||
floater_data.mWidth = floaterp->getRect().getWidth();
|
||||
floater_data.mHeight = floaterp->getRect().getHeight();
|
||||
floater_data.mCanMinimize = floaterp->isMinimizeable();
|
||||
floater_data.mCanResize = floaterp->isResizable();
|
||||
|
||||
// remove minimize and close buttons
|
||||
floaterp->setCanMinimize(FALSE);
|
||||
floaterp->setCanResize(FALSE);
|
||||
floaterp->setCanDrag(FALSE);
|
||||
floaterp->storeRectControl();
|
||||
// avoid double rendering of floater background (makes it more opaque)
|
||||
floaterp->setBackgroundVisible(FALSE);
|
||||
|
||||
if (mAutoResize)
|
||||
{
|
||||
growToFit(floater_data.mWidth, floater_data.mHeight);
|
||||
}
|
||||
|
||||
//add the panel, add it to proper maps
|
||||
mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point);
|
||||
mFloaterDataMap[floaterp->getHandle()] = floater_data;
|
||||
|
||||
updateResizeLimits();
|
||||
|
||||
if ( select_added_floater )
|
||||
{
|
||||
mTabContainer->selectTabPanel(floaterp);
|
||||
}
|
||||
else
|
||||
{
|
||||
// reassert visible tab (hiding new floater if necessary)
|
||||
mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
|
||||
}
|
||||
|
||||
floaterp->setHost(this);
|
||||
if (isMinimized())
|
||||
{
|
||||
floaterp->setVisible(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
BOOL selectFloater(LLFloater* floaterp)
|
||||
|
||||
If the LLFloater pointed to by floaterp is hosted by this,
|
||||
then its tab is selected and returns true. Otherwise returns false.
|
||||
|
||||
Affects: mTabContainer
|
||||
**/
|
||||
BOOL LLMultiFloater::selectFloater(LLFloater* floaterp)
|
||||
{
|
||||
return mTabContainer->selectTabPanel(floaterp);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLMultiFloater::selectNextFloater()
|
||||
{
|
||||
mTabContainer->selectNextTab();
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLMultiFloater::selectPrevFloater()
|
||||
{
|
||||
mTabContainer->selectPrevTab();
|
||||
}
|
||||
|
||||
void LLMultiFloater::showFloater(LLFloater* floaterp)
|
||||
{
|
||||
// we won't select a panel that already is selected
|
||||
// it is hard to do this internally to tab container
|
||||
// as tab selection is handled via index and the tab at a given
|
||||
// index might have changed
|
||||
if (floaterp != mTabContainer->getCurrentPanel() &&
|
||||
!mTabContainer->selectTabPanel(floaterp))
|
||||
{
|
||||
addFloater(floaterp, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLMultiFloater::removeFloater(LLFloater* floaterp)
|
||||
{
|
||||
if (!floaterp || floaterp->getHost() != this )
|
||||
return;
|
||||
|
||||
floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle());
|
||||
if (found_data_it != mFloaterDataMap.end())
|
||||
{
|
||||
LLFloaterData& floater_data = found_data_it->second;
|
||||
floaterp->setCanMinimize(floater_data.mCanMinimize);
|
||||
if (!floater_data.mCanResize)
|
||||
{
|
||||
// restore original size
|
||||
floaterp->reshape(floater_data.mWidth, floater_data.mHeight);
|
||||
}
|
||||
floaterp->setCanResize(floater_data.mCanResize);
|
||||
mFloaterDataMap.erase(found_data_it);
|
||||
}
|
||||
mTabContainer->removeTabPanel(floaterp);
|
||||
floaterp->setBackgroundVisible(TRUE);
|
||||
floaterp->setCanDrag(TRUE);
|
||||
floaterp->setHost(NULL);
|
||||
floaterp->applyRectControl();
|
||||
|
||||
updateResizeLimits();
|
||||
|
||||
tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
|
||||
}
|
||||
|
||||
void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click)
|
||||
{
|
||||
// default implementation does nothing
|
||||
}
|
||||
|
||||
void LLMultiFloater::tabClose()
|
||||
{
|
||||
if (mTabContainer->getTabCount() == 0)
|
||||
{
|
||||
// no more children, close myself
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void LLMultiFloater::setVisible(BOOL visible)
|
||||
{
|
||||
// *FIX: shouldn't have to do this, fix adding to minimized multifloater
|
||||
LLFloater::setVisible(visible);
|
||||
|
||||
if (mTabContainer)
|
||||
{
|
||||
LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
|
||||
|
||||
if (cur_floaterp)
|
||||
{
|
||||
cur_floaterp->setVisible(visible);
|
||||
}
|
||||
|
||||
// if no tab selected, and we're being shown,
|
||||
// select last tab to be added
|
||||
if (visible && !cur_floaterp)
|
||||
{
|
||||
mTabContainer->selectLastTab();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask)
|
||||
{
|
||||
if (key == 'W' && mask == MASK_CONTROL)
|
||||
{
|
||||
LLFloater* floater = getActiveFloater();
|
||||
// is user closeable and is system closeable
|
||||
if (floater && floater->canClose() && floater->isCloseable())
|
||||
{
|
||||
floater->close();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return LLFloater::handleKeyHere(key, mask);
|
||||
}
|
||||
|
||||
LLFloater* LLMultiFloater::getActiveFloater()
|
||||
{
|
||||
return (LLFloater*)mTabContainer->getCurrentPanel();
|
||||
}
|
||||
|
||||
S32 LLMultiFloater::getFloaterCount()
|
||||
{
|
||||
return mTabContainer->getTabCount();
|
||||
}
|
||||
|
||||
/**
|
||||
BOOL isFloaterFlashing(LLFloater* floaterp)
|
||||
|
||||
Returns true if the LLFloater pointed to by floaterp
|
||||
is currently in a flashing state and is hosted by this.
|
||||
False otherwise.
|
||||
|
||||
Requires: floaterp != NULL
|
||||
**/
|
||||
BOOL LLMultiFloater::isFloaterFlashing(LLFloater* floaterp)
|
||||
{
|
||||
if ( floaterp && floaterp->getHost() == this )
|
||||
return mTabContainer->getTabPanelFlashing(floaterp);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
BOOL setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
|
||||
|
||||
Sets the current flashing state of the LLFloater pointed
|
||||
to by floaterp to be the BOOL flashing if the LLFloater pointed
|
||||
to by floaterp is hosted by this.
|
||||
|
||||
Requires: floaterp != NULL
|
||||
**/
|
||||
void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
|
||||
{
|
||||
if ( floaterp && floaterp->getHost() == this )
|
||||
mTabContainer->setTabPanelFlashing(floaterp, flashing);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLMultiFloater::onTabSelected(void* userdata, bool from_click)
|
||||
{
|
||||
LLMultiFloater* floaterp = (LLMultiFloater*)userdata;
|
||||
|
||||
floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(), from_click);
|
||||
}
|
||||
|
||||
void LLMultiFloater::setCanResize(BOOL can_resize)
|
||||
{
|
||||
LLFloater::setCanResize(can_resize);
|
||||
if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
|
||||
{
|
||||
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
mTabContainer->setRightTabBtnOffset(0);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLMultiFloater::postBuild()
|
||||
{
|
||||
// remember any original xml minimum size
|
||||
getResizeLimits(&mOrigMinWidth, &mOrigMinHeight);
|
||||
|
||||
if (mTabContainer)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
requires<LLTabContainer>("Preview Tabs");
|
||||
if (checkRequirements())
|
||||
{
|
||||
mTabContainer = getChild<LLTabContainer>("Preview Tabs");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void LLMultiFloater::updateResizeLimits()
|
||||
{
|
||||
// initialize minimum size constraint to the original xml values.
|
||||
S32 new_min_width = mOrigMinWidth;
|
||||
S32 new_min_height = mOrigMinHeight;
|
||||
// possibly increase minimum size constraint due to children's minimums.
|
||||
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
|
||||
{
|
||||
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
|
||||
if (floaterp)
|
||||
{
|
||||
new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
|
||||
new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
|
||||
}
|
||||
}
|
||||
setResizeLimits(new_min_width, new_min_height);
|
||||
|
||||
S32 cur_height = getRect().getHeight();
|
||||
S32 new_width = llmax(getRect().getWidth(), new_min_width);
|
||||
S32 new_height = llmax(getRect().getHeight(), new_min_height);
|
||||
|
||||
if (isMinimized())
|
||||
{
|
||||
const LLRect& expanded = getExpandedRect();
|
||||
LLRect newrect;
|
||||
newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height));
|
||||
setExpandedRect(newrect);
|
||||
}
|
||||
else
|
||||
{
|
||||
reshape(new_width, new_height);
|
||||
|
||||
// make sure upper left corner doesn't move
|
||||
translate(0, cur_height - getRect().getHeight());
|
||||
|
||||
// make sure this window is visible on screen when it has been modified
|
||||
// (tab added, etc)
|
||||
gFloaterView->adjustToFitScreen(this, TRUE);
|
||||
}
|
||||
}
|
||||
103
indra/llui/llmultifloater.h
Normal file
103
indra/llui/llmultifloater.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file llmultifloater.h
|
||||
* @brief LLFloater that hosts other floaters
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Floating "windows" within the GL display, like the inventory floater,
|
||||
// mini-map floater, etc.
|
||||
|
||||
|
||||
#ifndef LL_MULTI_FLOATER_H
|
||||
#define LL_MULTI_FLOATER_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "lltabcontainer.h" // for LLTabContainer::eInsertionPoint
|
||||
|
||||
// https://wiki.lindenlab.com/mediawiki/index.php?title=LLMultiFloater&oldid=81376
|
||||
class LLMultiFloater : public LLFloater
|
||||
{
|
||||
public:
|
||||
LLMultiFloater();
|
||||
LLMultiFloater(LLTabContainer::TabPosition tab_pos);
|
||||
LLMultiFloater(const std::string& name);
|
||||
LLMultiFloater(const std::string& name, const LLRect& rect, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE);
|
||||
LLMultiFloater(const std::string& name, const std::string& rect_control, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE);
|
||||
virtual ~LLMultiFloater() {};
|
||||
|
||||
virtual BOOL postBuild();
|
||||
virtual LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
/*virtual*/ void open(); /* Flawfinder: ignore */
|
||||
/*virtual*/ void onClose(bool app_quitting);
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ void setVisible(BOOL visible);
|
||||
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
|
||||
|
||||
virtual void setCanResize(BOOL can_resize);
|
||||
virtual void growToFit(S32 content_width, S32 content_height);
|
||||
virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
|
||||
|
||||
virtual void showFloater(LLFloater* floaterp);
|
||||
virtual void removeFloater(LLFloater* floaterp);
|
||||
|
||||
virtual void tabOpen(LLFloater* opened_floater, bool from_click);
|
||||
virtual void tabClose();
|
||||
|
||||
virtual BOOL selectFloater(LLFloater* floaterp);
|
||||
virtual void selectNextFloater();
|
||||
virtual void selectPrevFloater();
|
||||
|
||||
virtual LLFloater* getActiveFloater();
|
||||
virtual BOOL isFloaterFlashing(LLFloater* floaterp);
|
||||
virtual S32 getFloaterCount();
|
||||
|
||||
virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing);
|
||||
virtual BOOL closeAllFloaters(); //Returns FALSE if the floater could not be closed due to pending confirmation dialogs
|
||||
void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; }
|
||||
static void onTabSelected(void* userdata, bool);
|
||||
|
||||
virtual void updateResizeLimits();
|
||||
|
||||
protected:
|
||||
struct LLFloaterData
|
||||
{
|
||||
S32 mWidth;
|
||||
S32 mHeight;
|
||||
BOOL mCanMinimize;
|
||||
BOOL mCanResize;
|
||||
};
|
||||
|
||||
LLTabContainer* mTabContainer;
|
||||
|
||||
typedef std::map<LLHandle<LLFloater>, LLFloaterData> floater_data_map_t;
|
||||
floater_data_map_t mFloaterDataMap;
|
||||
|
||||
LLTabContainer::TabPosition mTabPos;
|
||||
BOOL mAutoResize;
|
||||
S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late
|
||||
};
|
||||
|
||||
#endif // LL_MULTI_FLOATER_H
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "llfocusmgr.h"
|
||||
#include "llkeyboard.h" // for the MASK constants
|
||||
#include "llcontrol.h"
|
||||
#include "llimagegl.h"
|
||||
#include "lluiimage.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user