From 111c671a21f5ad498c1ae8ecf114b38d477f61eb Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 8 May 2011 15:44:06 +0200 Subject: [PATCH 01/87] Also strip libraries on x86_64, which uses lib32 and lib64 directory names --- indra/newview/viewer_manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 9ca3b4704..a663389ea 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -723,8 +723,8 @@ class LinuxManifest(ViewerManifest): if self.args['buildtype'].lower() in ['release', 'releasesse2']: print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build" # makes some small assumptions about our packaged dir structure - self.run_command("find %(d)r/bin %(d)r/lib -type f | xargs --no-run-if-empty strip --strip-unneeded" % {'d': self.get_dst_prefix()} ) - self.run_command("find %(d)r/bin %(d)r/lib -type f -not -name \\*.so | xargs --no-run-if-empty strip -s" % {'d': self.get_dst_prefix()} ) + self.run_command("find %(d)r/bin %(d)r/lib* -type f | xargs --no-run-if-empty strip --strip-unneeded" % {'d': self.get_dst_prefix()} ) + self.run_command("find %(d)r/bin %(d)r/lib* -type f -not -name \\*.so | xargs --no-run-if-empty strip -s" % {'d': self.get_dst_prefix()} ) # Fix access permissions self.run_command(""" From 3a1d753344196a5bfb87a47c02743bb63a57312a Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 8 May 2011 15:10:51 +0200 Subject: [PATCH 02/87] Use LL_DEBUG_TERMINAL_COMMAND and LL_DEBUG_GDB_PATH Upgraded the code that attaches gdb to a plugin for linux to the code that I wrote for viewer 2. --- doc/contributions.txt | 1 + indra/llplugin/llpluginprocessparent.cpp | 48 +++++++++++++++--------- indra/newview/app_settings/settings.xml | 2 +- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 258e139bc..f70336a94 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -74,6 +74,7 @@ Aleric Inglewood VWR-24312 VWR-24320 VWR-24333 + VWR-24334 SNOW-47 SNOW-84 SNOW-86 diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 2cb6b2832..2be917be6 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -38,6 +38,9 @@ #include "llpluginprocessparent.h" #include "llpluginmessagepipe.h" #include "llpluginmessageclasses.h" +#if LL_LINUX +#include +#endif #include "llapr.h" @@ -373,14 +376,12 @@ void LLPluginProcessParent::idle(void) { if(mDebug) { - #if LL_DARWIN // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue. - + std::stringstream cmd; + +#if LL_DARWIN // The command we're constructing would look like this on the command line: // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell' - - std::stringstream cmd; - mDebugger.setExecutable("/usr/bin/osascript"); mDebugger.addArgument("-e"); mDebugger.addArgument("tell application \"Terminal\""); @@ -392,19 +393,32 @@ void LLPluginProcessParent::idle(void) mDebugger.addArgument("-e"); mDebugger.addArgument("end tell"); mDebugger.launch(); - - #elif LL_LINUX - - std::stringstream cmd; - - mDebugger.setExecutable("/usr/bin/gnome-terminal"); - mDebugger.addArgument("--geometry=165x24-0+0"); - mDebugger.addArgument("-e"); - cmd << "/usr/bin/gdb -n /proc/" << mProcess.getProcessID() << "/exe " << mProcess.getProcessID(); - mDebugger.addArgument(cmd.str()); +#elif LL_LINUX + // The command we're constructing would look like this on the command line: + // /usr/bin/xterm -geometry 160x24-0+0 -e '/usr/bin/gdb -n /proc/12345/exe 12345' + // This can be changed by setting the following environment variables, for example: + // export LL_DEBUG_TERMINAL_COMMAND="/usr/bin/gnome-terminal --geometry=165x24-0+0 -e %s" + // export LL_DEBUG_GDB_PATH=/usr/bin/gdb + char const* env; + std::string const terminal_command = (env = getenv("LL_DEBUG_TERMINAL_COMMAND")) ? env : "/usr/bin/xterm -geometry 160x24+0+0 -e %s"; + char const* const gdb_path = (env = getenv("LL_DEBUG_GDB_PATH")) ? env : "/usr/bin/gdb"; + cmd << gdb_path << " -n /proc/" << mProcess.getProcessID() << "/exe " << mProcess.getProcessID(); + std::vector tokens = boost::program_options::split_unix(terminal_command, " "); + std::vector::iterator token = tokens.begin(); + mDebugger.setExecutable(*token); + while (++token != tokens.end()) + { + if (*token == "%s") + { + mDebugger.addArgument(cmd.str()); + } + else + { + mDebugger.addArgument(*token); + } + } mDebugger.launch(); - - #endif +#endif } // This will allow us to time out if the process never starts. diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 038090663..b0a04a3bd 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1935,7 +1935,7 @@ PluginAttachDebuggerToPlugins Comment - TODO: understand what this actually does -.-sg + Opens a terminal window with a debugger and attach it, every time a new SLPlugin process is started. Persist 1 Type From 474acdbff9d3a4d6fd60f9437135654e0b1a69f6 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 8 May 2011 16:16:11 +0200 Subject: [PATCH 03/87] Add support for libcwd. This patch has no influence if you don't have libcwd installed. Note that libcwd (http://libcwd.sourceforge.net/) is only available for linux. A default compile of libcwd does memory allocation tracking, which is too slow for everyday usage of the viewer (usable, but notably slower) and we don't need that. Configure your libcwd as follows: ./configure --prefix=/sl/usr --disable-alloc --enable-optimize Or whatever prefix you prefer (add --enable-maintainer-mode if you're compiling it from the SVN repository), add --disable-nonthreading to compile twice as fast. If you have it installed you can activate it's use by setting a few environment variables: CXXFLAGS="$(pkg-config --cflags libcwd_r)" LDFLAGS="$(pkg-config --libs libcwd_r) -lpthread" and then reconfiguring the viewer. The -lpthread is needed when using ld.gold, however, if you leave it out you might get an LDFLAGS that ends on trailing whitespaces, which doesn't work for some reason. Also, if you installed it in a non-standard place (/sl/usr above) then you need this to run the viewer (and tests): export LD_LIBRARY_PATH="/sl/usr/lib" --- indra/CMakeLists.txt | 1 + indra/cmake/Cwdebug.cmake | 1 + indra/cmake/LLAddBuildTest.cmake | 1 + indra/cmake/LLCommon.cmake | 1 + indra/cwdebug/CMakeLists.txt | 33 ++ indra/cwdebug/cwdebug.h | 9 + indra/cwdebug/debug.cc | 412 +++++++++++++++++++++ indra/cwdebug/debug.h | 256 +++++++++++++ indra/cwdebug/debug_ostream_operators.h | 1 + indra/cwdebug/sys.h | 9 + indra/llcommon/CMakeLists.txt | 7 + indra/llcommon/linden_common.h | 2 + indra/llcommon/llassettype.h | 5 + indra/llcommon/llerror.cpp | 10 + indra/llcommon/llindraconfigfile.h | 2 +- indra/llcommon/llthread.cpp | 4 + indra/llcrashlogger/llcrashlogger.cpp | 4 +- indra/llcrashlogger/llcrashlogger.h | 4 +- indra/llimage/tests/llimageworker_test.cpp | 1 + indra/llinventory/llsaleinfo.cpp | 2 +- indra/llmessage/llnetcanary.cpp | 2 +- indra/llmessage/llsocks5.cpp | 3 +- indra/llplugin/slplugin/slplugin.cpp | 7 + indra/newview/llappviewerlinux.cpp | 3 + 24 files changed, 772 insertions(+), 8 deletions(-) create mode 100644 indra/cmake/Cwdebug.cmake create mode 100644 indra/cwdebug/CMakeLists.txt create mode 100644 indra/cwdebug/cwdebug.h create mode 100644 indra/cwdebug/debug.cc create mode 100644 indra/cwdebug/debug.h create mode 100644 indra/cwdebug/debug_ostream_operators.h create mode 100644 indra/cwdebug/sys.h diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index e81510b2c..f88aa1fa0 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -44,6 +44,7 @@ endif(NOT STANDALONE) add_custom_target(prepare DEPENDS ${prepare_depends}) add_subdirectory(cmake) +add_subdirectory(${LIBS_OPEN_PREFIX}cwdebug) add_subdirectory(${LIBS_OPEN_PREFIX}llaudio) add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter) add_subdirectory(${LIBS_OPEN_PREFIX}llcommon) diff --git a/indra/cmake/Cwdebug.cmake b/indra/cmake/Cwdebug.cmake new file mode 100644 index 000000000..9568a625f --- /dev/null +++ b/indra/cmake/Cwdebug.cmake @@ -0,0 +1 @@ +set(CWDEBUG_LIBRARIES cwdebug) diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index f9b1ef96f..74f2e0cb1 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -3,6 +3,7 @@ INCLUDE(APR) INCLUDE(LLMath) INCLUDE(Tut) +INCLUDE(Cwdebug) MACRO(ADD_BUILD_TEST_NO_COMMON name parent) # MESSAGE("${CMAKE_CURRENT_SOURCE_DIR}/tests/${name}_test.cpp") diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 2862ba7f0..efb3d004c 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -6,6 +6,7 @@ include(EXPAT) include(ZLIB) set(LLCOMMON_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/cwdebug ${LIBS_OPEN_DIR}/llcommon ${APR_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} diff --git a/indra/cwdebug/CMakeLists.txt b/indra/cwdebug/CMakeLists.txt new file mode 100644 index 000000000..b291957e7 --- /dev/null +++ b/indra/cwdebug/CMakeLists.txt @@ -0,0 +1,33 @@ +# -*- cmake -*- + +project(cwdebug) + +include(00-Common) +include(LLCommon) +include(LLMath) +include(LLMessage) +include(LLVFS) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +set(cwdebug_SOURCE_FILES + debug.cc + ) + +set(cwdebug_HEADER_FILES + CMakeLists.txt + + cwdebug.h + sys.h + debug.h + debug_ostream_operators.h + ) + +set_source_files_properties(${cwdebug_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +add_definitions(-fPIC) + +list(APPEND cwdebug_SOURCE_FILES ${cwdebug_HEADER_FILES}) + +add_library (cwdebug ${cwdebug_SOURCE_FILES}) diff --git a/indra/cwdebug/cwdebug.h b/indra/cwdebug/cwdebug.h new file mode 100644 index 000000000..37415df3f --- /dev/null +++ b/indra/cwdebug/cwdebug.h @@ -0,0 +1,9 @@ +// We support compiling C++ source files that are not +// thread-safe, but in that case we assume that they +// will not be linked with libcwd_r. +#if !defined(_REENTRANT) || !defined(__linux__) +#undef CWDEBUG +#endif + +#include "sys.h" +#include "debug.h" diff --git a/indra/cwdebug/debug.cc b/indra/cwdebug/debug.cc new file mode 100644 index 000000000..3066c2845 --- /dev/null +++ b/indra/cwdebug/debug.cc @@ -0,0 +1,412 @@ +// slviewer -- Second Life Viewer Source Code +// +//! @file debug.cc +//! @brief This file contains the definitions of debug related objects and functions. +// +// Copyright (C) 2008, by +// +// Carlo Wood, Run on IRC +// RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt +// Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef USE_PCH +#include "sys.h" // Needed for platform-specific code +#endif + +#ifdef CWDEBUG + +#ifndef USE_PCH +#include // Needed for std::isprint +#include // Needed for setfill and setw +#include +#include +#include +#include +#include "debug.h" +#ifdef USE_LIBCW +#include // memleak_filter +#endif +#include +#include +#endif // USE_PCH + +#define BACKTRACE_AQUIRE_LOCK libcwd::_private_::mutex_tct::lock() +#define BACKTRACE_RELEASE_LOCK libcwd::_private_::mutex_tct::unlock() + +namespace debug { + +#if CWDEBUG_LOCATION +void BackTrace::dump_backtrace(void) const +{ + for (int frame = 0; frame < frames(); ++frame) + { + libcwd::location_ct loc((char*)buffer()[frame] + libcwd::builtin_return_address_offset); + Dout(dc::notice|continued_cf, '#' << std::left << std::setw(3) << frame << + std::left << std::setw(16) << buffer()[frame] << ' ' << loc << "\n in "); + char const* mangled_function_name = loc.mangled_function_name(); + if (mangled_function_name != libcwd::unknown_function_c) + { + std::string demangled_function_name; + libcwd::demangle_symbol(mangled_function_name, demangled_function_name); + Dout(dc::finish, demangled_function_name); + } + else + Dout(dc::finish, mangled_function_name); + } +} +#endif // CWDEBUG_LOCATION + +#if CWDEBUG_ALLOC && CWDEBUG_LOCATION +typedef std::map, libcwd::_private_::internal_allocator> backtrace_map_t; +backtrace_map_t* backtrace_map; +static int total_calls = 0; +static int number_of_stack_traces = 0; + +void my_backtrace_hook(void** buffer, int frames LIBCWD_COMMA_TSD_PARAM) +{ + ++total_calls; + + backtrace_map_t::iterator iter; + + set_alloc_checking_off(__libcwd_tsd); + { + BackTrace backtrace(buffer, frames); + std::pair res = backtrace_map->insert(backtrace_map_t::value_type(backtrace, 0)); + if (res.second) + ++number_of_stack_traces; + ++res.first->second; + iter = res.first; + } + set_alloc_checking_on(__libcwd_tsd); +#if 0 + // Dump the stack trace. + iter->first.dump_backtrace(); +#endif +} + +void start_recording_backtraces(void) +{ + BACKTRACE_AQUIRE_LOCK; + libcwd::backtrace_hook = my_backtrace_hook; + BACKTRACE_RELEASE_LOCK; + //Debug(dc::malloc.on()); + LIBCWD_TSD_DECLARATION; + set_alloc_checking_off(__libcwd_tsd); + backtrace_map = new backtrace_map_t; + set_alloc_checking_on(__libcwd_tsd); +} + +struct Compare { + bool operator()(backtrace_map_t::const_iterator const& iter1, backtrace_map_t::const_iterator const& iter2) + { + return iter1->second > iter2->second; + } +}; + +void stop_recording_backtraces(void) +{ + //Debug(dc::malloc.off()); + BACKTRACE_AQUIRE_LOCK; + libcwd::backtrace_hook = NULL; + + if (!backtrace_map) + { + Dout(dc::notice, "Not recording; call cwdebug_start() first."); + return; + } + + Dout(dc::notice, "Total number of calls: " << total_calls); + Dout(dc::notice, "Number of different stack traces: " << number_of_stack_traces); + Dout(dc::notice, "First 10 stack traces:"); + std::list entries; + for (backtrace_map_t::const_iterator iter = backtrace_map->begin(); iter != backtrace_map->end(); ++iter) + entries.push_back(iter); + entries.sort(Compare()); + int count = 0; + for (std::list::iterator iter = entries.begin(); iter != entries.end(); ++iter, ++count) + { + Dout(dc::notice, "Used: " << (*iter)->second); + // Dump the stack trace. + (*iter)->first.dump_backtrace(); + if (count == 10) + break; + } + + // Clear all data. + LIBCWD_TSD_DECLARATION; + set_alloc_checking_off(__libcwd_tsd); + delete backtrace_map; + set_alloc_checking_on(__libcwd_tsd); + backtrace_map = NULL; + total_calls = 0; + number_of_stack_traces = 0; + + BACKTRACE_RELEASE_LOCK; +} +#endif // CWDEBUG_ALLOC && CWDEBUG_LOCATION + + namespace channels { // namespace DEBUGCHANNELS + namespace dc { + +#ifndef DOXYGEN +#define DDCN(x) (x) +#endif + // Add new debug channels here. + + channel_ct viewer DDCN("VIEWER"); //!< This debug channel is used for the normal debugging out of the viewer. + channel_ct primbackup DDCN("PRIMBACKUP"); //!< This debug channel is used for output related to primbackup. + channel_ct gtk DDCN("GTK"); //!< This debug channel is used for output related to gtk. + channel_ct sdl DDCN("SDL"); //!< This debug channel is used for output related to sdl locking. + channel_ct backtrace DDCN("BACKTRACE"); //!< This debug channel is used for backtraces. + + } // namespace dc + } // namespace DEBUGCHANNELS + + // Anonymous namespace, this map and its initialization functions are private to this file + // for Thead-safeness reasons. + namespace { + + /*! @brief The type of rcfile_dc_states. + * @internal + */ + typedef std::map rcfile_dc_states_type; + + /*! @brief Map containing the default debug channel states used at the start of each new thread. + * @internal + * + * The first thread calls main, which calls debug::init which will initialize this + * map with all debug channel labels and whether or not they were turned on in the + * rcfile or not. + */ + rcfile_dc_states_type rcfile_dc_states; + + /*! @brief Set the default state of debug channel \a dc_label. + * @internal + * + * This function is called once for each debug channel. + */ + void set_state(char const* dc_label, bool is_on) + { + std::pair res = + rcfile_dc_states.insert(rcfile_dc_states_type::value_type(std::string(dc_label), is_on)); + if (!res.second) + Dout(dc::warning, "Calling set_state() more than once for the same label!"); + return; + } + + /*! @brief Save debug channel states. + * @internal + * + * One time initialization function of rcfile_dc_state. + * This must be called from debug::init after reading the rcfile. + */ + void save_dc_states(void) + { + // We may only call this function once: it reflects the states as stored + // in the rcfile and that won't change. Therefore it is not needed to + // lock `rcfile_dc_states', it is only written to by the first thread + // (once, via main -> init) when there are no other threads yet. + static bool second_time = false; + if (second_time) + { + Dout(dc::warning, "Calling save_dc_states() more than once!"); + return; + } + second_time = true; + ForAllDebugChannels( set_state(debugChannel.get_label(), debugChannel.is_on()) ); + } + + } // anonymous namespace + + /*! @brief Returns the the original state of a debug channel. + * @internal + * + * For a given \a dc_label, which must be the exact name (channel_ct::get_label) of an + * existing debug channel, this function returns \c true when the corresponding debug channel was + * on at the startup of the application, directly after reading the libcwd runtime + * configuration file (.libcwdrc). + * + * If the label/channel did not exist at the start of the application, it will return \c false + * (note that libcwd disallows adding debug channels to modules - so this would probably + * a bug). + */ + bool is_on_in_rcfile(char const* dc_label) + { + rcfile_dc_states_type::const_iterator iter = rcfile_dc_states.find(std::string(dc_label)); + if (iter == rcfile_dc_states.end()) + { + Dout(dc::warning, "is_on_in_rcfile(\"" << dc_label << "\"): \"" << dc_label << "\" is an unknown label!"); + return false; + } + return iter->second; + } + +#if LIBCWD_THREAD_SAFE + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + // I can cause I'm the maintainer of libcwd ;). + libcwd::_private_::pthread_lock_interface_ct cout_mutex(&mutex); + libcwd::_private_::lock_interface_base_ct* cout_mutex_ptr(&cout_mutex); +#endif + + /*! @brief Initialize debugging code from new threads. + * + * This function needs to be called at the start of each new thread, + * because a new thread starts in a completely reset state. + * + * The function turns on all debug channels that were turned on + * after reading the rcfile at the start of the application. + * Furthermore it initializes the debug ostream, its mutex and the + * margin of the default debug object (Dout). + */ + void init_thread(void) + { + // Turn on all debug channels that are turned on as per rcfile configuration. + ForAllDebugChannels( + if (!debugChannel.is_on() && is_on_in_rcfile(debugChannel.get_label())) + debugChannel.on(); + ); + + // Turn on debug output. + Debug( libcw_do.on() ); + static std::ofstream debug_file; + static bool debug_out_opened = false; + if (!debug_out_opened) + { + debug_out_opened = true; // Thread-safe, cause the main thread calls this first while it's still alone. + std::ostringstream os; + os << "debug.out." << getpid(); + debug_file.open(os.str().c_str()); + } + static debug::TeeStream debug_stream(std::cout, debug_file); +#if LIBCWD_THREAD_SAFE + Debug( libcw_do.set_ostream(&debug_stream, cout_mutex_ptr) ); +#else + Debug( libcw_do.set_ostream(&debug_stream) ); +#endif + + static bool first_thread = true; + if (!first_thread) // So far, the application has only one thread. So don't add a thread id. + { + // Set the thread id in the margin. + char margin[18]; + sprintf(margin, "0x%-14lx ", pthread_self()); + Debug( libcw_do.margin().assign(margin, 17) ); + } + first_thread = false; + } + + /*! @brief Initialize debugging code from main. + * + * This function initializes the debug code. + */ + void init(void) + { +#if CWDEBUG_ALLOC && defined(USE_LIBCW) + // Tell the memory leak detector which parts of the code are + // expected to leak so that we won't get an alarm for those. + { + std::vector > hide_list; + hide_list.push_back(std::pair("libdl.so.2", "_dlerror_run")); + hide_list.push_back(std::pair("libstdc++.so.6", "__cxa_get_globals")); + // The following is actually necessary because of a bug in glibc + // (see http://sources.redhat.com/bugzilla/show_bug.cgi?id=311). + hide_list.push_back(std::pair("libc.so.6", "dl_open_worker")); + memleak_filter().hide_functions_matching(hide_list); + } + { + std::vector hide_list; + // Also because of http://sources.redhat.com/bugzilla/show_bug.cgi?id=311 + hide_list.push_back(std::string("ld-linux.so.2")); + memleak_filter().hide_objectfiles_matching(hide_list); + } + memleak_filter().set_flags(libcwd::show_objectfile|libcwd::show_function); +#endif + + // The following call allocated the filebuf's of cin, cout, cerr, wcin, wcout and wcerr. + // Because this causes a memory leak being reported, make them invisible. + Debug(set_invisible_on()); + + // You want this, unless you mix streams output with C output. + // Read http://gcc.gnu.org/onlinedocs/libstdc++/27_io/howto.html#8 for an explanation. + //std::ios::sync_with_stdio(false); + + // Cancel previous call to set_invisible_on. + Debug(set_invisible_off()); + + // This will warn you when you are using header files that do not belong to the + // shared libcwd object that you linked with. + Debug( check_configuration() ); + + Debug( + libcw_do.on(); // Show which rcfile we are reading! + ForAllDebugChannels( + while (debugChannel.is_on()) + debugChannel.off() // Print as little as possible though. + ); + read_rcfile(); // Put 'silent = on' in the rcfile to suppress most of the output here. + libcw_do.off() + ); + save_dc_states(); + + init_thread(); + } + +#if CWDEBUG_LOCATION + /*! @brief Return call location. + * + * @param return_addr The return address of the call. + */ + std::string call_location(void const* return_addr) + { + libcwd::location_ct loc((char*)return_addr + libcwd::builtin_return_address_offset); + std::ostringstream convert; + convert << loc; + return convert.str(); + } + + std::vector __attribute__ ((visibility("default"))) backtraces; + pthread_mutex_t __attribute__ ((visibility("default"))) backtrace_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +} // namespace debug + +#if CWDEBUG_ALLOC +// These can be called from gdb. +void cwdebug_start() +{ + debug::start_recording_backtraces(); +} + +void cwdebug_stop() +{ + debug::stop_recording_backtraces(); +} +#endif + +#if CWDEBUG_LOCATION +void cwdebug_backtrace(int n) +{ + if (0 < n && n <= debug::backtraces.size()) + { + Dout(dc::backtrace, "Backtrace #" << n << ":"); + debug::backtraces[n - 1].dump_backtrace(); + } + else + std::cout << "No such backtrace nr. Max is " << debug::backtraces.size() << std::endl; +} +#endif + +#endif // CWDEBUG diff --git a/indra/cwdebug/debug.h b/indra/cwdebug/debug.h new file mode 100644 index 000000000..66408ad72 --- /dev/null +++ b/indra/cwdebug/debug.h @@ -0,0 +1,256 @@ +// slviewer -- Second Life Viewer Source Code +// +//! @file debug.h +//! @brief This file contains the declaration of debug related macros, objects and functions. +// +// Copyright (C) 2008, by +// +// Carlo Wood, Run on IRC +// RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt +// Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef DEBUG_H +#define DEBUG_H + +#ifndef CWDEBUG + +#ifndef DOXYGEN // No need to document this. See http://libcwd.sourceforge.net/ for more info. + +#include +#include // std::exit, EXIT_FAILURE + +#define AllocTag1(p) +#define AllocTag2(p, desc) +#define AllocTag_dynamic_description(p, x) +#define AllocTag(p, x) +#define Debug(x) +#define Dout(a, b) +#define DoutEntering(a, b) +#define DoutFatal(a, b) LibcwDoutFatal(::std, , a, b) +#define ForAllDebugChannels(STATEMENT) +#define ForAllDebugObjects(STATEMENT) +#define LibcwDebug(dc_namespace, x) +#define LibcwDout(a, b, c, d) +#define LibcwDoutFatal(a, b, c, d) do { ::std::cerr << d << ::std::endl; ::std::exit(EXIT_FAILURE); } while (1) +#define NEW(x) new x +#define CWDEBUG_ALLOC 0 +#define CWDEBUG_MAGIC 0 +#define CWDEBUG_LOCATION 0 +#define CWDEBUG_LIBBFD 0 +#define CWDEBUG_DEBUG 0 +#define CWDEBUG_DEBUGOUTPUT 0 +#define CWDEBUG_DEBUGM 0 +#define CWDEBUG_DEBUGT 0 +#define CWDEBUG_MARKER 0 + +#define BACKTRACE do { } while(0) + +#endif // !DOXYGEN + +#include +#ifdef DEBUG +#define ASSERT(x) assert(x) +#else +#define ASSERT(x) +#endif + +#else // CWDEBUG + +//! Assert \a x, if debugging is turned on. +#define ASSERT(x) LIBCWD_ASSERT(x) +#define builtin_return_address(addr) ((char*)__builtin_return_address(addr) + libcwd::builtin_return_address_offset) + +#ifndef DEBUGCHANNELS +//! @brief The namespace in which the \c dc namespace is declared. +// +// Libcwd demands that this macro is defined +// before is included and must be the name of the namespace containing +// the \c dc (Debug Channels) namespace. +// +// @sa debug::channels::dc + +#define DEBUGCHANNELS ::debug::channels +#endif +#include +#include +#if CWDEBUG_LOCATION +#include // Needed for 'backtrace'. +#endif + +#define CWD_API __attribute__ ((visibility("default"))) + +//! Debug specific code. +namespace debug { + +void CWD_API init(void); // Initialize debugging code, called once from main. +void CWD_API init_thread(void); // Initialize debugging code, called once for each thread. + +//! @brief Debug Channels (dc) namespace. +// +// @sa debug::channels::dc +namespace channels { // namespace DEBUGCHANNELS + +//! The namespace containing the actual debug channels. +namespace dc { +using namespace libcwd::channels::dc; +using libcwd::channel_ct; + +#ifndef DOXYGEN // Doxygen bug causes a warning here. +// Add the declaration of new debug channels here +// and add their definition in a custom debug.cc file. +extern CWD_API channel_ct viewer; // The normal logging output of the viewer (normally to stderr). +extern CWD_API channel_ct primbackup; +extern CWD_API channel_ct gtk; +extern CWD_API channel_ct sdl; +extern CWD_API channel_ct backtrace; + +#endif + +} // namespace dc +} // namespace DEBUGCHANNELS + +#if CWDEBUG_LOCATION +std::string call_location(void const* return_addr); +#endif + +//! @brief Interface for marking scopes of invisible memory allocations. +// +// Creation of the object does nothing, you have to explicitly call +// InvisibleAllocations::on. Destruction of the object automatically +// cancels any call to \c on of this object. This makes it exception- +// (stack unwinding) and recursive-safe. +struct InvisibleAllocations { + int M_on; //!< The number of times that InvisibleAllocations::on() was called. + //! Constructor. + InvisibleAllocations() : M_on(0) { } + //! Destructor. + ~InvisibleAllocations() { while (M_on > 0) off(); } + //! Set invisible allocations on. Can be called recursively. + void on(void) { libcwd::set_invisible_on(); ++M_on; } + //! Cancel one call to on(). + void off(void) { assert(M_on > 0); --M_on; libcwd::set_invisible_off(); } +}; + +//! @brief Interface for marking scopes with indented debug output. +// +// Creation of the object increments the debug indentation. Destruction +// of the object automatically decrements the indentation again. +struct Indent { + int M_indent; //!< The extra number of spaces that were added to the indentation. + //! Construct an Indent object. + Indent(int indent) : M_indent(indent) { if (M_indent > 0) libcwd::libcw_do.inc_indent(M_indent); } + //! Destructor. + ~Indent() { if (M_indent > 0) libcwd::libcw_do.dec_indent(M_indent); } +}; + +// A class streambuf that splits what is written to two streambufs. +class TeeBuf : public std::streambuf { + private: + std::streambuf* M_sb1; + std::streambuf* M_sb2; + + public: + TeeBuf(std::streambuf* sb1, std::streambuf* sb2) : M_sb1(sb1), M_sb2(sb2) { } + + protected: + virtual int sync(void) { M_sb2->pubsync(); return M_sb1->pubsync(); } + virtual std::streamsize xsputn(char_type const* p, std::streamsize n) { M_sb2->sputn(p, n); return M_sb1->sputn(p, n); } + virtual int_type overflow(int_type c = traits_type::eof()) { M_sb2->sputc(c); return M_sb1->sputc(c); } +}; + +// An ostream that passes what is written to it on to two other ostreams. +class TeeStream : public std::ostream { + private: + TeeBuf M_teebuf; + public: + TeeStream(std::ostream& os1, std::ostream& os2) : std::ostream(&M_teebuf), M_teebuf(os1.rdbuf(), os2.rdbuf()) { } +}; + +#if CWDEBUG_LOCATION +class BackTrace { + private: + boost::shared_array M_buffer; + int M_frames; + public: + BackTrace(void** buffer, int frames) : M_buffer(new void* [frames]), M_frames(frames) { std::memcpy(M_buffer.get(), buffer, sizeof(void*) * frames); } + + friend bool operator<(BackTrace const& bt1, BackTrace const& bt2) + { + if (bt1.M_frames != bt2.M_frames) + return bt1.M_frames < bt2.M_frames; + for (int frame = 0; frame < bt1.M_frames; ++frame) + if (bt1.M_buffer[frame] < bt2.M_buffer[frame]) + return true; + else if (bt1.M_buffer[frame] > bt2.M_buffer[frame]) + return true; + return false; + } + + void dump_backtrace(void) const; + + int frames(void) const { return M_frames; } + boost::shared_array const& buffer(void) const { return M_buffer; } +}; +extern std::vector backtraces; +extern pthread_mutex_t backtrace_mutex; +#define BACKTRACE do { \ + using namespace debug; \ + void* buffer[32]; \ + int frames = backtrace(buffer, 32); \ + size_t size; \ + { \ + pthread_mutex_lock(&backtrace_mutex); \ + backtraces.push_back(BackTrace(buffer, frames)); \ + size = backtraces.size(); \ + pthread_mutex_unlock(&backtrace_mutex); \ + } \ + Dout(dc::backtrace, "Stored backtrace #" << size); \ + } while(0) +#else +#define BACKTRACE do { } while(0) +#endif // CWDEBUG_LOCATION + +} // namespace debug + +//! Debugging macro. +// +// Print "Entering " << \a data to channel \a cntrl and increment +// debugging output indentation until the end of the current scope. +#define DoutEntering(cntrl, data) \ + int __slviewer_debug_indentation = 2; \ + { \ + LIBCWD_TSD_DECLARATION; \ + if (LIBCWD_DO_TSD_MEMBER_OFF(::libcwd::libcw_do) < 0) \ + { \ + ::libcwd::channel_set_bootstrap_st __libcwd_channel_set(LIBCWD_DO_TSD(::libcwd::libcw_do) LIBCWD_COMMA_TSD); \ + bool on; \ + { \ + using namespace LIBCWD_DEBUGCHANNELS; \ + on = (__libcwd_channel_set|cntrl).on; \ + } \ + if (on) \ + Dout(cntrl, "Entering " << data); \ + else \ + __slviewer_debug_indentation = 0; \ + } \ + } \ + debug::Indent __slviewer_debug_indent(__slviewer_debug_indentation); + +#endif // CWDEBUG + +#include "debug_ostream_operators.h" + +#endif // DEBUG_H diff --git a/indra/cwdebug/debug_ostream_operators.h b/indra/cwdebug/debug_ostream_operators.h new file mode 100644 index 000000000..4459e9fab --- /dev/null +++ b/indra/cwdebug/debug_ostream_operators.h @@ -0,0 +1 @@ +// Empty so far... diff --git a/indra/cwdebug/sys.h b/indra/cwdebug/sys.h new file mode 100644 index 000000000..c18df1701 --- /dev/null +++ b/indra/cwdebug/sys.h @@ -0,0 +1,9 @@ +// The following is the libcwd related mandatory part. +// It must be included before any system header file is included. +#ifdef CWDEBUG +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#endif + diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 7f352269b..f1325163c 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -2,6 +2,7 @@ project(llcommon) +include(Cwdebug) include(00-Common) include(LLCommon) include(Linking) @@ -214,5 +215,11 @@ target_link_libraries( ${EXPAT_LIBRARIES} ${ZLIB_LIBRARIES} ${WINDOWS_LIBRARIES} + ${CWDEBUG_LIBRARIES} ) +if (LINUX) + # When linking with llcommon later, we do not want to link with cwdebug.a again. + set_property(TARGET llcommon PROPERTY LINK_INTERFACE_LIBRARIES "-lapr-1 -laprutil-1 -lz") +endif (LINUX) + diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index 6e66e9916..d486359c7 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -33,6 +33,8 @@ #ifndef LL_LINDEN_COMMON_H #define LL_LINDEN_COMMON_H +#include "cwdebug.h" + #if defined(LL_WINDOWS) && defined(_DEBUG) # if _MSC_VER >= 1400 // Visual C++ 2005 or later # define _CRTDBG_MAP_ALLOC diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index a769e165c..9912ecba2 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -195,4 +195,9 @@ private: static const char* mAssetTypeHumanNames[]; }; +#ifdef CWDEBUG +#include +inline std::ostream& operator<<(std::ostream& os, LLAssetType::EType type) { return os << LLAssetType::getDesc(type); } +#endif + #endif // LL_LLASSETTYPE diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 4cdfe097d..a9c4380a1 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -162,7 +162,15 @@ namespace { break; } } +#ifdef CWDEBUG + // Include normal logging in libcwd's message processing. + // This takes care of prefixing with thread ID's, locking + // and allows us to (temporarily) turn off normal logging + // output. + Dout(dc::viewer, message); +#else fprintf(stderr, "%s\n", message.c_str()); +#endif #if LL_WINDOWS fflush(stderr); //Now using a buffer. flush is required. #endif @@ -1218,6 +1226,8 @@ namespace LLError #endif void crashAndLoop(const std::string& message) { + DoutFatal(dc::core, message); + // Now, we go kaboom! int* make_me_crash = NULL; diff --git a/indra/llcommon/llindraconfigfile.h b/indra/llcommon/llindraconfigfile.h index 661f79bd6..17eda906e 100644 --- a/indra/llcommon/llindraconfigfile.h +++ b/indra/llcommon/llindraconfigfile.h @@ -33,8 +33,8 @@ #ifndef LL_LLINDRACONFIGFILE_H #define LL_LLINDRACONFIGFILE_H -#include #include "linden_common.h" +#include #include "lllivefile.h" #include "llsd.h" diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 7ced30939..8bd341457 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -67,6 +67,10 @@ // void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap) { +#ifdef CWDEBUG + debug::init_thread(); +#endif + LLThread *threadp = (LLThread *)datap; // Set thread state to running diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 3dc41e897..f955ccdfd 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -29,13 +29,15 @@ * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ + +#include "linden_common.h" + #include #include #include #include #include "llcrashlogger.h" -#include "linden_common.h" #include "llstring.h" #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME #include "llerror.h" diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h index f8abe2059..72c1f3fb8 100644 --- a/indra/llcrashlogger/llcrashlogger.h +++ b/indra/llcrashlogger/llcrashlogger.h @@ -32,10 +32,10 @@ #ifndef LLCRASHLOGGER_H #define LLCRASHLOGGER_H -#include - #include "linden_common.h" +#include + #include "llapp.h" #include "llsd.h" #include "llcontrol.h" diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp index cc44696a4..2bca81434 100644 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -32,6 +32,7 @@ */ // Precompiled header: almost always required for newview cpp files +#include "../llcommon/linden_common.h" #include #include #include diff --git a/indra/llinventory/llsaleinfo.cpp b/indra/llinventory/llsaleinfo.cpp index b7afb28ad..e51e35e6e 100644 --- a/indra/llinventory/llsaleinfo.cpp +++ b/indra/llinventory/llsaleinfo.cpp @@ -30,8 +30,8 @@ * $/LicenseInfo$ */ -#include #include "linden_common.h" +#include #include "llsaleinfo.h" diff --git a/indra/llmessage/llnetcanary.cpp b/indra/llmessage/llnetcanary.cpp index a714c60f2..57ee6d3a6 100644 --- a/indra/llmessage/llnetcanary.cpp +++ b/indra/llmessage/llnetcanary.cpp @@ -1,6 +1,6 @@ // -#include "llnetcanary.h" #include "linden_common.h" +#include "llnetcanary.h" #include "llerror.h" #ifdef _MSC_VER #include diff --git a/indra/llmessage/llsocks5.cpp b/indra/llmessage/llsocks5.cpp index 7326e806b..d21412f86 100644 --- a/indra/llmessage/llsocks5.cpp +++ b/indra/llmessage/llsocks5.cpp @@ -30,13 +30,12 @@ * $/LicenseInfo$ */ -#include - #include "linden_common.h" #include "net.h" #include "llhost.h" #include "message.h" #include "llsocks5.h" +#include // Static class variable instances diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp index cca8ead8f..febcfea84 100644 --- a/indra/llplugin/slplugin/slplugin.cpp +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -183,6 +183,13 @@ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdL int main(int argc, char **argv) #endif { +#ifdef CWDEBUG + Debug( libcw_do.margin().assign("SLPlugin ", 9) ); + Debug(debug::init()); + // Uncomment this to automatically open a terminal with gdb. Requires SNOW-173. + //Debug(attach_gdb()); +#endif + // Set up llerror logging { LLError::initForApplication("."); diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index a19ad5658..4e4bbcb43 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -98,6 +98,9 @@ static void exceptionTerminateHandler() int main( int argc, char **argv ) { + Debug(debug::init()); + Debug(libcw_do.on()); + LLMemType mt1(LLMemType::MTYPE_STARTUP); #if LL_SOLARIS && defined(__sparc) From f6b57d956d2f395d87e83f8097f94d9566308ae7 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 5 May 2011 16:34:38 +0200 Subject: [PATCH 04/87] Added base class AIStateMachine. This is the skeleton needed to implement classes that can be reused and work together, which can perform asynchronous tasks (read: need to wait for certain events before they can continue). An example would be the task of waiting for a given inventory folder to be read. This could then be used to improve the builtin AO (automatically reading that folder when a notecard is dropped, and continuing when the whole folder is read). It's first use will be communication with a filepicker that runs in a plugin. --- doc/contributions.txt | 1 + indra/cwdebug/debug.cc | 1 + indra/cwdebug/debug.h | 1 + indra/llcommon/llfasttimer.h | 1 + indra/newview/CMakeLists.txt | 9 + indra/newview/app_settings/settings.xml | 11 + indra/newview/llcallbacklist.cpp | 40 +- indra/newview/llcallbacklist.h | 4 +- indra/newview/llfasttimerview.cpp | 1 + indra/newview/llviewercontrol.cpp | 7 + indra/newview/statemachine/aistatemachine.cpp | 343 +++++++++++++++++ indra/newview/statemachine/aistatemachine.h | 344 ++++++++++++++++++ 12 files changed, 757 insertions(+), 6 deletions(-) create mode 100644 indra/newview/statemachine/aistatemachine.cpp create mode 100644 indra/newview/statemachine/aistatemachine.h diff --git a/doc/contributions.txt b/doc/contributions.txt index f70336a94..ea148abd9 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -114,6 +114,7 @@ Aleric Inglewood IMP-670 IMP-701 IMP-734 + IMP-735 Alissa Sabre VWR-81 VWR-83 diff --git a/indra/cwdebug/debug.cc b/indra/cwdebug/debug.cc index 3066c2845..48392beae 100644 --- a/indra/cwdebug/debug.cc +++ b/indra/cwdebug/debug.cc @@ -171,6 +171,7 @@ void stop_recording_backtraces(void) channel_ct gtk DDCN("GTK"); //!< This debug channel is used for output related to gtk. channel_ct sdl DDCN("SDL"); //!< This debug channel is used for output related to sdl locking. channel_ct backtrace DDCN("BACKTRACE"); //!< This debug channel is used for backtraces. + channel_ct statemachine DDCN("STATEMACHINE"); //!< This debug channel is used class AIStateMachine. } // namespace dc } // namespace DEBUGCHANNELS diff --git a/indra/cwdebug/debug.h b/indra/cwdebug/debug.h index 66408ad72..e91eab92e 100644 --- a/indra/cwdebug/debug.h +++ b/indra/cwdebug/debug.h @@ -116,6 +116,7 @@ extern CWD_API channel_ct primbackup; extern CWD_API channel_ct gtk; extern CWD_API channel_ct sdl; extern CWD_API channel_ct backtrace; +extern CWD_API channel_ct statemachine; #endif diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 898ed496b..726274c23 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -177,6 +177,7 @@ public: FTM_REFRESH, FTM_SORT, FTM_PICK, + FTM_STATEMACHINE, // Temp FTM_TEMP1, diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 57a6163d7..628ee9ec4 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1005,6 +1005,15 @@ set(viewer_HEADER_FILES source_group("CMake Rules" FILES ViewerInstall.cmake) +set(statemachine_SOURCE_FILES + statemachine/aistatemachine.cpp + ) +set(statemachine_HEADER_FILES + statemachine/aistatemachine.h + ) +list(APPEND viewer_SOURCE_FILES ${statemachine_SOURCE_FILES}) +list(APPEND viewer_HEADER_FILES ${statemachine_HEADER_FILES}) + if (DARWIN) LIST(APPEND viewer_SOURCE_FILES llappviewermacosx.cpp) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b0a04a3bd..1406c4e96 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11382,6 +11382,17 @@ Value 0 + StateMachineMaxTime + + Comment + Maximum time per frame spent executing AIStateMachine objects, in miliseconds + Persist + 1 + Type + U32 + Value + 20 + StatsAutoRun Comment diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp index bba4d021c..6063995cf 100644 --- a/indra/newview/llcallbacklist.cpp +++ b/indra/newview/llcallbacklist.cpp @@ -47,7 +47,7 @@ LLCallbackList gIdleCallbacks; // Member functions // -LLCallbackList::LLCallbackList() +LLCallbackList::LLCallbackList() : mLoopingOverCallbackList(false) { // nothing } @@ -96,7 +96,15 @@ BOOL LLCallbackList::deleteFunction( callback_t func, void *data) callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); if (iter != mCallbackList.end()) { - mCallbackList.erase(iter); + if (mLoopingOverCallbackList) + { + iter->first = NULL; // Mark for removal later (when we return to LLCallbackList::callFunctions). + mNeedErase = true; + } + else + { + mCallbackList.erase(iter); + } return TRUE; } else @@ -108,16 +116,38 @@ BOOL LLCallbackList::deleteFunction( callback_t func, void *data) void LLCallbackList::deleteAllFunctions() { + llassert(!mLoopingOverCallbackList); // Only called from unit tests. mCallbackList.clear(); } void LLCallbackList::callFunctions() { - for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) + llassert(!mLoopingOverCallbackList); + mLoopingOverCallbackList = true; + mNeedErase = false; + for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ++iter) { - callback_list_t::iterator curiter = iter++; - curiter->first(curiter->second); + if (iter->first) // Not pending removal? + { + iter->first(iter->second); // This can theorectically set any iter->first to NULL, which means the entry should be erased. + } + } + mLoopingOverCallbackList = false; + if (mNeedErase) + { + callback_list_t::iterator iter = mCallbackList.begin(); + while (iter != mCallbackList.end()) + { + if (!iter->first) + { + iter = mCallbackList.erase(iter); + } + else + { + ++iter; + } + } } } diff --git a/indra/newview/llcallbacklist.h b/indra/newview/llcallbacklist.h index be0fe9f5c..240346478 100644 --- a/indra/newview/llcallbacklist.h +++ b/indra/newview/llcallbacklist.h @@ -53,9 +53,11 @@ public: protected: // Use a list so that the callbacks are ordered in case that matters - typedef std::pair callback_pair_t; + typedef std::pair callback_pair_t; // callback_t is a (function) pointer. If it is NULL it means that the entry should be considered deleted. typedef std::list callback_list_t; callback_list_t mCallbackList; + bool mLoopingOverCallbackList; // True while looping over mCallbackList and calling the callback_t functions (see callFunctions). + bool mNeedErase; // True when deleteFunction was called while mLoopingOverCallbackList was true. }; extern LLCallbackList gIdleCallbacks; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 27661567e..418ea1bf0 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -83,6 +83,7 @@ static struct ft_display_info ft_display_table[] = { LLFastTimer::FTM_KEYHANDLER, " Keyboard", &LLColor4::grey1, 0 }, { LLFastTimer::FTM_SLEEP, " Sleep", &LLColor4::grey2, 0 }, { LLFastTimer::FTM_IDLE, " Idle", &blue0, 0 }, + { LLFastTimer::FTM_STATEMACHINE, " State Machines", &LLColor4::yellow1, 0 }, { LLFastTimer::FTM_PUMP, " Pump", &LLColor4::magenta2, 1 }, { LLFastTimer::FTM_CURL, " Curl", &LLColor4::magenta3, 0 }, { LLFastTimer::FTM_PUMPIO, " PumpIO", &LLColor4::magenta1, 0 }, diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 23c9535fa..de65b97af 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -75,6 +75,7 @@ #include "llnetmap.h" #include "llrender.h" #include "llfloaterchat.h" +#include "statemachine/aistatemachine.h" #include "aithreadsafe.h" #include "llviewerobjectlist.h" #include "lldrawpoolbump.h" @@ -119,6 +120,11 @@ static bool handleTerrainDetailChanged(const LLSD& newvalue) return true; } +bool handleStateMachineMaxTimeChanged(const LLSD& newvalue) +{ + AIStateMachine::updateSettings(); + return true; +} static bool handleSetShaderChanged(const LLSD& newvalue) { @@ -707,6 +713,7 @@ void settings_setup_listeners() gSavedSettings.getControl("AudioLevelMic")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); gSavedSettings.getControl("TranslateChat")->getSignal()->connect(boost::bind(&handleTranslateChatPrefsChanged, _1)); + gSavedSettings.getControl("StateMachineMaxTime")->getSignal()->connect(boost::bind(&handleStateMachineMaxTimeChanged, _1)); gSavedSettings.getControl("CloudsEnabled")->getSignal()->connect(boost::bind(&handleCloudSettingsChanged, _1)); gSavedSettings.getControl("SkyUseClassicClouds")->getSignal()->connect(boost::bind(&handleCloudSettingsChanged, _1)); diff --git a/indra/newview/statemachine/aistatemachine.cpp b/indra/newview/statemachine/aistatemachine.cpp new file mode 100644 index 000000000..ca1b5c61e --- /dev/null +++ b/indra/newview/statemachine/aistatemachine.cpp @@ -0,0 +1,343 @@ +/** + * @file aistatemachine.cpp + * @brief Implementation of AIStateMachine + * + * Copyright (c) 2010, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * 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. + * + * CHANGELOG + * and additional copyright holders. + * + * 01/03/2010 + * Initial version, written by Aleric Inglewood @ SL + */ + +#include "../llviewerprecompiledheaders.h" + +#include + +#include "../llcallbacklist.h" +#include "../llviewercontrol.h" + +#include "llfasttimer.h" +#include "aithreadsafe.h" +#include "aistatemachine.h" + +// Local variables. +namespace { + struct QueueElementComp; + + class QueueElement { + private: + AIStateMachine* mStateMachine; + U64 mRuntime; + + public: + QueueElement(AIStateMachine* statemachine) : mStateMachine(statemachine), mRuntime(0) { } + friend bool operator==(QueueElement const& e1, QueueElement const& e2) { return e1.mStateMachine == e2.mStateMachine; } + friend struct QueueElementComp; + + AIStateMachine& statemachine(void) const { return *mStateMachine; } + void add(U64 count) { mRuntime += count; } + }; + + struct QueueElementComp { + bool operator()(QueueElement const& e1, QueueElement const& e2) const { return e1.mRuntime < e2.mRuntime; } + }; + + typedef std::vector active_statemachines_type; + static active_statemachines_type active_statemachines; + typedef std::vector continued_statemachines_type; + struct cscm_type + { + continued_statemachines_type continued_statemachines; + bool calling_mainloop; + }; + static AITHREADSAFE(cscm_type, continued_statemachines_and_calling_mainloop, ); +} + +// static +AITHREADSAFESIMPLE(U64, AIStateMachine::sMaxCount, ); + +void AIStateMachine::updateSettings(void) +{ + Dout(dc::statemachine, "Initializing AIStateMachine::sMaxCount"); + *AIAccess(sMaxCount) = LLFastTimer::countsPerSecond() * gSavedSettings.getU32("StateMachineMaxTime") / 1000; +} + +//---------------------------------------------------------------------------- +// +// Public methods +// + +void AIStateMachine::run(AIStateMachine* parent, state_type new_parent_state, bool abort_parent) +{ + DoutEntering(dc::statemachine, "AIStateMachine::run(" << (void*)parent << ", " << (parent ? parent->state_str(new_parent_state) : "NA") << ", " << abort_parent << ") [" << (void*)this << "]"); + // Must be the first time we're being run. + llassert(!mParent); + llassert(!mCallback); + // Can only be run when in this state. + llassert(mState == bs_initialize); + // If a parent is provided, it must be running. + llassert(!parent || parent->mState == bs_run); + + mParent = parent; + mNewParentState = new_parent_state; + mAbortParent = abort_parent; + + cont(); +} + +void AIStateMachine::run(callback_type::signal_type::slot_type const& slot) +{ + DoutEntering(dc::statemachine, "AIStateMachine::run() [" << (void*)this << "]"); + // Must be the first time we're being run. + llassert(!mParent); + llassert(!mCallback); + // Can only be run when in this state. + llassert(mState == bs_initialize); + + mCallback = new callback_type(slot); + + cont(); +} + +void AIStateMachine::idle(void) +{ + DoutEntering(dc::statemachine, "AIStateMachine::idle() [" << (void*)this << "]"); + llassert(!mIdle); + mIdle = true; + mSleep = 0; +} + +void AIStateMachine::cont(void) +{ + DoutEntering(dc::statemachine, "AIStateMachine::cont() [" << (void*)this << "]"); + llassert(mIdle); + mIdle = false; + AIWriteAccess cscm_w(continued_statemachines_and_calling_mainloop); + cscm_w->continued_statemachines.push_back(this); + if (!cscm_w->calling_mainloop) + { + Dout(dc::statemachine, "Adding AIStateMachine::mainloop to gIdleCallbacks"); + cscm_w->calling_mainloop = true; + gIdleCallbacks.addFunction(&AIStateMachine::mainloop); + } +} + +void AIStateMachine::set_state(state_type state) +{ + DoutEntering(dc::statemachine, "AIStateMachine::set_state(" << state_str(state) << ") [" << (void*)this << "]"); + llassert(mState == bs_run); + if (mRunState != state) + { + mRunState = state; + Dout(dc::statemachine, "mRunState set to " << state_str(mRunState)); + } + if (mIdle) + cont(); +} + +void AIStateMachine::abort(void) +{ + DoutEntering(dc::statemachine, "AIStateMachine::abort() [" << (void*)this << "]"); + llassert(mState == bs_run); + mState = bs_abort; + abort_impl(); + mAborted = true; + finish(); +} + +void AIStateMachine::finish(void) +{ + DoutEntering(dc::statemachine, "AIStateMachine::finish() [" << (void*)this << "]"); + llassert(mState == bs_run || mState == bs_abort); + mState = bs_finish; + finish_impl(); + if (mParent) + { + // It is possible that the parent is not running when the parent is in fact aborting and called + // abort on this object from it's abort_impl function. It that case we don't want to recursively + // call abort again (or change it's state). + if (mParent->running()) + { + if (mAborted && mAbortParent) + { + mParent->abort(); + } + else + { + mParent->set_state(mNewParentState); + } + } + mParent = NULL; + } + // Set this already to bs_initialize now, so that (bool)*this evaluates to true. + mState = bs_initialize; + // It is possible that mIdle is false when abort or finish was called from + // outside multiplex_impl. However, that only may be done by the main thread. + llassert(!mIdle || is_main_thread()); + if (!mIdle) + idle(); + if (mCallback) + { + mCallback->callback(!mAborted); // This can/may call deleteMe(), in which case the whole AIStateMachine will be deleted from the mainloop. + delete mCallback; + mCallback = NULL; + } +} + +void AIStateMachine::deleteMe(void) +{ + llassert(mIdle && mState == bs_initialize); + mState = bs_deleted; +} + +// Return stringified 'state'. +char const* AIStateMachine::state_str(state_type state) +{ + if (state >= min_state && state < max_state) + { + switch (state) + { + AI_CASE_RETURN(bs_initialize); + AI_CASE_RETURN(bs_run); + AI_CASE_RETURN(bs_abort); + AI_CASE_RETURN(bs_finish); + AI_CASE_RETURN(bs_deleted); + } + } + return state_str_impl(state); +} + +//---------------------------------------------------------------------------- +// +// Private methods +// + +void AIStateMachine::multiplex(U64 current_time) +{ + // Return immediately when this state machine is sleeping. + // A negative value of mSleep means we're counting frames, + // a positive value means we're waiting till a certain + // amount of time has passed. + if (mSleep != 0) + { + if (mSleep < 0) + { + if (++mSleep) + return; + } + else + { + if (current_time < mSleep) + return; + mSleep = 0; + } + } + + DoutEntering(dc::statemachine, "AIStateMachine::multiplex() [" << (void*)this << "] [with state: " << state_str(mState == bs_run ? mRunState : mState) << "]"); + llassert(mState == bs_initialize || mState == bs_run); + + // Real state machine starts here. + if (mState == bs_initialize) + { + mAborted = false; + mState = bs_run; + initialize_impl(); + if (mAborted || mState != bs_run) + return; + } + multiplex_impl(); +} + +// static +void AIStateMachine::mainloop(void*) +{ + LLFastTimer t(LLFastTimer::FTM_STATEMACHINE); + // Add continued state machines. + { + AIReadAccess cscm_r(continued_statemachines_and_calling_mainloop); + bool nonempty = false; + for (continued_statemachines_type::const_iterator iter = cscm_r->continued_statemachines.begin(); iter != cscm_r->continued_statemachines.end(); ++iter) + { + nonempty = true; + active_statemachines.push_back(QueueElement(*iter)); + Dout(dc::statemachine, "Adding " << (void*)*iter << " to active_statemachines"); + } + if (nonempty) + AIWriteAccess(cscm_r)->continued_statemachines.clear(); + } + llassert(!active_statemachines.empty()); + // Run one or more state machines. + U64 total_clocks = 0; + U64 max_count = *AIAccess(sMaxCount); + for (active_statemachines_type::iterator iter = active_statemachines.begin(); iter != active_statemachines.end(); ++iter) + { + AIStateMachine& statemachine(iter->statemachine()); + if (!statemachine.mIdle) + { + U64 start = get_cpu_clock_count(); + iter->statemachine().multiplex(start); + U64 delta = get_cpu_clock_count() - start; + iter->add(delta); + total_clocks += delta; + if (total_clocks >= max_count) + { +#ifndef LL_RELEASE_FOR_DOWNLOAD + llwarns << "AIStateMachine::mainloop did run for " << (total_clocks * 1000 / LLFastTimer::countsPerSecond()) << " ms." << llendl; +#endif + std::sort(active_statemachines.begin(), active_statemachines.end(), QueueElementComp()); + break; + } + } + } + // Remove idle state machines from the loop. + active_statemachines_type::iterator iter = active_statemachines.begin(); + while (iter != active_statemachines.end()) + { + AIStateMachine& statemachine(iter->statemachine()); + if (statemachine.mIdle) + { + Dout(dc::statemachine, "Erasing " << (void*)&statemachine << " from active_statemachines"); + iter = active_statemachines.erase(iter); + if (statemachine.mState == bs_deleted) + { + Dout(dc::statemachine, "Deleting " << (void*)&statemachine); + delete &statemachine; + } + } + else + { + llassert(statemachine.mState == bs_run); + ++iter; + } + } + if (active_statemachines.empty()) + { + // If this was the last state machine, remove mainloop from the IdleCallbacks. + AIReadAccess cscm_r(continued_statemachines_and_calling_mainloop); + if (cscm_r->continued_statemachines.empty() && cscm_r->calling_mainloop) + { + Dout(dc::statemachine, "Removing AIStateMachine::mainloop from gIdleCallbacks"); + AIWriteAccess(cscm_r)->calling_mainloop = false; + gIdleCallbacks.deleteFunction(&AIStateMachine::mainloop); + } + } +} diff --git a/indra/newview/statemachine/aistatemachine.h b/indra/newview/statemachine/aistatemachine.h new file mode 100644 index 000000000..4b25b957d --- /dev/null +++ b/indra/newview/statemachine/aistatemachine.h @@ -0,0 +1,344 @@ +/** + * @file aistatemachine.h + * @brief State machine base class + * + * Copyright (c) 2010, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * 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. + * + * CHANGELOG + * and additional copyright holders. + * + * 01/03/2010 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AISTATEMACHINE_H +#define AISTATEMACHINE_H + +#include "aithreadsafe.h" +#include "llfasttimer.h" + +//! +// A AIStateMachine is a base class that allows derived classes to +// go through asynchronous states, while the code still appears to +// be more or less sequential. +// +// These state machine objects can be reused to build more complex +// objects. +// +// It is important to note that each state has a duality: the object +// can have a state that will cause a corresponding function to be +// called; and often that function will end with changing the state +// again, to signal that it was handled. It is easy to confuse the +// function of a state with the state at the end of the function. +// For example, the state "initialize" could cause the member +// function 'init()' to be called, and at the end one would be +// inclined to set the state to "initialized". However, this is the +// wrong approach: the correct use of state names does reflect the +// functions that will be called, never the function that just was +// called. +// +// Each (derived) class goes through a series of states as follows: +// +// Creation +// | +// v +// (idle) <----. Idle until run() is called. +// | | +// Initialize | Calls initialize_impl(). +// | | +// | (idle) | Idle until cont() or set_state() is called. +// | | ^ | +// v v | | +// .-------. | | +// | Run |_, | Call multiplex_impl() until idle(), abort() or finish() is called. +// '-------' | +// | | | +// v | | +// Abort | | Calls abort_impl(). +// | | | +// v v | +// Finish | Calls finish_impl(). +// | | +// `---------' +// +// Each state causes corresponding code to be called. +// Finish cleans up whatever is done by Initialize. +// Abort should clean up additional things done by Run. +// +// The Run state is entered by calling run(). +// +// While the base class is in the Run state, it is the derived class +// that goes through different states. The state variable of the derived +// class is only valid while the base class is in the state Run. +// +// A derived class can exit the Run state by calling one of two methods: +// abort() in case of failure, or finish() in case of success. +// Respectively these set the state to Abort and Finish. +// +// State machines are run from the "idle" part of the viewer main loop. +// Often a state machine has nothing to do however. In that case it can +// call the method idle(). This will stop the state machine until +// external code changes it's state (by calling set_state()), or calls +// cont() to continue with the last state. +// +// The methods of the derived class call set_state() to change their +// own state within the bs_run state, or by calling either abort() +// or finish(). +// +// Restarting a finished state machine can also be done by calling run(), +// which will cause a re-initialize. +// +// Derived classes should implement the following constants: +// +// static state_type const min_state = first_state; +// static state_type const max_state = last_state + 1; +// +// Where first_state should be equal to BaseClass::max_state. +// These should represent the minimum and (one past) the maximum +// values of mRunState. +// +// virtual void initialize_impl(void) +// +// Initializes the derived class. +// +// virtual void multiplex_impl(void); +// +// This method should handle mRunState in a switch. +// For example: +// +// switch(mRunState) +// { +// case foo: +// handle_foo(); +// break; +// case wait_state: +// if (still_waiting()) +// { +// idle(); +// break; +// } +// set_state(working); +// /*fall-through*/ +// case working: +// do_work(); +// if (failure()) +// abort(); +// break; +// case etc: +// etc(); +// finish(); +// break; +// } +// +// virtual void abort_impl(void); +// +// A call to this method should bring the object to a state +// where finish_impl() can be called. +// +// virtual void finish_impl(void); +// +// Should cleanup whatever init_impl() did, or any of the +// states of the object where multiplex_impl() calls finish(). +// +// virtual char const* state_str_impl(state_type run_state); +// +// Should return a stringified value of run_state. +// +class AIStateMachine { + //! The type of mState + enum base_state_type { + bs_initialize, + bs_run, + bs_abort, + bs_finish, + bs_deleted + }; + + public: + typedef U32 state_type; //!< The type of mRunState + + //! Integral value equal to the state with the lowest value. + static state_type const min_state = bs_initialize; + //! Integral value one more than the state with the highest value. + static state_type const max_state = bs_deleted + 1; + + private: + base_state_type mState; //!< State of the base class. + bool mIdle; //!< True if this state machine is not running. + bool mAborted; //!< True after calling abort() and before calling run(). + U64 mSleep; //!< Non-zero while the state machine is sleeping. + + // Callback facilities. + // From within an other state machine: + AIStateMachine* mParent; //!< The parent object that started this state machine, or NULL if there isn't any. + state_type mNewParentState; //!< The state at which the parent should continue upon a successful finish. + bool mAbortParent; //!< If true, abort parent on abort(). Otherwise continue as normal. + // From outside a state machine: + struct callback_type { + typedef boost::signal signal_type; + callback_type(signal_type::slot_type const& slot) { connection = signal.connect(slot); } + ~callback_type() { connection.disconnect(); } + void callback(bool success) const { signal(success); } + private: + boost::signals::connection connection; + signal_type signal; + }; + callback_type* mCallback; //!< Pointer to signal/connection, or NULL when not connected. + + static AIThreadSafeSimple sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame. + + protected: + //! State of the derived class. Only valid if mState == bs_run. Call set_state to change. + state_type mRunState; + + public: + //! Create a non-running state machine. + AIStateMachine(void) : mState(bs_initialize), mIdle(true), mAborted(true), mSleep(0), mParent(NULL), mCallback(NULL) { updateSettings(); } + + protected: + //! The user should call 'deleteMe()', not delete a AIStateMachine (derived) directly. + virtual ~AIStateMachine() { llassert(mState == bs_deleted); } + + public: + //! Halt the state machine until cont() is called. + void idle(void); + + //! Temporarily halt the state machine. + void yield_frame(unsigned int frames) { mSleep = -frames; } + + //! Temporarily halt the state machine. + void yield_ms(unsigned int ms) { mSleep = get_cpu_clock_count() + LLFastTimer::countsPerSecond() * ms / 1000; } + + //! Continue running after calling idle. + void cont(void); + + //--------------------------------------- + // Changing the state. + + //! Change state to bs_run. May only be called after creation or after returning from finish(). + // If parent is non-NULL, change the parent state machine's state to new_parent_state + // upon finish, or in the case of an abort and when abort_parent is true, call parent->abort() instead. + void run(AIStateMachine* parent, state_type new_parent_state, bool abort_parent = true); + + //! Change state to 'bs_run'. May only be called after creation or after returning from finish(). + // Does not cause a callback. + void run(void) { run(NULL, 0, false); } + + //! The same as above, but pass the result of a boost::bind with _1. + // + // Here _1, if present, will be replaced with a bool indicating success. + // + // For example: + // + // + // struct Foo { void callback(AIStateMachineDerived* ptr, bool success); }; + // ... + // AIStateMachineDerived* magic = new AIStateMachineDerived; // Deleted by callback + // // Call foo_ptr->callback(magic, _1) on finish. + // state_machine->run(boost::bind(&Foo::callback, foo_ptr, magic, _1)); + // + // + // or + // + // + // struct Foo { void callback(bool success, AIStateMachineDerived const& magic); }; + // ... + // AIStateMachineDerived magic; + // // Call foo_ptr->callback(_1, magic) on finish. + // magic.run(boost::bind(&Foo::callback, foo_ptr, _1, magic)); + // + // + // or + // + // + // static void callback(void* userdata); + // ... + // AIStateMachineDerived magic; + // // Call callback(userdata) on finish. + // magic.run(boost::bind(&callback, userdata)); + // + void run(callback_type::signal_type::slot_type const& slot); + + //! Change state to 'bs_abort'. May only be called while in the bs_run state. + void abort(void); + + //! Change state to 'bs_finish'. May only be called while in the bs_run state. + void finish(void); + + //! Refine state while in the bs_run state. May only be called while in the bs_run state. + void set_state(state_type run_state); + + //! Change state to 'bs_deleted'. May only be called while in the bs_finish state. + void deleteMe(void); + + //--------------------------------------- + // Other. + + //! Called whenever the StateMachineMaxTime setting is changed. + static void updateSettings(void); + + //--------------------------------------- + // Accessors. + + //! Return true if state machine was aborted (can be used in finish_impl). + bool aborted(void) const { return mAborted; } + + //! Return true if the derived class is running (also when we are idle). + bool running(void) const { return mState == bs_run; } + + //! Return true if the derived class is running but idle. + bool waiting(void) const { return mState == bs_run && mIdle; } + + // Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool. + typedef state_type AIStateMachine::* const bool_type; + //! Return true if state machine successfully finished. + operator bool_type() const { return (mState == bs_initialize && !mAborted) ? &AIStateMachine::mRunState : 0; } + + //! Return a stringified state, for debugging purposes. + char const* state_str(state_type state); + + private: + static void mainloop(void*); + void multiplex(U64 current_time); + + protected: + //--------------------------------------- + // Derived class implementations. + + // Handle initializing the object. + virtual void initialize_impl(void) = 0; + + // Handle mRunState. + virtual void multiplex_impl(void) = 0; + + // Handle aborting from current bs_run state. + virtual void abort_impl(void) = 0; + + // Handle cleaning up from initialization (or post abort) state. + virtual void finish_impl(void) = 0; + + // Implemenation of state_str for run states. + virtual char const* state_str_impl(state_type run_state) const = 0; +}; + +// This case be used in state_str_impl. +#define AI_CASE_RETURN(x) do { case x: return #x; } while(0) + +#endif From e89d6d9d667a3fb7eb5d56cdfa1e00ed0d134098 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 6 May 2011 14:39:16 +0200 Subject: [PATCH 05/87] Split plugin classes and derive AIFilePicker from BasicPluginBase (part 1). This commit contains all changes, except those in indra/media_plugins (which was renamed to indra/plugins) and indra/llplugin. However, it does contain the (new) file indra/plugins/filepicker/basic_plugin_filepicker.cpp --- doc/contributions.txt | 1 + indra/CMakeLists.txt | 4 +- indra/cmake/BasicPluginBase.cmake | 8 + indra/cmake/MediaPluginBase.cmake | 8 +- indra/newview/CMakeLists.txt | 7 + indra/newview/lldirpicker.cpp | 28 +- indra/newview/lldirpicker.h | 16 +- indra/newview/llfilepicker.cpp | 64 ++- indra/newview/llfilepicker.h | 30 +- indra/newview/llfloatersnapshot.cpp | 12 +- indra/newview/llmediactrl.h | 2 +- indra/newview/llviewermedia.cpp | 338 +++++++--------- indra/newview/llviewermedia.h | 33 +- indra/newview/llviewermediaeventemitter.cpp | 85 ++++ indra/newview/llviewermediaeventemitter.h | 56 +++ indra/newview/llviewermediaobserver.cpp | 47 +++ indra/newview/llviewermenufile.cpp | 2 - indra/newview/llviewerparcelmedia.h | 2 +- indra/newview/llviewerpluginmanager.cpp | 56 +++ indra/newview/llviewerpluginmanager.h | 115 ++++++ indra/newview/llviewerwindow.cpp | 55 ++- indra/newview/llviewerwindow.h | 9 +- indra/newview/statemachine/aifilepicker.cpp | 369 ++++++++++++++++++ indra/newview/statemachine/aifilepicker.h | 160 ++++++++ indra/newview/viewer_manifest.py | 19 +- .../filepicker/basic_plugin_filepicker.cpp | 243 ++++++++++++ 26 files changed, 1432 insertions(+), 337 deletions(-) create mode 100644 indra/cmake/BasicPluginBase.cmake create mode 100644 indra/newview/llviewermediaeventemitter.cpp create mode 100644 indra/newview/llviewermediaeventemitter.h create mode 100644 indra/newview/llviewermediaobserver.cpp create mode 100644 indra/newview/llviewerpluginmanager.cpp create mode 100644 indra/newview/llviewerpluginmanager.h create mode 100644 indra/newview/statemachine/aifilepicker.cpp create mode 100644 indra/newview/statemachine/aifilepicker.h create mode 100644 indra/plugins/filepicker/basic_plugin_filepicker.cpp diff --git a/doc/contributions.txt b/doc/contributions.txt index ea148abd9..53ab212d8 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -113,6 +113,7 @@ Aleric Inglewood IMP-664 IMP-670 IMP-701 + IMP-702 IMP-734 IMP-735 Alissa Sabre diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index f88aa1fa0..c23a03e6a 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -76,8 +76,8 @@ if (VIEWER) add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) add_subdirectory(${LIBS_OPEN_PREFIX}llui) - # viewer media plugins - add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins) + # viewer plugins directory + add_subdirectory(${LIBS_OPEN_PREFIX}plugins) # llplugin testbed code (is this the right way to include it?) #if (NOT LINUX) diff --git a/indra/cmake/BasicPluginBase.cmake b/indra/cmake/BasicPluginBase.cmake new file mode 100644 index 000000000..a4f339272 --- /dev/null +++ b/indra/cmake/BasicPluginBase.cmake @@ -0,0 +1,8 @@ +# -*- cmake -*- + + +set(BASIC_PLUGIN_BASE_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/plugins/base_basic/ + ) + +set(BASIC_PLUGIN_BASE_LIBRARIES basic_plugin_base) diff --git a/indra/cmake/MediaPluginBase.cmake b/indra/cmake/MediaPluginBase.cmake index 2be035b64..7e2d30dfa 100644 --- a/indra/cmake/MediaPluginBase.cmake +++ b/indra/cmake/MediaPluginBase.cmake @@ -1,8 +1,6 @@ # -*- cmake -*- +include(BasicPluginBase) -set(MEDIA_PLUGIN_BASE_INCLUDE_DIRS - ${LIBS_OPEN_DIR}/media_plugins/base/ - ) - -set(MEDIA_PLUGIN_BASE_LIBRARIES media_plugin_base) +set(MEDIA_PLUGIN_BASE_INCLUDE_DIRS ${LIBS_OPEN_DIR}/plugins/base_media ${BASIC_PLUGIN_BASE_INCLUDE_DIRS}) +set(MEDIA_PLUGIN_BASE_LIBRARIES media_plugin_base ${BASIC_PLUGIN_BASE_LIBRARIES}) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 628ee9ec4..3599a1d3d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -442,6 +442,8 @@ set(viewer_SOURCE_FILES llviewerkeyboard.cpp llviewerlayer.cpp llviewermedia.cpp + llviewermediaeventemitter.cpp + llviewermediaobserver.cpp llviewermediafocus.cpp llviewermedia_streamingaudio.cpp llviewermenu.cpp @@ -456,6 +458,7 @@ set(viewer_SOURCE_FILES llviewerparceloverlay.cpp llviewerpartsim.cpp llviewerpartsource.cpp + llviewerpluginmanager.cpp llviewerregion.cpp llviewershadermgr.cpp llviewerstats.cpp @@ -918,6 +921,7 @@ set(viewer_HEADER_FILES llviewerkeyboard.h llviewerlayer.h llviewermedia.h + llviewermediaeventemitter.h llviewermediaobserver.h llviewermediafocus.h llviewermenu.h @@ -932,6 +936,7 @@ set(viewer_HEADER_FILES llviewerparceloverlay.h llviewerpartsim.h llviewerpartsource.h + llviewerpluginmanager.h llviewerprecompiledheaders.h llviewerregion.h llviewershadermgr.h @@ -1007,9 +1012,11 @@ source_group("CMake Rules" FILES ViewerInstall.cmake) set(statemachine_SOURCE_FILES statemachine/aistatemachine.cpp + statemachine/aifilepicker.cpp ) set(statemachine_HEADER_FILES statemachine/aistatemachine.h + statemachine/aifilepicker.h ) list(APPEND viewer_SOURCE_FILES ${statemachine_SOURCE_FILES}) list(APPEND viewer_HEADER_FILES ${statemachine_HEADER_FILES}) diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 8b0ed39eb..3840b52bd 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -269,48 +269,36 @@ void LLDirPicker::reset() LLDirPicker::LLDirPicker() { - mFilePicker = new LLFilePicker(); reset(); } LLDirPicker::~LLDirPicker() { - delete mFilePicker; } void LLDirPicker::reset() { - if (mFilePicker) - mFilePicker->reset(); + LLFilePickerBase::reset(); } BOOL LLDirPicker::getDir(std::string* filename) { reset(); - if (mFilePicker) + GtkWindow* picker = buildFilePicker(false, true, "dirpicker"); + if (picker) { - GtkWindow* picker = mFilePicker->buildFilePicker(false, true, - "dirpicker"); - - if (picker) - { - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("choose_the_directory").c_str()); - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - return (!mFilePicker->getFirstFile().empty()); - } + gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("choose_the_directory").c_str()); + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + return (!getFirstFile().empty()); } return FALSE; } std::string LLDirPicker::getDirName() { - if (mFilePicker) - { - return mFilePicker->getFirstFile(); - } - return ""; + return getFirstFile(); } #else // not implemented diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index 26f76915a..cdee1d094 100644 --- a/indra/newview/lldirpicker.h +++ b/indra/newview/lldirpicker.h @@ -57,9 +57,15 @@ #include #endif -class LLFilePicker; +#if LL_LINUX || LL_SOLARIS +#include "llfilepicker.h" +#endif class LLDirPicker +#if LL_LINUX || LL_SOLARIS + // On Linux we just implement LLDirPicker on top of LLFilePickerBase + : public LLFilePickerBase +#endif { public: // calling this before main() is undefined @@ -90,19 +96,13 @@ private: #endif -#if LL_LINUX || LL_SOLARIS - // On Linux we just implement LLDirPicker on top of LLFilePicker - LLFilePicker *mFilePicker; -#endif - std::string* mFileName; std::string mDir; BOOL mLocked; static LLDirPicker sInstance; -public: - // don't call these directly please. +private: LLDirPicker(); ~LLDirPicker(); }; diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 5cea197ca..fb327e5a6 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -70,7 +70,7 @@ LLFilePicker LLFilePicker::sInstance; // // Implementation // -LLFilePicker::LLFilePicker() +LLFilePickerBase::LLFilePickerBase() : mCurrentFile(0), mLocked(FALSE) @@ -108,19 +108,13 @@ LLFilePicker::LLFilePicker() #endif } -LLFilePicker::~LLFilePicker() -{ - // nothing -} - - -const std::string LLFilePicker::getFirstFile() +const std::string LLFilePickerBase::getFirstFile() { mCurrentFile = 0; return getNextFile(); } -const std::string LLFilePicker::getNextFile() +const std::string LLFilePickerBase::getNextFile() { if (mCurrentFile >= getFileCount()) { @@ -133,7 +127,7 @@ const std::string LLFilePicker::getNextFile() } } -const std::string LLFilePicker::getCurFile() +const std::string LLFilePickerBase::getCurFile() { if (mCurrentFile >= getFileCount()) { @@ -146,7 +140,7 @@ const std::string LLFilePicker::getCurFile() } } -void LLFilePicker::reset() +void LLFilePickerBase::reset() { mLocked = FALSE; mFiles.clear(); @@ -155,7 +149,7 @@ void LLFilePicker::reset() #if LL_WINDOWS -BOOL LLFilePicker::setupFilter(ELoadFilter filter) +BOOL LLFilePickerBase::setupFilter(ELoadFilter filter) { BOOL res = TRUE; switch (filter) @@ -220,7 +214,7 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) return res; } -BOOL LLFilePicker::getOpenFile(ELoadFilter filter) +BOOL LLFilePickerBase::getOpenFile(ELoadFilter filter) { if( mLocked ) { @@ -258,7 +252,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter) return success; } -BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter) +BOOL LLFilePickerBase::getMultipleOpenFiles(ELoadFilter filter) { if( mLocked ) { @@ -321,7 +315,7 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter) return success; } -BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename) +BOOL LLFilePickerBase::getSaveFile(ESaveFilter filter, const std::string& filename) { if( mLocked ) { @@ -735,7 +729,7 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename) #elif LL_DARWIN -Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode) +Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode) { Boolean result = true; ELoadFilter filter = *((ELoadFilter*) callBackUD); @@ -832,7 +826,7 @@ Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callB return result; } -OSStatus LLFilePicker::doNavChooseDialog(ELoadFilter filter) +OSStatus LLFilePickerBase::doNavChooseDialog(ELoadFilter filter) { OSStatus error = noErr; NavDialogRef navRef = NULL; @@ -887,7 +881,7 @@ OSStatus LLFilePicker::doNavChooseDialog(ELoadFilter filter) return error; } -OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) +OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, const std::string& filename) { OSStatus error = noErr; NavDialogRef navRef = NULL; @@ -1059,7 +1053,7 @@ OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& fi return error; } -BOOL LLFilePicker::getOpenFile(ELoadFilter filter) +BOOL LLFilePickerBase::getOpenFile(ELoadFilter filter) { if( mLocked ) return FALSE; @@ -1088,7 +1082,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter) return success; } -BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter) +BOOL LLFilePickerBase::getMultipleOpenFiles(ELoadFilter filter) { if( mLocked ) return FALSE; @@ -1119,7 +1113,7 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter) return success; } -BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename) +BOOL LLFilePickerBase::getSaveFile(ESaveFilter filter, const std::string& filename) { if( mLocked ) return FALSE; @@ -1152,13 +1146,13 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename) # if LL_GTK // static -void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data) +void LLFilePickerBase::add_to_selectedfiles(gpointer data, gpointer user_data) { // We need to run g_filename_to_utf8 in the user's locale std::string saved_locale(setlocale(LC_ALL, NULL)); setlocale(LC_ALL, ""); - LLFilePicker* picker = (LLFilePicker*) user_data; + LLFilePickerBase* picker = (LLFilePickerBase*) user_data; GError *error = NULL; gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, -1, NULL, NULL, &error); @@ -1189,7 +1183,7 @@ void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data) } // static -void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) +void LLFilePickerBase::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) { LLFilePicker* picker = (LLFilePicker*)user_data; @@ -1212,7 +1206,7 @@ void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer } -GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context) +GtkWindow* LLFilePickerBase::buildFilePicker(bool is_save, bool is_folder, std::string context) { if (LLWindowSDL::ll_try_gtk_init()) { @@ -1270,7 +1264,7 @@ GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::stri g_signal_connect (GTK_FILE_CHOOSER(win), "response", - G_CALLBACK(LLFilePicker::chooser_responder), + G_CALLBACK(LLFilePickerBase::chooser_responder), this); gtk_window_set_modal(GTK_WINDOW(win), TRUE); @@ -1346,7 +1340,7 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) } -BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) +BOOL LLFilePickerBase::getSaveFile( ESaveFilter filter, const std::string& filename ) { BOOL rtn = FALSE; @@ -1435,7 +1429,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename return rtn; } -BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) +BOOL LLFilePickerBase::getOpenFile( ELoadFilter filter ) { BOOL rtn = FALSE; @@ -1479,7 +1473,7 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) return rtn; } -BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter ) +BOOL LLFilePickerBase::getMultipleOpenFiles( ELoadFilter filter ) { BOOL rtn = FALSE; @@ -1511,7 +1505,7 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter ) // Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with // static results, when we don't have a real filepicker. -BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) +BOOL LLFilePickerBase::getSaveFile( ESaveFilter filter, const std::string& filename ) { reset(); @@ -1525,7 +1519,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename return FALSE; } -BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) +BOOL LLFilePickerBase::getOpenFile( ELoadFilter filter ) { reset(); @@ -1543,7 +1537,7 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) return TRUE; } -BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter ) +BOOL LLFilePickerBase::getMultipleOpenFiles( ELoadFilter filter ) { reset(); return FALSE; @@ -1553,19 +1547,19 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter ) #else // not implemented -BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) +BOOL LLFilePickerBase::getSaveFile( ESaveFilter filter, const std::string& filename ) { reset(); return FALSE; } -BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) +BOOL LLFilePickerBase::getOpenFile( ELoadFilter filter ) { reset(); return FALSE; } -BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter ) +BOOL LLFilePickerBase::getMultipleOpenFiles( ELoadFilter filter ) { reset(); return FALSE; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index feba53423..8063a7068 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -69,16 +69,11 @@ #include "SDL/SDL_syswm.h" #endif -class LLFilePicker +// This class is used as base class of a singleton and is therefore not +// allowed to have any static members or static local variables! +class LLFilePickerBase { -#ifdef LL_GTK - friend class LLDirPicker; - friend void chooser_responder(GtkWidget *, gint, gpointer); -#endif // LL_GTK public: - // calling this before main() is undefined - static LLFilePicker& instance( void ) { return sInstance; } - enum ELoadFilter { FFLOAD_ALL = 1, @@ -212,8 +207,6 @@ private: S32 mCurrentFile; BOOL mLocked; BOOL mMultiFile; - - static LLFilePicker sInstance; protected: #if LL_GTK @@ -221,10 +214,21 @@ protected: std::string context = "generic"); #endif +protected: + LLFilePickerBase(); +}; + +// True singleton, private constructors (and no friends). +class LLFilePicker : public LLFilePickerBase +{ public: - // don't call these directly please. - LLFilePicker(); - ~LLFilePicker(); + // calling this before main() is undefined + static LLFilePicker& instance( void ) { return sInstance; } + +private: + static LLFilePicker sInstance; + + LLFilePicker() { } }; #endif diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 5af0de858..2d4ed9939 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -149,7 +149,7 @@ public: void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f); LLFloaterPostcard* savePostcard(); void saveTexture(); - BOOL saveLocal(); + void saveLocal(); BOOL setThumbnailImageSize() ; void generateThumbnailImage(BOOL force_update = FALSE) ; @@ -1005,20 +1005,14 @@ void LLSnapshotLivePreview::saveTexture() mDataSize = 0; } -BOOL LLSnapshotLivePreview::saveLocal() +void LLSnapshotLivePreview::saveLocal() { - BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage); + gViewerWindow->saveImageNumbered(mFormattedImage); // Relinquish image memory. Save button will be disabled as a side-effect. mFormattedImage = NULL; mDataSize = 0; updateSnapshot(FALSE, FALSE); - - if(success) - { - gViewerWindow->playSnapshotAnimAndSound(); - } - return success; } ///---------------------------------------------------------------------------- diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index f185fb9b9..bbf2dfa01 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -34,7 +34,7 @@ #define LL_LLMediaCtrl_H #include "llviewermedia.h" - +#include "llviewermediaobserver.h" #include "lluictrl.h" #include "llframetimer.h" #include "lldynamictexture.h" diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 035bdebe1..ca21f6d0c 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -47,84 +47,12 @@ #include "lluuid.h" #include "llkeyboard.h" - // Merov: Temporary definitions while porting the new viewer media code to Snowglobe const int LEFT_BUTTON = 0; const int RIGHT_BUTTON = 1; -// Move this to its own file. - -LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() -{ - observerListType::iterator iter = mObservers.begin(); - - while( iter != mObservers.end() ) - { - LLViewerMediaObserver *self = *iter; - iter++; - remObserver(self); - } -} - /////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer ) -{ - if ( ! observer ) - return false; - - if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() ) - return false; - - mObservers.push_back( observer ); - observer->mEmitters.push_back( this ); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) -{ - if ( ! observer ) - return false; - - mObservers.remove( observer ); - observer->mEmitters.remove(this); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLPluginClassMediaOwner::EMediaEvent event ) -{ - observerListType::iterator iter = mObservers.begin(); - - while( iter != mObservers.end() ) - { - LLViewerMediaObserver *self = *iter; - ++iter; - self->handleMediaEvent( media, event ); - } -} - -// Move this to its own file. -LLViewerMediaObserver::~LLViewerMediaObserver() -{ - std::list::iterator iter = mEmitters.begin(); - - while( iter != mEmitters.end() ) - { - LLViewerMediaEventEmitter *self = *iter; - iter++; - self->remObserver( this ); - } -} - - -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method +// Helper class that tries to download a URL from a web site and calls a method // on the Panel Land Media and to discover the MIME type class LLMimeDiscoveryResponder : public LLHTTPClient::Responder { @@ -279,9 +207,10 @@ void LLViewerMedia::updateBrowserUserAgent() for(; iter != end; iter++) { LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser()) + LLPluginClassMedia* plugin = pimpl->getMediaPlugin(); + if(plugin && plugin->pluginSupportsMediaBrowser()) { - pimpl->mMediaSource->setBrowserUserAgent(user_agent); + plugin->setBrowserUserAgent(user_agent); } } @@ -366,7 +295,6 @@ LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url, U8 media_loop, const std::string& mime_type) : - mMediaSource( NULL ), mMovieImageHasMips(false), mTextureId(texture_id), mMediaWidth(media_width), @@ -399,7 +327,7 @@ LLViewerMediaImpl::~LLViewerMediaImpl() ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) { - if((mMediaSource == NULL) || (mMimeType != mime_type)) + if((mPluginBase == NULL) || (mMimeType != mime_type)) { if(! initializePlugin(mime_type)) { @@ -413,7 +341,7 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) } // play(); - return (mMediaSource != NULL); + return (mPluginBase != NULL); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -434,14 +362,13 @@ void LLViewerMediaImpl::createMediaSource() void LLViewerMediaImpl::destroyMediaSource() { mNeedsNewTexture = true; - if(! mMediaSource) + if (!mPluginBase) { return; } // Restore the texture updateMovieImage(LLUUID::null, false); - delete mMediaSource; - mMediaSource = NULL; + destroyPlugin(); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -514,16 +441,17 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ LLNotifications::instance().add("NoPlugin", args); return NULL; -} +} ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { // Save the previous media source's last set size before destroying it. - mMediaWidth = mMediaSource->getSetWidth(); - mMediaHeight = mMediaSource->getSetHeight(); + mMediaWidth = plugin->getSetWidth(); + mMediaHeight = plugin->getSetHeight(); } // Always delete the old media impl first. @@ -541,7 +469,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) media_source->setAutoScale(mMediaAutoScale); media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); - mMediaSource = media_source; + mPluginBase = media_source; return true; } @@ -550,34 +478,38 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) void LLViewerMediaImpl::setSize(int width, int height) { + LLPluginClassMedia* plugin = getMediaPlugin(); mMediaWidth = width; mMediaHeight = height; - if(mMediaSource) + if (plugin) { - mMediaSource->setSize(width, height); + plugin->setSize(width, height); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::play() { + LLPluginClassMedia* plugin = getMediaPlugin(); + // first stop any previously playing media // stop(); - // mMediaSource->addObserver( this ); - if(mMediaSource == NULL) + // plugin->addObserver( this ); + if (!plugin) { if(!initializePlugin(mMimeType)) { // Plugin failed initialization... should assert or something return; } + plugin = getMediaPlugin(); } // updateMovieImage(mTextureId, true); - mMediaSource->loadURI( mMediaURL ); - if(/*mMediaSource->pluginSupportsMediaTime()*/ true) + plugin->loadURI( mMediaURL ); + if(/*plugin->pluginSupportsMediaTime()*/ true) { start(); } @@ -586,9 +518,10 @@ void LLViewerMediaImpl::play() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::stop() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->stop(); + plugin->stop(); // destroyMediaSource(); } } @@ -596,52 +529,57 @@ void LLViewerMediaImpl::stop() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::pause() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->pause(); + plugin->pause(); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::start() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->start(); + plugin->start(); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::seek(F32 time) { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->seek(time); + plugin->seek(time); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::setVolume(F32 volume) { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->setVolume(volume); + plugin->setVolume(volume); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::focus(bool focus) { - if (mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { // call focus just for the hell of it, even though this apopears to be a nop - mMediaSource->focus(focus); + plugin->focus(focus); if (focus) { // spoof a mouse click to *actually* pass focus // Don't do this anymore -- it actually clicks through now. -// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); -// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); +// plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); +// plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); } } } @@ -649,57 +587,62 @@ void LLViewerMediaImpl::focus(bool focus) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseDown(S32 x, S32 y) { + LLPluginClassMedia* plugin = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (mMediaSource) + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, LEFT_BUTTON, x, y, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, LEFT_BUTTON, x, y, 0); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseUp(S32 x, S32 y) { + LLPluginClassMedia* plugin = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (mMediaSource) + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, x, y, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, x, y, 0); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseMove(S32 x, S32 y) { + LLPluginClassMedia* plugin = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (mMediaSource) + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, LEFT_BUTTON, x, y, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, LEFT_BUTTON, x, y, 0); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseLeftDoubleClick(S32 x, S32 y) { + LLPluginClassMedia* plugin = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (mMediaSource) + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, LEFT_BUTTON, x, y, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, LEFT_BUTTON, x, y, 0); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::onMouseCaptureLost() { - if (mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, mLastMouseX, mLastMouseY, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, mLastMouseX, mLastMouseY, 0); } } @@ -720,15 +663,17 @@ BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateHome() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->loadURI( mHomeURL ); + plugin->loadURI( mHomeURL ); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type) { + LLPluginClassMedia* plugin = getMediaPlugin(); if(rediscover_type) { @@ -745,7 +690,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi // We use "data" internally for a text/html url for loading the login screen if(initializeMedia("text/html")) { - mMediaSource->loadURI( url ); + plugin->loadURI( url ); } } else @@ -753,17 +698,17 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi // This catches 'rtsp://' urls if(initializeMedia(scheme)) { - mMediaSource->loadURI( url ); + plugin->loadURI( url ); } } } - else if (mMediaSource) + else if (plugin) { - mMediaSource->loadURI( url ); + plugin->loadURI( url ); } - else if(initializeMedia(mime_type) && mMediaSource) + else if(initializeMedia(mime_type) && (plugin = getMediaPlugin())) { - mMediaSource->loadURI( url ); + plugin->loadURI( url ); } else { @@ -777,9 +722,10 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateStop() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->browse_stop(); + plugin->browse_stop(); } } @@ -788,8 +734,9 @@ void LLViewerMediaImpl::navigateStop() bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) { bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); - if (mMediaSource) + if (plugin) { // FIXME: THIS IS SO WRONG. // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... @@ -797,19 +744,19 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) { if( 'C' == key ) { - mMediaSource->copy(); + plugin->copy(); result = true; } else if( 'V' == key ) { - mMediaSource->paste(); + plugin->paste(); result = true; } else if( 'X' == key ) { - mMediaSource->cut(); + plugin->cut(); result = true; } } @@ -819,9 +766,9 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) LLSD native_key_data = LLSD::emptyMap(); - result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); + result = plugin->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. - (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); + (void)plugin->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); } } @@ -832,8 +779,9 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) { bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); - if (mMediaSource) + if (plugin) { // only accept 'printable' characters, sigh... if (uni_char >= 32 // discard 'control' characters @@ -841,7 +789,7 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) { LLSD native_key_data = LLSD::emptyMap(); - mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); + plugin->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); } } @@ -851,10 +799,11 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::canNavigateForward() { - BOOL result = FALSE; - if (mMediaSource) + bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - result = mMediaSource->getHistoryForwardAvailable(); + result = plugin->getHistoryForwardAvailable(); } return result; } @@ -862,10 +811,11 @@ bool LLViewerMediaImpl::canNavigateForward() ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::canNavigateBack() { - BOOL result = FALSE; - if (mMediaSource) + bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - result = mMediaSource->getHistoryBackAvailable(); + result = plugin->getHistoryBackAvailable(); } return result; } @@ -909,20 +859,21 @@ void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::update() { - if(mMediaSource == NULL) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (!plugin) { return; } - mMediaSource->idle(); + plugin->idle(); - if(mMediaSource->isPluginExited()) + if (plugin->isPluginExited()) { destroyMediaSource(); return; } - if(!mMediaSource->textureValid()) + if (!plugin->textureValid()) { return; } @@ -937,7 +888,7 @@ void LLViewerMediaImpl::update() if(placeholder_image) { LLRect dirty_rect; - if(mMediaSource->getDirty(&dirty_rect)) + if (plugin->getDirty(&dirty_rect)) { // Constrain the dirty rect to be inside the texture S32 x_pos = llmax(dirty_rect.mLeft, 0); @@ -948,16 +899,16 @@ void LLViewerMediaImpl::update() if(width > 0 && height > 0) { - U8* data = mMediaSource->getBitsData(); + U8* data = plugin->getBitsData(); // Offset the pixels pointer to match x_pos and y_pos - data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); - data += ( y_pos * mMediaSource->getTextureDepth() ); + data += ( x_pos * plugin->getTextureDepth() * plugin->getBitsWidth() ); + data += ( y_pos * plugin->getTextureDepth() ); placeholder_image->setSubImage( data, - mMediaSource->getBitsWidth(), - mMediaSource->getBitsHeight(), + plugin->getBitsWidth(), + plugin->getBitsHeight(), x_pos, y_pos, width, @@ -966,7 +917,7 @@ void LLViewerMediaImpl::update() } - mMediaSource->resetDirty(); + plugin->resetDirty(); } } } @@ -988,22 +939,23 @@ void LLViewerMediaImpl::updateImagesMediaStreams() } LLViewerMediaTexture* placeholder_image = (LLViewerMediaTexture*)LLViewerTextureManager::findTexture( mTextureId ); + LLPluginClassMedia* plugin = getMediaPlugin(); if (mNeedsNewTexture || placeholder_image->getUseMipMaps() || ! placeholder_image->mIsMediaTexture - || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) - || (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) - || (mTextureUsedWidth != mMediaSource->getWidth()) - || (mTextureUsedHeight != mMediaSource->getHeight()) + || (placeholder_image->getWidth() != plugin->getTextureWidth()) + || (placeholder_image->getHeight() != plugin->getTextureHeight()) + || (mTextureUsedWidth != plugin->getWidth()) + || (mTextureUsedHeight != plugin->getHeight()) ) { llinfos << "initializing media placeholder" << llendl; llinfos << "movie image id " << mTextureId << llendl; - int texture_width = mMediaSource->getTextureWidth(); - int texture_height = mMediaSource->getTextureHeight(); - int texture_depth = mMediaSource->getTextureDepth(); + int texture_width = plugin->getTextureWidth(); + int texture_height = plugin->getTextureHeight(); + int texture_depth = plugin->getTextureDepth(); // MEDIAOPT: check to see if size actually changed before doing work placeholder_image->destroyGLTexture(); @@ -1017,10 +969,10 @@ void LLViewerMediaImpl::updateImagesMediaStreams() int discard_level = 0; // ask media source for correct GL image format constants - placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), - mMediaSource->getTextureFormatPrimary(), - mMediaSource->getTextureFormatType(), - mMediaSource->getTextureFormatSwapBytes()); + placeholder_image->setExplicitFormat(plugin->getTextureFormatInternal(), + plugin->getTextureFormatPrimary(), + plugin->getTextureFormatType(), + plugin->getTextureFormatSwapBytes()); placeholder_image->createGLTexture(discard_level, raw); @@ -1033,8 +985,8 @@ void LLViewerMediaImpl::updateImagesMediaStreams() // If the amount of the texture being drawn by the media goes down in either width or height, // recreate the texture to avoid leaving parts of the old image behind. - mTextureUsedWidth = mMediaSource->getWidth(); - mTextureUsedHeight = mMediaSource->getHeight(); + mTextureUsedWidth = plugin->getWidth(); + mTextureUsedHeight = plugin->getHeight(); } return placeholder_image; @@ -1050,24 +1002,25 @@ LLUUID LLViewerMediaImpl::getMediaTextureID() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::setVisible(bool visible) { + LLPluginClassMedia* plugin = getMediaPlugin(); mVisible = visible; if(mVisible) { - if(mMediaSource && mMediaSource->isPluginExited()) + if(plugin && plugin->isPluginExited()) { destroyMediaSource(); } - if(!mMediaSource) + if(!plugin) { createMediaSource(); } } - if(mMediaSource) + if(plugin) { - mMediaSource->setPriority(mVisible?LLPluginClassMedia::PRIORITY_NORMAL:LLPluginClassMedia::PRIORITY_HIDDEN); + plugin->setPriority(mVisible?LLPluginClassBasic::PRIORITY_NORMAL:LLPluginClassBasic::PRIORITY_SLEEP); } } @@ -1080,10 +1033,11 @@ void LLViewerMediaImpl::mouseCapture() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::getTextureSize(S32 *texture_width, S32 *texture_height) { - if(mMediaSource && mMediaSource->textureValid()) + LLPluginClassMedia* plugin = getMediaPlugin(); + if(plugin && plugin->textureValid()) { - S32 real_texture_width = mMediaSource->getBitsWidth(); - S32 real_texture_height = mMediaSource->getBitsHeight(); + S32 real_texture_width = plugin->getBitsWidth(); + S32 real_texture_height = plugin->getBitsHeight(); { // The "texture width" coming back from the plugin may not be a power of two (thanks to webkit). @@ -1124,10 +1078,11 @@ void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) bool LLViewerMediaImpl::isMediaPlaying() { bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); - if(mMediaSource) + if(plugin) { - EMediaStatus status = mMediaSource->getStatus(); + EMediaStatus status = plugin->getStatus(); if(status == MEDIA_PLAYING || status == MEDIA_LOADING) result = true; } @@ -1138,10 +1093,11 @@ bool LLViewerMediaImpl::isMediaPlaying() bool LLViewerMediaImpl::isMediaPaused() { bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); - if(mMediaSource) + if(plugin) { - if(mMediaSource->getStatus() == MEDIA_PAUSED) + if(plugin->getStatus() == MEDIA_PAUSED) result = true; } @@ -1152,7 +1108,7 @@ bool LLViewerMediaImpl::isMediaPaused() // bool LLViewerMediaImpl::hasMedia() { - return mMediaSource != NULL; + return mPluginBase != NULL; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1179,8 +1135,9 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* self, LLPluginClass void LLViewerMediaImpl::cut() { - if (mMediaSource) - mMediaSource->cut(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + plugin->cut(); } //////////////////////////////////////////////////////////////////////////////// @@ -1188,8 +1145,9 @@ LLViewerMediaImpl::cut() BOOL LLViewerMediaImpl::canCut() const { - if (mMediaSource) - return mMediaSource->canCut(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + return plugin->canCut(); else return FALSE; } @@ -1199,8 +1157,9 @@ LLViewerMediaImpl::canCut() const void LLViewerMediaImpl::copy() { - if (mMediaSource) - mMediaSource->copy(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + plugin->copy(); } //////////////////////////////////////////////////////////////////////////////// @@ -1208,8 +1167,9 @@ LLViewerMediaImpl::copy() BOOL LLViewerMediaImpl::canCopy() const { - if (mMediaSource) - return mMediaSource->canCopy(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + return plugin->canCopy(); else return FALSE; } @@ -1219,8 +1179,9 @@ LLViewerMediaImpl::canCopy() const void LLViewerMediaImpl::paste() { - if (mMediaSource) - mMediaSource->paste(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + plugin->paste(); } //////////////////////////////////////////////////////////////////////////////// @@ -1228,8 +1189,9 @@ LLViewerMediaImpl::paste() BOOL LLViewerMediaImpl::canPaste() const { - if (mMediaSource) - return mMediaSource->canPaste(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + return plugin->canPaste(); else return FALSE; } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 1e9ef6c90..6b8bd2217 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -33,34 +33,17 @@ #ifndef LLVIEWERMEDIA_H #define LLVIEWERMEDIA_H +#include "llviewermediaeventemitter.h" +#include "llviewerpluginmanager.h" #include "llfocusmgr.h" - #include "llpanel.h" -#include "llpluginclassmediaowner.h" - -#include "llviewermediaobserver.h" class LLViewerMediaImpl; class LLUUID; -//class LLViewerMediaTexture; +class LLSD; class LLViewerTexture; typedef LLPointer viewer_media_t; -/////////////////////////////////////////////////////////////////////////////// -// -class LLViewerMediaEventEmitter -{ -public: - virtual ~LLViewerMediaEventEmitter(); - - bool addObserver( LLViewerMediaObserver* subject ); - bool remObserver( LLViewerMediaObserver* subject ); - void emitEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event); - -private: - typedef std::list< LLViewerMediaObserver* > observerListType; - observerListType mObservers; -}; class LLViewerMedia { @@ -93,7 +76,7 @@ class LLViewerMedia // Implementation functions not exported into header file class LLViewerMediaImpl - : public LLMouseHandler, public LLRefCount, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler + : public LLViewerPluginManager, public LLMouseHandler, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler { LOG_CLASS(LLViewerMediaImpl); public: @@ -112,9 +95,12 @@ public: void setMediaType(const std::string& media_type); bool initializeMedia(const std::string& mime_type); bool initializePlugin(const std::string& media_type); - LLPluginClassMedia* getMediaPlugin() { return mMediaSource; } + LLPluginClassMedia* getMediaPlugin() const { return (LLPluginClassMedia*)mPluginBase; } void setSize(int width, int height); + // Inherited from LLViewerPluginManager. + /*virtual*/ void update(); + void play(); void stop(); void pause(); @@ -141,7 +127,6 @@ public: void getTextureSize(S32 *texture_width, S32 *texture_height); void scaleMouse(S32 *mouse_x, S32 *mouse_y); - void update(); void updateMovieImage(const LLUUID& image_id, BOOL active); void updateImagesMediaStreams(); LLUUID getMediaTextureID(); @@ -201,7 +186,6 @@ public: public: // a single media url with some data and an impl. - LLPluginClassMedia* mMediaSource; LLUUID mTextureId; bool mMovieImageHasMips; std::string mMediaURL; @@ -219,7 +203,6 @@ public: bool mSuspendUpdates; bool mVisible; - private: /*LLViewerMediaTexture*/LLViewerTexture *updatePlaceholderImage(); }; diff --git a/indra/newview/llviewermediaeventemitter.cpp b/indra/newview/llviewermediaeventemitter.cpp new file mode 100644 index 000000000..39e0b2b52 --- /dev/null +++ b/indra/newview/llviewermediaeventemitter.cpp @@ -0,0 +1,85 @@ +/** + * @file llviewermediaeventemitter.cpp + * @brief Implementation of LLViewerMediaEventEmitter + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, 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 "llviewerprecompiledheaders.h" +#include "llviewermediaeventemitter.h" +#include "llviewermediaobserver.h" +#include + +LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() +{ + observerListType::iterator iter = mObservers.begin(); + + while (iter != mObservers.end()) + { + LLViewerMediaObserver* self = *iter; + ++iter; + remObserver(self); + } +} + +bool LLViewerMediaEventEmitter::addObserver(LLViewerMediaObserver* observer) +{ + if (!observer) + return false; + + if (std::find(mObservers.begin(), mObservers.end(), observer) != mObservers.end()) + return false; + + mObservers.push_back(observer); + observer->mEmitters.push_back(this); + + return true; +} + +bool LLViewerMediaEventEmitter::remObserver(LLViewerMediaObserver* observer) +{ + if (!observer) + return false; + + mObservers.remove(observer); + observer->mEmitters.remove(this); + + return true; +} + +void LLViewerMediaEventEmitter::emitEvent(LLPluginClassMedia* media, LLPluginClassMediaOwner::EMediaEvent event) +{ + observerListType::iterator iter = mObservers.begin(); + + while (iter != mObservers.end()) + { + LLViewerMediaObserver* self = *iter; + ++iter; + self->handleMediaEvent(media, event); + } +} diff --git a/indra/newview/llviewermediaeventemitter.h b/indra/newview/llviewermediaeventemitter.h new file mode 100644 index 000000000..17453a9e1 --- /dev/null +++ b/indra/newview/llviewermediaeventemitter.h @@ -0,0 +1,56 @@ +/** + * @file llviewermediaeventemitter.h + * @brief Helper class + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, 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 LLVIEWERMEDIAEVENTEMITTER_H +#define LLVIEWERMEDIAEVENTEMITTER_H + +#include "llpluginclassmediaowner.h" +#include + +class LLViewerMediaObserver; +class LLPluginClassMedia; + +class LLViewerMediaEventEmitter +{ +public: + virtual ~LLViewerMediaEventEmitter(); + + bool addObserver(LLViewerMediaObserver* subject); + bool remObserver(LLViewerMediaObserver* subject); + void emitEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event); + +private: + typedef std::list< LLViewerMediaObserver*> observerListType; + observerListType mObservers; +}; + +#endif // LLVIEWERMEDIAEVENTEMITTER_H diff --git a/indra/newview/llviewermediaobserver.cpp b/indra/newview/llviewermediaobserver.cpp new file mode 100644 index 000000000..6bed14311 --- /dev/null +++ b/indra/newview/llviewermediaobserver.cpp @@ -0,0 +1,47 @@ +/** + * @file llviewermediaobserver.cpp + * @brief Implementation of class LLViewerMediaObserver. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, 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 "llviewerprecompiledheaders.h" +#include "llviewermediaeventemitter.h" +#include "llviewermediaobserver.h" + +LLViewerMediaObserver::~LLViewerMediaObserver() +{ + std::list::iterator iter = mEmitters.begin(); + + while (iter != mEmitters.end()) + { + LLViewerMediaEventEmitter* self = *iter; + ++iter; + self->remObserver(this); + } +} diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index b4d01d476..7e276e51f 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -552,8 +552,6 @@ class LLFileTakeSnapshotToDisk : public view_listener_t 6144, supersample)) { - gViewerWindow->playSnapshotAnimAndSound(); - LLPointer formatted; switch(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))) { diff --git a/indra/newview/llviewerparcelmedia.h b/indra/newview/llviewerparcelmedia.h index 7531a0f59..50e7aaa2c 100644 --- a/indra/newview/llviewerparcelmedia.h +++ b/indra/newview/llviewerparcelmedia.h @@ -34,6 +34,7 @@ #define LLVIEWERPARCELMEDIA_H #include "llviewermedia.h" +#include "llviewermediaobserver.h" // For use by other patches so they know that media filtering is implemented. #define MEDIA_FILTERING 1 @@ -42,7 +43,6 @@ class LLMessageSystem; class LLParcel; class LLViewerParcelMediaNavigationObserver; - // This class understands land parcels, network traffic, LSL media // transport commands, and talks to the LLViewerMedia class to actually // do playback. It allows us to remove code from LLViewerParcelMgr. diff --git a/indra/newview/llviewerpluginmanager.cpp b/indra/newview/llviewerpluginmanager.cpp new file mode 100644 index 000000000..58ee33585 --- /dev/null +++ b/indra/newview/llviewerpluginmanager.cpp @@ -0,0 +1,56 @@ +/** + * @file llviewerpluginmanager.cpp + * @brief Client interface to the plugin engine + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, 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 "llviewerprecompiledheaders.h" +#include "llviewerpluginmanager.h" + +void LLViewerPluginManager::destroyPlugin() +{ + delete mPluginBase; + mPluginBase = NULL; +} + +void LLViewerPluginManager::update() +{ + if (!mPluginBase) + { + return; + } + + mPluginBase->idle(); + + if (mPluginBase->isPluginExited()) + { + destroyPlugin(); + return; + } +} diff --git a/indra/newview/llviewerpluginmanager.h b/indra/newview/llviewerpluginmanager.h new file mode 100644 index 000000000..b56d11eee --- /dev/null +++ b/indra/newview/llviewerpluginmanager.h @@ -0,0 +1,115 @@ +/** + * @file llviewerpluginmanager.h + * @brief Client interface to the plugin engine + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, 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 LLVIEWERPLUGINMANAGER_H +#define LLVIEWERPLUGINMANAGER_H + +#include +#include "llmemory.h" +#include "llerror.h" +#include "lldir.h" +#include "llfile.h" +#include "llviewercontrol.h" +#include "llnotifications.h" +#include "llpluginclassbasic.h" + +class LLViewerPluginManager : public LLRefCount +{ + LOG_CLASS(LLViewerPluginManager); + +public: + // Construct an uninitialized LLViewerPluginManager object. + LLViewerPluginManager(void) : mPluginBase(NULL) { } + + // Create a PLUGIN_TYPE (must be derived from LLPluginClassBasic). + // This uses PLUGIN_TYPE::launcher_name() and PLUGIN_TYPE::plugin_basename(). + // If successful, returns the created LLPluginClassBasic, NULL otherwise. + template + LLPluginClassBasic* createPlugin(T* user_data); + + // Delete the plugin. + void destroyPlugin(); + + // Handle plugin messages. + virtual void update(); + + // Return pointer to plugin. + LLPluginClassBasic* getPlugin(void) const { return mPluginBase; } + +protected: + LLPluginClassBasic* mPluginBase; //!< Pointer to the base class of the underlaying plugin. +}; + +template +LLPluginClassBasic* LLViewerPluginManager::createPlugin(T* user_data) +{ + // Always delete the old plugin first. + destroyPlugin(); + + std::string plugin_name = gDirUtilp->getLLPluginFilename(PLUGIN_TYPE::plugin_basename()); + + // See if the plugin executable exists. + llstat s; + if (LLFile::stat(PLUGIN_TYPE::launcher_name(), &s)) + { + LL_WARNS("Plugin") << "Couldn't find launcher at " << PLUGIN_TYPE::launcher_name() << LL_ENDL; + } + else if (LLFile::stat(plugin_name, &s)) + { + LL_WARNS("Plugin") << "Couldn't find plugin at " << plugin_name << LL_ENDL; + } + else + { + LLPluginClassBasic* plugin = new PLUGIN_TYPE(user_data); + if (plugin->init(PLUGIN_TYPE::launcher_name(), plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))) + { + mPluginBase = plugin; + } + else + { + LL_WARNS("Plugin") << "Failed to init plugin. Destroying." << LL_ENDL; + delete plugin; + } + } + + if (mPluginBase) + return mPluginBase; + + LL_WARNS("Plugin") << "plugin intialization failed for plugin: " << PLUGIN_TYPE::plugin_basename() << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = PLUGIN_TYPE::plugin_basename(); // FIXME: Use different notification. + LLNotifications::instance().add("NoPlugin", args); + + return NULL; +} + +#endif // LLVIEWERPLUGINMANAGER_H diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index a82fdb3d5..2139e75d8 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -89,7 +89,7 @@ #include "llmaniptranslate.h" #include "llface.h" #include "llfeaturemanager.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llfloater.h" #include "llfloateractivespeakers.h" #include "llfloaterbuildoptions.h" @@ -3988,27 +3988,27 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d } // Saves an image to the harddrive as "SnapshotX" where X >= 1. -BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image) +void LLViewerWindow::saveImageNumbered(LLPointer image) { if (!image) { - return FALSE; + return; } - LLFilePicker::ESaveFilter pick_type; + ESaveFilter pick_type; std::string extension("." + image->getExtension()); if (extension == ".j2c") - pick_type = LLFilePicker::FFSAVE_J2C; + pick_type = FFSAVE_J2C; else if (extension == ".bmp") - pick_type = LLFilePicker::FFSAVE_BMP; + pick_type = FFSAVE_BMP; else if (extension == ".jpg") - pick_type = LLFilePicker::FFSAVE_JPEG; + pick_type = FFSAVE_JPEG; else if (extension == ".png") - pick_type = LLFilePicker::FFSAVE_PNG; + pick_type = FFSAVE_PNG; else if (extension == ".tga") - pick_type = LLFilePicker::FFSAVE_TGA; + pick_type = FFSAVE_TGA; else - pick_type = LLFilePicker::FFSAVE_ALL; // ??? + pick_type = FFSAVE_ALL; // ??? // Get a base file location if needed. if ( ! isSnapshotLocSet()) @@ -4018,20 +4018,34 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image) // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. // pick a directory in which to save - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getSaveFile(pick_type, proposed_name)) - { - // Clicked cancel - return FALSE; - } + AIFilePicker* filepicker = new AIFilePicker; // Deleted in LLViewerWindow::saveImageNumbered_filepicker_callback + filepicker->open(proposed_name, pick_type, "", "snapshot"); + filepicker->run(boost::bind(&LLViewerWindow::saveImageNumbered_filepicker_callback, this, image, extension, filepicker, _1)); + return; + } + // LLViewerWindow::sSnapshotBaseName and LLViewerWindow::sSnapshotDir already known. Go straight to saveImageNumbered_continued. + saveImageNumbered_continued(image, extension); +} + +void LLViewerWindow::saveImageNumbered_filepicker_callback(LLPointer image, std::string const& extension, AIFilePicker* filepicker, bool success) +{ + llassert((bool)*filepicker == success); + if (success) + { // Copy the directory + file name - std::string filepath = picker.getFirstFile(); + std::string filepath = filepicker->getFilename(); LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true); LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath); - } + saveImageNumbered_continued(image, extension); + } + delete filepicker; +} + +void LLViewerWindow::saveImageNumbered_continued(LLPointer image, std::string const& extension) +{ // Look for an unused file name std::string filepath; S32 i = 1; @@ -4051,7 +4065,10 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image) } while( -1 != err ); // search until the file is not found (i.e., stat() gives an error). - return image->save(filepath); + if (image->save(filepath)) + { + playSnapshotAnimAndSound(); + } } void LLViewerWindow::resetSnapshotLoc() diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 21867f7eb..cbf3f0187 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -60,6 +60,7 @@ class LLTextBox; class LLImageRaw; class LLHUDIcon; class LLMouseHandler; +class AIFilePicker; #define PICK_HALF_WIDTH 5 #define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1) @@ -282,19 +283,21 @@ public: // snapshot functionality. // perhaps some of this should move to llfloatershapshot? -MG - typedef enum e_snapshot_type + enum ESnapshotType { SNAPSHOT_TYPE_COLOR, SNAPSHOT_TYPE_DEPTH, SNAPSHOT_TYPE_OBJECT_ID - } ESnapshotType; + }; BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR); BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE, F32 supersample = 1.f ); BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ; BOOL isSnapshotLocSet() const { return ! sSnapshotDir.empty(); } void resetSnapshotLoc() const { sSnapshotDir.clear(); } - BOOL saveImageNumbered(LLImageFormatted *image); + void saveImageNumbered(LLPointer image); + void saveImageNumbered_filepicker_callback(LLPointer image, std::string const& extension, AIFilePicker* filepicker, bool success); + void saveImageNumbered_continued(LLPointer image, std::string const& extension); // Reset the directory where snapshots are saved. // Client will open directory picker on next snapshot save. diff --git a/indra/newview/statemachine/aifilepicker.cpp b/indra/newview/statemachine/aifilepicker.cpp new file mode 100644 index 000000000..cd6856100 --- /dev/null +++ b/indra/newview/statemachine/aifilepicker.cpp @@ -0,0 +1,369 @@ +/** + * @file aifilepicker.cpp + * @brief Implementation of AIFilePicker + * + * Copyright (c) 2010, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * 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. + * + * CHANGELOG + * and additional copyright holders. + * + * 04/12/2010 + * Initial version, written by Aleric Inglewood @ SL + */ + +#include "../llviewerprecompiledheaders.h" +#include "../llviewermedia.h" +#include "../lltrans.h" +#include "llpluginclassmedia.h" +#include "llpluginmessageclasses.h" +#include "aifilepicker.h" +#if LL_WINDOWS +#include "../llviewerwindow.h" +#endif +#if LL_GTK && LL_X11 +#include "llwindowsdl.h" +#endif + +enum filepicker_state_type { + AIFilePicker_initialize_plugin = AIStateMachine::max_state, + AIFilePicker_plugin_running, + AIFilePicker_canceled, + AIFilePicker_done +}; + +char const* AIFilePicker::state_str_impl(state_type run_state) const +{ + switch(run_state) + { + AI_CASE_RETURN(AIFilePicker_initialize_plugin); + AI_CASE_RETURN(AIFilePicker_plugin_running); + AI_CASE_RETURN(AIFilePicker_canceled); + AI_CASE_RETURN(AIFilePicker_done); + } + return "UNKNOWN STATE"; +} + +AIFilePicker::AIFilePicker(void) : mPluginManager(NULL), mCanceled(false) +{ +} + +void AIFilePicker::store_folder(std::string const& context, std::string const& folder) +{ + if (!folder.empty()) + { + mContextMap[context] = folder; + } +} + +std::string AIFilePicker::get_folder(std::string const& default_path, std::string const& context) +{ + context_map_type::iterator iter = mContextMap.find(context); + if (iter != mContextMap.end()) + { + return iter->second; + } + else if (!default_path.empty()) + { + return default_path; + } + else if ((iter = mContextMap.find("savefile")) != mContextMap.end()) + { + return iter->second; + } + else + { + // This is the last resort when all else failed. Open the file chooser in directory 'home'. + char const* home = NULL; +#if LL_WINDOWS + #warning "Attention WINDOWS DEVELOPER: Set 'home' to a sensible default directory (users Desktop?)" +#else + home = getenv("HOME"); +#endif + return home ? home : ""; + } +} + +void AIFilePicker::open(ELoadFilter filter, std::string const& default_path, std::string const& context, bool multiple) +{ + mContext = context; + mFolder = get_folder(default_path, context); + mOpenType = multiple ? load_multiple : load; + switch(filter) + { + case FFLOAD_ALL: + mFilter = "all"; + break; + case FFLOAD_WAV: + mFilter = "wav"; + break; + case FFLOAD_IMAGE: + mFilter = "image"; + break; + case FFLOAD_ANIM: + mFilter = "anim"; + break; +#ifdef _CORY_TESTING + case FFLOAD_GEOMETRY: + mFilter = "geometry"; + break; +#endif + case FFLOAD_XML: + mFilter = "xml"; + break; + case FFLOAD_SLOBJECT: + mFilter = "slobject"; + break; + case FFLOAD_RAW: + mFilter = "raw"; + break; + case FFLOAD_TEXT: + mFilter = "text"; + break; + } +} + +void AIFilePicker::open(std::string const& filename, ESaveFilter filter, std::string const& default_path, std::string const& context) +{ + mFilename = filename; + mContext = context; + mFolder = get_folder(default_path, context); + mOpenType = save; + switch(filter) + { + case FFSAVE_ALL: + mFilter = "all"; + break; + case FFSAVE_WAV: + mFilter = "wav"; + break; + case FFSAVE_TGA: + mFilter = "tga"; + break; + case FFSAVE_BMP: + mFilter = "bmp"; + break; + case FFSAVE_AVI: + mFilter = "avi"; + break; + case FFSAVE_ANIM: + mFilter = "anim"; + break; +#ifdef _CORY_TESTING + case FFSAVE_GEOMETRY: + mFilter = "geometry"; + break; +#endif + case FFSAVE_XML: + mFilter = "xml"; + break; + case FFSAVE_COLLADA: + mFilter = "collada"; + break; + case FFSAVE_RAW: + mFilter = "raw"; + break; + case FFSAVE_J2C: + mFilter = "j2c"; + break; + case FFSAVE_PNG: + mFilter = "png"; + break; + case FFSAVE_JPEG: + mFilter = "jpeg"; + break; + case FFSAVE_HPA: + mFilter = "hpa"; + break; + case FFSAVE_TEXT: + mFilter = "text"; + break; + case FFSAVE_LSL: + mFilter = "lsl"; + break; + } +} + +void AIFilePicker::initialize_impl(void) +{ + mCanceled = false; + if (mFilter.empty()) + { + llwarns << "Calling AIFilePicker::initialize_impl() with empty mFilter. Call open before calling run!" << llendl; + abort(); + return; + } + mPluginManager = new LLViewerPluginManager; + if (!mPluginManager) + { + abort(); + return; + } + LLPluginClassBasic* plugin = mPluginManager->createPlugin(this); + if (!plugin) + { + abort(); + return; + } + set_state(AIFilePicker_initialize_plugin); +} + +void AIFilePicker::multiplex_impl(void) +{ + mPluginManager->update(); // Give the plugin some CPU for it's messages. + LLPluginClassBasic* plugin = mPluginManager->getPlugin(); + if (!plugin || plugin->isPluginExited()) + { + // This happens when there was a problem with the plugin (ie, it crashed). + abort(); + return; + } + switch (mRunState) + { + case AIFilePicker_initialize_plugin: + { + if (!plugin->isPluginRunning()) + { + break; // Still initializing. + } + + // Send initialization message. + LLPluginMessage initialization_message(LLPLUGIN_MESSAGE_CLASS_BASIC, "initialization"); + static char const* key_str[] = { + "all_files", "sound_files", "animation_files", "image_files", "save_file_verb", + "targa_image_files", "bitmap_image_files", "avi_movie_file", "xaf_animation_file", + "xml_file", "raw_file", "compressed_image_files", "load_file_verb", "load_files" + }; + LLSD dictionary; + for (int key = 0; key < sizeof(key_str) / sizeof(key_str[0]); ++key) + { + dictionary[key_str[key]] = LLTrans::getString(key_str[key]); + } + initialization_message.setValueLLSD("dictionary", dictionary); +#if LL_WINDOWS || (LL_GTK && LL_X11) + std::ostringstream window_id_str; +#if LL_WINDOWS + unsigned long window_id = gViewerWindow->getPlatformWindow(); +#else + unsigned long window_id = LLWindowSDL::get_SDL_XWindowID(); +#endif + if (window_id != None) + { + window_id_str << std::hex << "0x" << window_id; + initialization_message.setValue("window_id", window_id_str.str()); + } + else + { + LL_WARNS("Plugin") << "Couldn't get xwid to use for transient." << LL_ENDL; + } +#endif // LL_WINDOWS || (LL_GTK && LL_X11) + plugin->sendMessage(initialization_message); + + // Send open message. + LLPluginMessage open_message(LLPLUGIN_MESSAGE_CLASS_BASIC, "open"); + open_message.setValue("type", (mOpenType == save) ? "save" : (mOpenType == load) ? "load" : "load_multiple"); + open_message.setValue("filter", mFilter); + if (mOpenType == save) open_message.setValue("default", mFilename); + open_message.setValue("folder", mFolder); + open_message.setValue("gorgon", "block"); // Don't expect HeartBeat messages after an "open". + plugin->sendMessage(open_message); + + set_state(AIFilePicker_plugin_running); + break; + } + case AIFilePicker_plugin_running: + { + // Users are slow, no need to look for new messages from the plugin all too often. + yield_ms(250); + break; + } + case AIFilePicker_canceled: + { + mCanceled = true; + finish(); + break; + } + case AIFilePicker_done: + { + // Store folder of first filename as context. + store_folder(mContext, getFolder()); + finish(); + } + } +} + +void AIFilePicker::abort_impl(void) +{ +} + +void AIFilePicker::finish_impl(void) +{ + mPluginManager = NULL; // This deletes the plugin, since mPluginManager is a LLPointer. + mFilter.clear(); // Check that open is called before calling run (again). +} + +// This function is called when a new message is received from the plugin. +// We get here when calling mPluginManager->update() in the first line of +// AIFilePicker::multiplex_impl. +// +// Note that we can't call finish() or abort() directly in this function, +// as that deletes mPluginManager and we're using the plugin manager +// right now (to receive this message)! +void AIFilePicker::receivePluginMessage(const LLPluginMessage &message) +{ + std::string message_class = message.getClass(); + + if (message_class == LLPLUGIN_MESSAGE_CLASS_BASIC) + { + std::string message_name = message.getName(); + if (message_name == "canceled") + { + set_state(AIFilePicker_canceled); + } + else if (message_name == "done") + { + LLSD filenames = message.getValueLLSD("filenames"); + mFilenames.clear(); + for(LLSD::array_iterator filename = filenames.beginArray(); filename != filenames.endArray(); ++filename) + { + mFilenames.push_back(*filename); + } + set_state(AIFilePicker_done); + } + else + { + LL_WARNS("Plugin") << "Unknown " << message_class << " class message: " << message_name << LL_ENDL; + } + } +} + +std::string const& AIFilePicker::getFilename(void) const +{ + // Only call this function after the AIFilePicker finished successfully without being canceled. + llassert_always(!mFilenames.empty()); + // This function returns the first filename in the case that more than one was selected. + return mFilenames[0]; +} + +std::string AIFilePicker::getFolder(void) const +{ + // Return the folder of the first filename. + return gDirUtilp->getDirName(getFilename()); +} + diff --git a/indra/newview/statemachine/aifilepicker.h b/indra/newview/statemachine/aifilepicker.h new file mode 100644 index 000000000..008afb1d7 --- /dev/null +++ b/indra/newview/statemachine/aifilepicker.h @@ -0,0 +1,160 @@ +/** + * @file aifilepicker.h + * @brief File picker State machine + * + * Copyright (c) 2010, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * 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. + * + * CHANGELOG + * and additional copyright holders. + * + * 02/12/2010 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AIFILEPICKER_H +#define AIFILEPICKER_H + +#include "aistatemachine.h" +#include "llpluginclassmedia.h" +#include "../llviewermedia.h" +#include + +enum ELoadFilter +{ + FFLOAD_ALL, + FFLOAD_WAV, + FFLOAD_IMAGE, + FFLOAD_ANIM, + FFLOAD_XML, + FFLOAD_SLOBJECT, + FFLOAD_RAW, + FFLOAD_TEXT +}; + +enum ESaveFilter +{ + FFSAVE_ALL, + FFSAVE_WAV, + FFSAVE_TGA, + FFSAVE_BMP, + FFSAVE_AVI, + FFSAVE_ANIM, + FFSAVE_XML, + FFSAVE_COLLADA, + FFSAVE_RAW, + FFSAVE_J2C, + FFSAVE_PNG, + FFSAVE_JPEG, + FFSAVE_HPA, + FFSAVE_TEXT, + FFSAVE_LSL +}; + +// A file picker state machine. +// +// Before calling run(), call open() to pass needed parameters. +// +// When the state machine finishes, call isCanceled to check +// whether or not getFilename and getFolder will be valid. +// +// Objects of this type can be reused multiple times, see +// also the documentation of AIStateMachine. +class AIFilePicker : public AIStateMachine { +public: + AIFilePicker(void); + + // The starting directory that the user will be in when the file picker opens + // will be the same as the directory used the last time the file picker was + // opened with the same context. If the file picker was never opened before + // with the given context, the starting directory will be set to default_path + // unless that is the empty string, in which case it will be equal to the + // directory used the last time the filepicker was opened with context "savefile". + void open(std::string const& filename, ESaveFilter filter = FFSAVE_ALL, std::string const& default_path = "", std::string const& context = "savefile"); + void open(ELoadFilter filter = FFLOAD_ALL, std::string const& default_path = "", std::string const& context = "openfile", bool multiple = false); + + bool isCanceled(void) const { return mCanceled; } + std::string const& getFilename(void) const; + std::string getFolder(void) const; + std::vector const& getFilenames(void) const { return mFilenames; } + +private: + friend class AIPluginFilePicker; + + // This is called from AIPluginFilePicker::receivePluginMessage, see below. + void receivePluginMessage(LLPluginMessage const& message); + +public: + enum open_type { save, load, load_multiple }; + +private: + LLPointer mPluginManager; //!< Pointer to the plugin manager. + // FIXME: this should be a separate, thread-safe singleton. + typedef std::map context_map_type; //!< Type of mContextMap. + context_map_type mContextMap; //!< Map context (ie, "snapshot" or "image") to last used folder. + std::string mContext; //!< Some key to indicate the context (remembers the folder per key). + + // Input variables (cache variable between call to open and run). + open_type mOpenType; //!< Set to whether opening a filepicker to select for saving one file, for loading one file, or loading multiple files. + std::string mFilter; //!< A keyword indicating which file types (extensions) we want to see. + std::string mFilename; //!< When saving: proposed filename. + std::string mFolder; //!< Initial folder to start in. + // Output variables: + bool mCanceled; //!< True if the file picker was canceled or closed. + std::vector mFilenames; //!< Filesnames. + + // Store a folder for the given context. + void store_folder(std::string const& context, std::string const& folder); + // Return the last folder stored for 'context', or default_path if none, or context "savefile" if empty, or $HOME if none. + std::string get_folder(std::string const& default_path, std::string const& context); + +protected: + // Handle initializing the object. + /*virtual*/ void initialize_impl(void); + + // Handle mRunState. + /*virtual*/ void multiplex_impl(void); + + // Handle aborting from current bs_run state. + /*virtual*/ void abort_impl(void); + + // Handle cleaning up from initialization (or post abort) state. + /*virtual*/ void finish_impl(void); + + // Implemenation of state_str for run states. + /*virtual*/ char const* state_str_impl(state_type run_state) const; +}; + +// Viewer-side helper class for objects with a lifetime equal to the +// plugin child process (SLPlugin). Don't use directly. +class AIPluginFilePicker : public LLPluginClassBasic { + LOG_CLASS(AIPluginFilePicker); +public: + AIPluginFilePicker(AIFilePicker* state_machine) : mStateMachine(state_machine) { } + + static std::string launcher_name(void) { return gDirUtilp->getLLPluginLauncher(); } + static char const* plugin_basename(void) { return "basic_plugin_filepicker"; } + + /*virtual*/ void receivePluginMessage(LLPluginMessage const& message) { mStateMachine->receivePluginMessage(message); } + +private: + AIFilePicker* mStateMachine; +}; + +#endif diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index a663389ea..42859efbe 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -220,13 +220,18 @@ class WindowsManifest(ViewerManifest): # self.path("openjpeg.dll") # self.end_prefix() + # Plugins - FilePicker + if self.prefix(src='../plugins/filepicker/%s' % self.args['configuration'], dst="llplugin"): + self.path("basic_plugin_filepicker.dll") + self.end_prefix() + # Media plugins - QuickTime - if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): + if self.prefix(src='../plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): self.path("media_plugin_quicktime.dll") self.end_prefix() # Media plugins - WebKit/Qt - if self.prefix(src='../media_plugins/webkit/%s' % self.args['configuration'], dst="llplugin"): + if self.prefix(src='../plugins/webkit/%s' % self.args['configuration'], dst="llplugin"): self.path("media_plugin_webkit.dll") self.end_prefix() @@ -533,8 +538,9 @@ class DarwinManifest(ViewerManifest): # plugins if self.prefix(src="", dst="llplugin"): - self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") - self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") + self.path("../plugins/filepicker/" + self.args['configuration'] + "/basic_plugin_filepicker.dylib", "basic_plugin_filepicker.dylib") + self.path("../plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") + self.path("../plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib") self.end_prefix("llplugin") @@ -689,8 +695,9 @@ class LinuxManifest(ViewerManifest): # plugins if self.prefix(src="", dst="bin/llplugin"): - self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") - self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so") + self.path("../plugins/filepicker/libbasic_plugin_filepicker.so", "libbasic_plugin_filepicker.so") + self.path("../plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") + self.path("../plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so") self.end_prefix("bin/llplugin") # Per platform MIME config on the cheap. See SNOW-307 / DEV-41388 diff --git a/indra/plugins/filepicker/basic_plugin_filepicker.cpp b/indra/plugins/filepicker/basic_plugin_filepicker.cpp new file mode 100644 index 000000000..bd415c64a --- /dev/null +++ b/indra/plugins/filepicker/basic_plugin_filepicker.cpp @@ -0,0 +1,243 @@ +/** + * @file plugin_filepicker.cpp + * @brief Plugin that runs a file picker. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#include "linden_common.h" +#include "basic_plugin_base.h" +#include "llfilepicker.h" + +class FilepickerPlugin : public BasicPluginBase +{ + public: + FilepickerPlugin(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); + ~FilepickerPlugin(); + + /*virtual*/ void receiveMessage(char const* message_string); + + private: + bool init(); +}; + +FilepickerPlugin::FilepickerPlugin(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) : + BasicPluginBase(send_message_function, plugin_instance) +{ +} + +FilepickerPlugin::~FilepickerPlugin() +{ +} + +static LLFilePicker::ESaveFilter str2savefilter(std::string const& filter) +{ + // Complement of AIFilePicker::open(std::string const& filename, ESaveFilter filter, std::string const& folder) + if (filter == "wav") + return LLFilePicker::FFSAVE_WAV; + else if (filter == "tga") + return LLFilePicker::FFSAVE_TGA; + else if (filter == "bmp") + return LLFilePicker::FFSAVE_BMP; + else if (filter == "avi") + return LLFilePicker::FFSAVE_AVI; + else if (filter == "anim") + return LLFilePicker::FFSAVE_ANIM; +#ifdef _CORY_TESTING + else if (filter == "geometry") + return LLFilePicker::FFSAVE_GEOMETRY; +#endif + else if (filter == "xml") + return LLFilePicker::FFSAVE_XML; + else if (filter == "collada") + return LLFilePicker::FFSAVE_COLLADA; + else if (filter == "raw") + return LLFilePicker::FFSAVE_RAW; + else if (filter == "j2c") + return LLFilePicker::FFSAVE_J2C; + else if (filter == "png") + return LLFilePicker::FFSAVE_PNG; + else if (filter == "jpeg") + return LLFilePicker::FFSAVE_JPEG; + else if (filter == "hpa") + return LLFilePicker::FFSAVE_HPA; + else if (filter == "text") + return LLFilePicker::FFSAVE_TEXT; + else if (filter == "lsl") + return LLFilePicker::FFSAVE_LSL; + else + return LLFilePicker::FFSAVE_ALL; +} + +static LLFilePicker::ELoadFilter str2loadfilter(std::string const& filter) +{ + // Complement of AIFilePicker::open(ELoadFilter filter, std::string const& folder) + if (filter == "wav") + return LLFilePicker::FFLOAD_WAV; + else if (filter == "image") + return LLFilePicker::FFLOAD_IMAGE; + else if (filter == "anim") + return LLFilePicker::FFLOAD_ANIM; +#ifdef _CORY_TESTING + else if (filter == "geometry") + return LLFilePicker::FFLOAD_GEOMETRY; +#endif + else if (filter == "xml") + return LLFilePicker::FFLOAD_XML; + else if (filter == "slobject") + return LLFilePicker::FFLOAD_SLOBJECT; + else if (filter == "raw") + return LLFilePicker::FFLOAD_RAW; + else if (filter == "text") + return LLFilePicker::FFLOAD_TEXT; + else + return LLFilePicker::FFLOAD_ALL; +} + +// This is the SLPlugin process. +// This is part of the loaded DSO. +// +// This function is called from LLPluginInstance::sendMessage +// for messages received from the viewer (that are not 'internal'). +void FilepickerPlugin::receiveMessage(char const* message_string) +{ + LLPluginMessage message_in; + + if (message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + + if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if (message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_BASIC] = LLPLUGIN_MESSAGE_CLASS_BASIC_VERSION; + message.setValueLLSD("versions", versions); + + std::string plugin_version = "Filepicker Plugin, version 1.0.0.0"; + message.setValue("plugin_version", plugin_version); + sendMessage(message); + } + else if (message_name == "idle") + { + // This whole message should not have existed imho -- Aleric + } + else + { + std::cerr << "FilepickerPlugin::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if (message_class == LLPLUGIN_MESSAGE_CLASS_BASIC) + { + // This message should be sent at most once per SLPlugin invokation. + if (message_name == "initialization") + { + LLSD dictionary = message_in.getValueLLSD("dictionary"); + for (LLSD::map_iterator iter = dictionary.beginMap(); iter != dictionary.endMap(); ++iter) + { + translation::add(iter->first, iter->second.asString()); + } + if (message_in.hasValue("window_id")) + { + unsigned long window_id = strtoul(message_in.getValue("window_id").c_str(), NULL, 16); + LLFilePicker::instance().setWindowID(window_id); + } + } + // This message may theoretically be repeated (though currently the plugin is terminated after returning). + else if (message_name == "open") + { + std::string type = message_in.getValue("type"); + std::string filter = message_in.getValue("filter"); + std::string folder = message_in.getValue("folder"); + + bool canceled; + if (type == "save") + { + canceled = !LLFilePicker::instance().getSaveFile(str2savefilter(filter), message_in.getValue("default"), folder); + } + else if (type == "load") + { + canceled = !LLFilePicker::instance().getLoadFile(str2loadfilter(filter), folder); + } + else // type == "load_multiple" + { + canceled = !LLFilePicker::instance().getMultipleLoadFiles(str2loadfilter(filter), folder); + } + if (canceled) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "canceled"); + message.setValue("perseus", "unblock"); + sendMessage(message); + } + else + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "done"); + message.setValue("perseus", "unblock"); + LLSD filenames; + for (std::string filename = LLFilePicker::instance().getFirstFile(); !filename.empty(); filename = LLFilePicker::instance().getNextFile()) + { + filenames.append(filename); + } + message.setValueLLSD("filenames", filenames); + sendMessage(message); + } + } + else + { + std::cerr << "FilepickerPlugin::receiveMessage: unknown basic message: " << message_name << std::endl; + } + } + else + { + std::cerr << "FilepickerPlugin::receiveMessage: unknown message class: " << message_class << std::endl; + } + } +} + +bool FilepickerPlugin::init(void) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "name_text"); + message.setValue("name", "Filepicker Plugin"); + sendMessage(message); + + return true; +} + +int create_plugin(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance, BasicPluginBase** plugin_object) +{ + *plugin_object = new FilepickerPlugin(send_message_function, plugin_instance); + return 0; +} + From 784fdd4f379dc340a94c4ab88e6b15a9ce3495f7 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 6 May 2011 15:00:50 +0200 Subject: [PATCH 06/87] Split plugin classes and derive AIFilePicker from BasicPluginBase (part 2). This commit contains all changes to indra/llplugin. Since there were no differences at all between Singularity and imprudence before this patch, it's a perfect port. --- indra/llplugin/CMakeLists.txt | 2 + indra/llplugin/llpluginclassbasic.cpp | 189 +++++++++++++++++++++++ indra/llplugin/llpluginclassbasic.h | 126 +++++++++++++++ indra/llplugin/llpluginclassmedia.cpp | 163 +++---------------- indra/llplugin/llpluginclassmedia.h | 83 ++-------- indra/llplugin/llplugininstance.cpp | 33 ++-- indra/llplugin/llplugininstance.h | 14 +- indra/llplugin/llpluginmessage.h | 6 +- indra/llplugin/llpluginmessageclasses.h | 3 + indra/llplugin/llpluginprocesschild.cpp | 28 +++- indra/llplugin/llpluginprocessparent.cpp | 35 +++++ indra/llplugin/llpluginprocessparent.h | 1 + 12 files changed, 457 insertions(+), 226 deletions(-) create mode 100644 indra/llplugin/llpluginclassbasic.cpp create mode 100644 indra/llplugin/llpluginclassbasic.h diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index 7a7f4e583..270a95d54 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -24,6 +24,7 @@ include_directories( ) set(llplugin_SOURCE_FILES + llpluginclassbasic.cpp llpluginclassmedia.cpp llplugincookiestore.cpp llplugininstance.cpp @@ -37,6 +38,7 @@ set(llplugin_SOURCE_FILES set(llplugin_HEADER_FILES CMakeLists.txt + llpluginclassbasic.h llpluginclassmedia.h llpluginclassmediaowner.h llplugincookiestore.h diff --git a/indra/llplugin/llpluginclassbasic.cpp b/indra/llplugin/llpluginclassbasic.cpp new file mode 100644 index 000000000..0567b157f --- /dev/null +++ b/indra/llplugin/llpluginclassbasic.cpp @@ -0,0 +1,189 @@ +/** + * @file llpluginclassbasic.cpp + * @brief LLPluginClassBasic handles a plugin which knows about the "basic" message class. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#include "linden_common.h" +#include "indra_constants.h" + +#include "llpluginclassbasic.h" +#include "llpluginmessageclasses.h" + +LLPluginClassBasic::LLPluginClassBasic(void) : mPlugin(NULL), mDeleteOK(true) +{ + // Note that this only initializes the base class, the derived class doesn't exist yet! + // Derived classes must therefore call their own reset_impl() from their constructor. + reset(); +} + +LLPluginClassBasic::~LLPluginClassBasic() +{ + llassert_always(mDeleteOK); + delete mPlugin; +} + +bool LLPluginClassBasic::init(std::string const& launcher_filename, std::string const& plugin_filename, bool debug) +{ + LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; + LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; + + mPlugin = new LLPluginProcessParent(this); + mPlugin->setSleepTime(mSleepTime); + + mPlugin->init(launcher_filename, plugin_filename, debug); + + return init_impl(); +} + +void LLPluginClassBasic::reset() +{ + if (mPlugin != NULL) + { + delete mPlugin; + mPlugin = NULL; + } + mSleepTime = 1.0f / 50.0f; + mPriority = PRIORITY_NORMAL; + reset_impl(); +} + +void LLPluginClassBasic::idle(void) +{ + if(mPlugin) + { + mPlugin->idle(); + } + + idle_impl(); + + if(mPlugin && mPlugin->isRunning()) + { + // Send queued messages + while(!mSendQueue.empty()) + { + LLPluginMessage message = mSendQueue.front(); + mSendQueue.pop(); + mPlugin->sendMessage(message); + } + } +} + +char const* LLPluginClassBasic::priorityToString(EPriority priority) +{ + const char* result = "UNKNOWN"; + switch(priority) + { + case PRIORITY_SLEEP: result = "sleep"; break; + case PRIORITY_LOW: result = "low"; break; + case PRIORITY_NORMAL: result = "normal"; break; + case PRIORITY_HIGH: result = "high"; break; + } + + return result; +} + +void LLPluginClassBasic::setPriority(EPriority priority) +{ + if (mPriority != priority) + { + mPriority = priority; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "set_priority"); + + std::string priority_string = priorityToString(priority); + switch(priority) + { + case PRIORITY_SLEEP: + mSleepTime = 1.0f; + break; + case PRIORITY_LOW: + mSleepTime = 1.0f / 25.0f; + break; + case PRIORITY_NORMAL: + mSleepTime = 1.0f / 50.0f; + break; + case PRIORITY_HIGH: + mSleepTime = 1.0f / 100.0f; + break; + } + + message.setValue("priority", priority_string); + sendMessage(message); + + if(mPlugin) + { + mPlugin->setSleepTime(mSleepTime); + } + + LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; + + priorityChanged(mPriority); + } +} + +/* virtual */ +void LLPluginClassBasic::receivePluginMessage(const LLPluginMessage &message) +{ + std::string message_class = message.getClass(); + + if (message_class == LLPLUGIN_MESSAGE_CLASS_BASIC) + { + std::string message_name = message.getName(); + + // This class hasn't defined any incoming messages yet. +// if (message_name == "message_name") +// { +// } +// else + { + LL_WARNS("Plugin") << "Unknown " << message_class << " class message: " << message_name << LL_ENDL; + } + } +} + +// This is the viewer process (the parent process) +// +// Call this function to send a message to a plugin. +// It calls LLPluginProcessParent::sendMessage. +void LLPluginClassBasic::sendMessage(LLPluginMessage const& message) +{ + if(mPlugin && mPlugin->isRunning()) + { + mPlugin->sendMessage(message); + } + else + { + // The plugin isn't set up yet -- queue this message to be sent after initialization. + mSendQueue.push(message); + } +} diff --git a/indra/llplugin/llpluginclassbasic.h b/indra/llplugin/llpluginclassbasic.h new file mode 100644 index 000000000..a9e4dba46 --- /dev/null +++ b/indra/llplugin/llpluginclassbasic.h @@ -0,0 +1,126 @@ +/** + * @file llpluginclassbasic.h + * @brief LLPluginClassBasic handles interaction with a plugin which knows about the "basic" message class. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINCLASSBASIC_H +#define LL_LLPLUGINCLASSBASIC_H + +#include "llerror.h" // Needed for LOG_CLASS +#include "stdtypes.h" // Needed for F64 +#include "llpluginprocessparent.h" +#include "llpluginclassmediaowner.h" +#include "llpluginmessage.h" +#include +#include + +class LLPluginClassBasic : public LLPluginProcessParentOwner +{ + LOG_CLASS(LLPluginClassBasic); + +public: + LLPluginClassBasic(void); + virtual ~LLPluginClassBasic(); + + // Local initialization, called when creating a plugin process. Return true if successful. + bool init(std::string const& launcher_filename, std::string const& plugin_filename, bool debug); + + // Undoes everything init did. Called when destroying a plugin process. + void reset(void); + + void idle(void); + + // Send message to the plugin, either queueing or sending directly. + void sendMessage(LLPluginMessage const& message); + + // "Loading" means uninitialized or any state prior to fully running (processing commands). + bool isPluginLoading(void) const { return mPlugin ? mPlugin->isLoading() : false; } + + // "Running" means the steady state -- i.e. processing messages. + bool isPluginRunning(void) const { return mPlugin ? mPlugin->isRunning() : false; } + + // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally). + bool isPluginExited(void) const { return mPlugin ? mPlugin->isDone() : false; } + + std::string getPluginVersion() const { return mPlugin ? mPlugin->getPluginVersion() : std::string(""); } + + bool getDisableTimeout() const { return mPlugin ? mPlugin->getDisableTimeout() : false; } + + void setDisableTimeout(bool disable) { if (mPlugin) mPlugin->setDisableTimeout(disable); } + + enum EPriority + { + PRIORITY_SLEEP, // Sleep 1 second every message. + PRIORITY_LOW, // Sleep 1/25 second. + PRIORITY_NORMAL, // Sleep 1/50 second. + PRIORITY_HIGH // Sleep 1/100 second. + }; + + static char const* priorityToString(EPriority priority); + void setPriority(EPriority priority); + +protected: + EPriority mPriority; + LLPluginProcessParent* mPlugin; + +private: + F64 mSleepTime; + std::queue mSendQueue; // Used to queue messages while the plugin initializes. + +protected: + // Called as last function when calling 'init()'. + virtual bool init_impl(void) { return true; } + + // Called as last function when calling 'reset()'. + virtual void reset_impl(void) { } + + // Called from idle() before flushing messages to the plugin. + virtual void idle_impl(void) { } + + // Called from setPriority. + virtual void priorityChanged(EPriority priority) { } + + // Inherited from LLPluginProcessParentOwner. + /*virtual*/ void receivePluginMessage(LLPluginMessage const&); + + //-------------------------------------- + // Debug use only + // +private: + bool mDeleteOK; + +public: + void setDeleteOK(bool flag) { mDeleteOK = flag; } +}; + +#endif // LL_LLPLUGINCLASSBASIC_H diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 85241bec1..2bbad6011 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -54,49 +54,24 @@ static int nextPowerOf2( int value ) return next_power_of_2; } -LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) +LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner): mOwner(owner) { - mOwner = owner; - mPlugin = NULL; - reset(); - - //debug use - mDeleteOK = true ; + // Most initialization is done with reset_impl(), which we call here + // in order to avoid code duplication. + LLPluginClassMedia::reset_impl(); } - -LLPluginClassMedia::~LLPluginClassMedia() +bool LLPluginClassMedia::init_impl(void) { - llassert_always(mDeleteOK) ; - reset(); -} - -bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug) -{ - LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; - LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; - - mPlugin = new LLPluginProcessParent(this); - mPlugin->setSleepTime(mSleepTime); - // Queue up the media init message -- it will be sent after all the currently queued messages. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); sendMessage(message); - - mPlugin->init(launcher_filename, plugin_filename, debug); return true; } - -void LLPluginClassMedia::reset() +void LLPluginClassMedia::reset_impl(void) { - if(mPlugin != NULL) - { - delete mPlugin; - mPlugin = NULL; - } - mTextureParamsReceived = false; mRequestedTextureDepth = 0; mRequestedTextureInternalFormat = 0; @@ -125,14 +100,12 @@ void LLPluginClassMedia::reset() mDirtyRect = LLRect::null; mAutoScaleMedia = false; mRequestedVolume = 1.0f; - mPriority = PRIORITY_NORMAL; mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; mAllowDownsample = false; mPadding = 0; mLastMouseX = 0; mLastMouseY = 0; mStatus = LLPluginClassMediaOwner::MEDIA_NONE; - mSleepTime = 1.0f / 100.0f; mCanCut = false; mCanCopy = false; mCanPaste = false; @@ -158,13 +131,8 @@ void LLPluginClassMedia::reset() mLoadedDuration = 0.0f; } -void LLPluginClassMedia::idle(void) +void LLPluginClassMedia::idle_impl(void) { - if(mPlugin) - { - mPlugin->idle(); - } - if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked())) { // Can't process a size change at this time @@ -260,17 +228,6 @@ void LLPluginClassMedia::idle(void) LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; } } - - if(mPlugin && mPlugin->isRunning()) - { - // Send queued messages - while(!mSendQueue.empty()) - { - LLPluginMessage message = mSendQueue.front(); - mSendQueue.pop(); - mPlugin->sendMessage(message); - } - } } int LLPluginClassMedia::getTextureWidth() const @@ -295,18 +252,16 @@ unsigned char* LLPluginClassMedia::getBitsData() void LLPluginClassMedia::setSize(int width, int height) { - if((width > 0) && (height > 0)) + if (width <= 0 || height <= 0) + { + width = height = -1; + } + if (mSetMediaWidth != width || mSetMediaHeight != height) { mSetMediaWidth = width; mSetMediaHeight = height; + setSizeInternal(); } - else - { - mSetMediaWidth = -1; - mSetMediaHeight = -1; - } - - setSizeInternal(); } void LLPluginClassMedia::setSizeInternal(void) @@ -335,7 +290,7 @@ void LLPluginClassMedia::setSizeInternal(void) { switch(mPriority) { - case PRIORITY_SLIDESHOW: + case PRIORITY_SLEEP: case PRIORITY_LOW: // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) @@ -584,71 +539,10 @@ void LLPluginClassMedia::loadURI(const std::string &uri) sendMessage(message); } -const char* LLPluginClassMedia::priorityToString(EPriority priority) +void LLPluginClassMedia::priorityChanged(EPriority priority) { - const char* result = "UNKNOWN"; - switch(priority) - { - case PRIORITY_UNLOADED: result = "unloaded"; break; - case PRIORITY_STOPPED: result = "stopped"; break; - case PRIORITY_HIDDEN: result = "hidden"; break; - case PRIORITY_SLIDESHOW: result = "slideshow"; break; - case PRIORITY_LOW: result = "low"; break; - case PRIORITY_NORMAL: result = "normal"; break; - case PRIORITY_HIGH: result = "high"; break; - } - - return result; -} - -void LLPluginClassMedia::setPriority(EPriority priority) -{ - if(mPriority != priority) - { - mPriority = priority; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); - - std::string priority_string = priorityToString(priority); - switch(priority) - { - case PRIORITY_UNLOADED: - mSleepTime = 1.0f; - break; - case PRIORITY_STOPPED: - mSleepTime = 1.0f; - break; - case PRIORITY_HIDDEN: - mSleepTime = 1.0f; - break; - case PRIORITY_SLIDESHOW: - mSleepTime = 1.0f; - break; - case PRIORITY_LOW: - mSleepTime = 1.0f / 25.0f; - break; - case PRIORITY_NORMAL: - mSleepTime = 1.0f / 50.0f; - break; - case PRIORITY_HIGH: - mSleepTime = 1.0f / 100.0f; - break; - } - - message.setValue("priority", priority_string); - - sendMessage(message); - - if(mPlugin) - { - mPlugin->setSleepTime(mSleepTime); - } - - LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; - - // This may affect the calculated size, so recalculate it here. - setSizeInternal(); - } + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); } void LLPluginClassMedia::setLowPrioritySizeLimit(int size) @@ -657,7 +551,6 @@ void LLPluginClassMedia::setLowPrioritySizeLimit(int size) if(mLowPrioritySizeLimit != power) { mLowPrioritySizeLimit = power; - // This may affect the calculated size, so recalculate it here. setSizeInternal(); } @@ -726,7 +619,11 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { std::string message_class = message.getClass(); - if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + if (message_class == LLPLUGIN_MESSAGE_CLASS_BASIC) + { + LLPluginClassBasic::receivePluginMessage(message); + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) { std::string message_name = message.getName(); if(message_name == "texture_params") @@ -1003,10 +900,9 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) // } // else { - LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + LL_WARNS("Plugin") << "Unknown " << message_class << " class message: " << message_name << LL_ENDL; } } - } /* virtual */ @@ -1029,19 +925,6 @@ void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) } } -void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) -{ - if(mPlugin && mPlugin->isRunning()) - { - mPlugin->sendMessage(message); - } - else - { - // The plugin isn't set up yet -- queue this message to be sent after initialization. - mSendQueue.push(message); - } -} - //////////////////////////////////////////////////////////// // MARK: media_browser class functions bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 0004971c6..1996c6588 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -36,29 +36,17 @@ #ifndef LL_LLPLUGINCLASSMEDIA_H #define LL_LLPLUGINCLASSMEDIA_H +#include "llpluginclassbasic.h" #include "llgltypes.h" -#include "llpluginprocessparent.h" #include "llrect.h" -#include "llpluginclassmediaowner.h" -#include #include "v4color.h" -class LLPluginClassMedia : public LLPluginProcessParentOwner +class LLPluginClassMedia : public LLPluginClassBasic { LOG_CLASS(LLPluginClassMedia); + public: LLPluginClassMedia(LLPluginClassMediaOwner *owner); - virtual ~LLPluginClassMedia(); - - // local initialization, called by the media manager when creating a source - virtual bool init(const std::string &launcher_filename, - const std::string &plugin_filename, - bool debug); - - // undoes everything init() didm called by the media manager when destroying a source - virtual void reset(); - - void idle(void); // All of these may return 0 or an actual valid value. // Callers need to check the return for 0, and not use the values in that case. @@ -101,22 +89,22 @@ public: bool getDirty(LLRect *dirty_rect = NULL); void resetDirty(void); - typedef enum + enum EMouseEventType { MOUSE_EVENT_DOWN, MOUSE_EVENT_UP, MOUSE_EVENT_MOVE, MOUSE_EVENT_DOUBLE_CLICK - }EMouseEventType; + }; void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers); - typedef enum + enum EKeyEventType { KEY_EVENT_DOWN, KEY_EVENT_UP, KEY_EVENT_REPEAT - }EKeyEventType; + }; bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); @@ -127,39 +115,13 @@ public: void loadURI(const std::string &uri); - // "Loading" means uninitialized or any state prior to fully running (processing commands) - bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; - - // "Running" means the steady state -- i.e. processing messages - bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; - - // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) - bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; - - std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; - - bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; - void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; - // Inherited from LLPluginProcessParentOwner /* virtual */ void receivePluginMessage(const LLPluginMessage &message); /* virtual */ void pluginLaunchFailed(); /* virtual */ void pluginDied(); + // Inherited from LLPluginClassBasic + /* virtual */ void priorityChanged(EPriority priority); - - typedef enum - { - PRIORITY_UNLOADED, // media plugin isn't even loaded. - PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. - PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. - PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently - PRIORITY_LOW, // media is in the distance, may be rendered at reduced size - PRIORITY_NORMAL, // normal (default) priority - PRIORITY_HIGH // media has user focus and/or is taking up most of the screen - }EPriority; - - static const char* priorityToString(EPriority priority); - void setPriority(EPriority priority); void setLowPrioritySizeLimit(int size); F64 getCPUUsage(); @@ -256,17 +218,18 @@ public: void initializeUrlHistory(const LLSD& url_history); protected: - - LLPluginClassMediaOwner *mOwner; + virtual bool init_impl(void); + virtual void reset_impl(void); + virtual void idle_impl(void); // Notify this object's owner that an event has occurred. void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); - void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. - std::queue mSendQueue; // Used to queue messages while the plugin initializes. - void setSizeInternal(void); +protected: + LLPluginClassMediaOwner *mOwner; + bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true S32 mRequestedTextureDepth; LLGLenum mRequestedTextureInternalFormat; @@ -313,16 +276,11 @@ protected: float mRequestedVolume; - // Priority of this media stream - EPriority mPriority; int mLowPrioritySizeLimit; bool mAllowDownsample; int mPadding; - - LLPluginProcessParent *mPlugin; - LLRect mDirtyRect; std::string translateModifiers(MASK modifiers); @@ -332,8 +290,6 @@ protected: int mLastMouseY; LLPluginClassMediaOwner::EMediaStatus mStatus; - - F64 mSleepTime; bool mCanCut; bool mCanCopy; @@ -363,15 +319,6 @@ protected: F64 mDuration; F64 mCurrentRate; F64 mLoadedDuration; - -//-------------------------------------- - //debug use only - // -private: - bool mDeleteOK ; -public: - void setDeleteOK(bool flag) { mDeleteOK = flag ;} -//-------------------------------------- }; #endif // LL_LLPLUGINCLASSMEDIA_H diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp index 3a1395cd2..914eadcce 100644 --- a/indra/llplugin/llplugininstance.cpp +++ b/indra/llplugin/llplugininstance.cpp @@ -55,8 +55,8 @@ const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoin */ LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) : mDSOHandle(NULL), - mPluginUserData(NULL), - mPluginSendMessageFunction(NULL) + mPluginObject(NULL), + mReceiveMessageFunction(NULL) { mOwner = owner; } @@ -109,9 +109,9 @@ int LLPluginInstance::load(std::string &plugin_file) if(result == APR_SUCCESS) { - result = init_function(staticReceiveMessage, (void*)this, &mPluginSendMessageFunction, &mPluginUserData); + result = init_function(&LLPluginInstance::staticReceiveMessage, this, &mReceiveMessageFunction, &mPluginObject); - if(result != APR_SUCCESS) + if(result != 0) { LL_WARNS("Plugin") << "call to init function failed with error " << result << LL_ENDL; } @@ -120,6 +120,14 @@ int LLPluginInstance::load(std::string &plugin_file) return (int)result; } +// This is the SLPlugin process (the child process). +// This is not part of a DSO. +// +// This function is called from LLPluginProcessChild::receiveMessageRaw +// for messages received from the viewer that are not internal. +// +// It sends the message to the DSO by calling the registered 'received' +// function (for example, FilepickerPlugin::receiveMessage). /** * Sends a message to the plugin. * @@ -127,10 +135,10 @@ int LLPluginInstance::load(std::string &plugin_file) */ void LLPluginInstance::sendMessage(const std::string &message) { - if(mPluginSendMessageFunction) + if(mReceiveMessageFunction) { LL_DEBUGS("Plugin") << "sending message to plugin: \"" << message << "\"" << LL_ENDL; - mPluginSendMessageFunction(message.c_str(), &mPluginUserData); + mReceiveMessageFunction(message.c_str(), &mPluginObject); } else { @@ -147,14 +155,19 @@ void LLPluginInstance::idle(void) } // static -void LLPluginInstance::staticReceiveMessage(const char *message_string, void **user_data) +void LLPluginInstance::staticReceiveMessage(char const* message_string, LLPluginInstance** self_ptr) { - // TODO: validate that the user_data argument is still a valid LLPluginInstance pointer + // TODO: validate that the self argument is still a valid LLPluginInstance pointer // we could also use a key that's looked up in a map (instead of a direct pointer) for safety, but that's probably overkill - LLPluginInstance *self = (LLPluginInstance*)*user_data; - self->receiveMessage(message_string); + (*self_ptr)->receiveMessage(message_string); } +// This is the SLPlugin process. +// This is not part of a DSO. +// +// This function is called by a loaded DSO (through a function pointer, it +// is called from BasicPluginBase::sendMessage) for messages it wants to +// send to the viewer. It calls LLPluginProcessChild::receivePluginMessage. /** * Plugin receives message from plugin loader shell. * diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h index 9cf6075ff..faa1cbb7f 100644 --- a/indra/llplugin/llplugininstance.h +++ b/indra/llplugin/llplugininstance.h @@ -51,6 +51,8 @@ public: virtual void receivePluginMessage(const std::string &message) = 0; }; +class BasicPluginBase; + /** * @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing. */ @@ -79,26 +81,28 @@ public: * @param[in] message_string Null-terminated C string * @param[in] user_data The opaque reference that the callee supplied during setup. */ - typedef void (*sendMessageFunction) (const char *message_string, void **user_data); + typedef void (*receiveMessageFunction)(char const* message_string, BasicPluginBase** plugin_object); + + typedef void (*sendMessageFunction)(char const* message_string, LLPluginInstance** plugin_instance); /** The signature of the plugin init function. TODO:DOC check direction (pluging loader shell to plugin?) * * @param[in] host_user_data Data from plugin loader shell. * @param[in] plugin_send_function Function for sending from the plugin loader shell to plugin. */ - typedef int (*pluginInitFunction) (sendMessageFunction host_send_func, void *host_user_data, sendMessageFunction *plugin_send_func, void **plugin_user_data); + typedef int (*pluginInitFunction)(sendMessageFunction send_message_function, LLPluginInstance* plugin_instance, receiveMessageFunction* receive_message_function, BasicPluginBase** plugin_object); /** Name of plugin init function */ static const char *PLUGIN_INIT_FUNCTION_NAME; private: - static void staticReceiveMessage(const char *message_string, void **user_data); + static void staticReceiveMessage(char const* message_string, LLPluginInstance** plugin_instance); void receiveMessage(const char *message_string); apr_dso_handle_t *mDSOHandle; - void *mPluginUserData; - sendMessageFunction mPluginSendMessageFunction; + BasicPluginBase* mPluginObject; + receiveMessageFunction mReceiveMessageFunction; LLPluginInstanceMessageListener *mOwner; }; diff --git a/indra/llplugin/llpluginmessage.h b/indra/llplugin/llpluginmessage.h index fe504c8b9..3c7b91750 100644 --- a/indra/llplugin/llpluginmessage.h +++ b/indra/llplugin/llpluginmessage.h @@ -99,8 +99,10 @@ public: // (this clears out all existing state before starting the parse) // Returns -1 on failure, otherwise returns the number of key/value pairs in the message. int parse(const std::string &message); - - + + // For debugging purposes. + friend std::ostream& operator<<(std::ostream& os, LLPluginMessage const& message) { return os << message.mMessage; } + private: LLSD mMessage; diff --git a/indra/llplugin/llpluginmessageclasses.h b/indra/llplugin/llpluginmessageclasses.h index 8812a1676..b61720ab4 100644 --- a/indra/llplugin/llpluginmessageclasses.h +++ b/indra/llplugin/llpluginmessageclasses.h @@ -48,6 +48,9 @@ #define LLPLUGIN_MESSAGE_CLASS_BASE "base" #define LLPLUGIN_MESSAGE_CLASS_BASE_VERSION "1.0" +#define LLPLUGIN_MESSAGE_CLASS_BASIC "basic" +#define LLPLUGIN_MESSAGE_CLASS_BASIC_VERSION "1.0" + #define LLPLUGIN_MESSAGE_CLASS_MEDIA "media" #define LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION "1.0" diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index d2238236f..2c47087ab 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -286,6 +286,11 @@ bool LLPluginProcessChild::isDone(void) return result; } +// This is the SLPlugin process. +// This is not part of a DSO. +// +// This function is called by SLPlugin to send a message (originating from +// SLPlugin itself) to the loaded DSO. It calls LLPluginInstance::sendMessage. void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) { if (mInstance) @@ -305,15 +310,26 @@ void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) } } +// This is the SLPlugin process (the child process). +// This is not part of a DSO. +// +// This function is called by SLPlugin to send 'message' to the viewer (the parent process). void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message) { std::string buffer = message.generate(); LL_DEBUGS("Plugin") << "Sending to parent: " << buffer << LL_ENDL; + // Write the serialized message to the pipe. writeMessageRaw(buffer); } +// This is the SLPlugin process (the child process). +// This is not part of a DSO. +// +// This function is called when the serialized message 'message' was received from the viewer. +// It parses the message and handles LLPLUGIN_MESSAGE_CLASS_INTERNAL. +// Other message classes are passed on to LLPluginInstance::sendMessage. void LLPluginProcessChild::receiveMessageRaw(const std::string &message) { // Incoming message from the TCP Socket @@ -449,7 +465,17 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message) } } -/* virtual */ +// This is the SLPlugin process. +// This is not part of a DSO. +// +// This function is called from LLPluginInstance::receiveMessage +// for messages from a loaded DSO that have to be passed to the +// viewer. +// +// It handles the base messages that are responses to messages sent by this +// class, and passes the rest on to LLPluginMessagePipeOwner::writeMessageRaw +// to be written to the pipe. +/* virtual */ void LLPluginProcessChild::receivePluginMessage(const std::string &message) { LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL; diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 2be917be6..35931426d 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -579,6 +579,9 @@ void LLPluginProcessParent::setSleepTime(F64 sleep_time, bool force_send) } } +// This is the viewer process (the parent process) +// +// This function is called to send a message to the plugin. void LLPluginProcessParent::sendMessage(const LLPluginMessage &message) { if(message.hasValue("blocking_response")) @@ -588,6 +591,11 @@ void LLPluginProcessParent::sendMessage(const LLPluginMessage &message) // reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked. mHeartbeat.setTimerExpirySec(mPluginLockupTimeout); } + if (message.hasValue("gorgon")) + { + // After this message it is expected that the plugin will not send any more messages for a long time. + mBlocked = true; + } std::string buffer = message.generate(); LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL; @@ -636,6 +644,16 @@ void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe) } } +apr_status_t LLPluginProcessParent::socketError(apr_status_t error) +{ + mSocketError = error; + if (APR_STATUS_IS_EPIPE(error)) + { + errorState(); + } + return error; +}; + //static void LLPluginProcessParent::dirtyPollSet() { @@ -852,6 +870,10 @@ void LLPluginProcessParent::servicePoll() } } +// This the viewer process (the parent process). +// +// This function is called when a message is received from a plugin. +// It parses the message and passes it on to LLPluginProcessParent::receiveMessage. void LLPluginProcessParent::receiveMessageRaw(const std::string &message) { LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL; @@ -863,6 +885,13 @@ void LLPluginProcessParent::receiveMessageRaw(const std::string &message) { mBlocked = true; } + if(parsed.hasValue("perseus")) + { + mBlocked = false; + + // reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked. + mHeartbeat.setTimerExpirySec(mPluginLockupTimeout); + } if(mPolledInput) { @@ -905,6 +934,12 @@ void LLPluginProcessParent::receiveMessageEarly(const LLPluginMessage &message) } } +// This is the viewer process (the parent process). +// +// This function is called for messages that have to +// be written to the plugin. +// Note that LLPLUGIN_MESSAGE_CLASS_INTERNAL messages +// are not sent to the plugin, but are handled here. void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) { std::string message_class = message.getClass(); diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index bba3643d6..a82407d05 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -99,6 +99,7 @@ public: /*virtual*/ void receiveMessageRaw(const std::string &message); /*virtual*/ void receiveMessageEarly(const LLPluginMessage &message); /*virtual*/ void setMessagePipe(LLPluginMessagePipe *message_pipe) ; + /*virtual*/ apr_status_t socketError(apr_status_t error); // This adds a memory segment shared with the client, generating a name for the segment. The name generated is guaranteed to be unique on the host. // The caller must call removeSharedMemory first (and wait until getSharedMemorySize returns 0 for the indicated name) before re-adding a segment with the same name. From 16cd4c5c4ba19a43cbc2757768ba4a5bb2e3647b Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 6 May 2011 16:08:24 +0200 Subject: [PATCH 07/87] Split plugin classes and derive AIFilePicker from BasicPluginBase (part 3). This commit deletes all indra/media_plugins and copied one-on-one the indra/plugins directory from my (imprudence) statemachine branch (which contains the AIFilePicker patch). git shows this as a lot of 'renamed' files because originally it was a rename. However, there are a lot of changes as well: it's both an upgrade to a newer plugin system (changes by LL) as well as an upgrade to my refactored plugin system with a file picker as plugin. Since this commit is a one-on-one copy, it disregards any changes that were in Singularity and not in imprudence in indra/media_plugins however. I will add those back in the next commit. --- indra/media_plugins/CMakeLists.txt | 15 - .../example/media_plugin_example.cpp | 412 ----- .../gstreamer010/llmediaimplgstreamer.h | 53 - .../llmediaimplgstreamer_syms.cpp | 167 -- .../gstreamer010/llmediaimplgstreamer_syms.h | 74 - .../llmediaimplgstreamer_syms_raw.inc | 51 - .../llmediaimplgstreamer_syms_rawv.inc | 5 - .../llmediaimplgstreamertriviallogging.h | 55 - .../webkit/dummy_volume_catcher.cpp | 58 - indra/media_plugins/webkit/volume_catcher.h | 54 - indra/plugins/CMakeLists.txt | 17 + indra/plugins/base_basic/CMakeLists.txt | 39 + .../plugins/base_basic/basic_plugin_base.cpp | 136 ++ .../base_basic/basic_plugin_base.exp} | 0 indra/plugins/base_basic/basic_plugin_base.h | 88 + .../base_media}/CMakeLists.txt | 11 +- .../base_media}/media_plugin_base.cpp | 70 +- .../plugins/base_media/media_plugin_base.exp | 2 + .../base_media}/media_plugin_base.h | 48 +- indra/plugins/example_basic/CMakeLists.txt | 68 + .../example_basic/basic_plugin_example.cpp | 123 ++ .../example_media}/CMakeLists.txt | 19 +- .../example_media/media_plugin_example.cpp | 490 ++++++ indra/plugins/filepicker/CMakeLists.txt | 81 + indra/plugins/filepicker/llfilepicker.cpp | 1414 +++++++++++++++++ indra/plugins/filepicker/llfilepicker.h | 231 +++ .../gstreamer010/CMakeLists.txt | 11 - .../gstreamer010/llmediaimplgstreamer.h | 60 + .../llmediaimplgstreamertriviallogging.h | 65 + .../llmediaimplgstreamervidplug.cpp | 201 ++- .../llmediaimplgstreamervidplug.h | 38 +- .../media_plugin_gstreamer010.cpp | 602 ++++--- .../quicktime/CMakeLists.txt | 3 +- .../quicktime/media_plugin_quicktime.cpp | 29 +- .../webkit/CMakeLists.txt | 20 +- indra/plugins/webkit/dummy_volume_catcher.cpp | 65 + .../webkit/linux_volume_catcher.cpp | 40 +- indra/plugins/webkit/linux_volume_catcher.h | 56 + .../webkit/linux_volume_catcher_pa_syms.inc | 0 .../linux_volume_catcher_paglib_syms.inc | 0 .../webkit/mac_volume_catcher.cpp | 37 +- .../webkit/media_plugin_webkit.cpp | 135 +- indra/plugins/webkit/volume_catcher.h | 61 + .../webkit/windows_volume_catcher.cpp | 39 +- 44 files changed, 3666 insertions(+), 1577 deletions(-) delete mode 100644 indra/media_plugins/CMakeLists.txt delete mode 100644 indra/media_plugins/example/media_plugin_example.cpp delete mode 100644 indra/media_plugins/gstreamer010/llmediaimplgstreamer.h delete mode 100644 indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp delete mode 100644 indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h delete mode 100644 indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc delete mode 100644 indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc delete mode 100644 indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h delete mode 100644 indra/media_plugins/webkit/dummy_volume_catcher.cpp delete mode 100644 indra/media_plugins/webkit/volume_catcher.h create mode 100644 indra/plugins/CMakeLists.txt create mode 100644 indra/plugins/base_basic/CMakeLists.txt create mode 100755 indra/plugins/base_basic/basic_plugin_base.cpp rename indra/{media_plugins/base/media_plugin_base.exp => plugins/base_basic/basic_plugin_base.exp} (100%) mode change 100755 => 100644 create mode 100755 indra/plugins/base_basic/basic_plugin_base.h rename indra/{media_plugins/base => plugins/base_media}/CMakeLists.txt (81%) rename indra/{media_plugins/base => plugins/base_media}/media_plugin_base.cpp (66%) mode change 100644 => 100755 create mode 100755 indra/plugins/base_media/media_plugin_base.exp rename indra/{media_plugins/base => plugins/base_media}/media_plugin_base.h (67%) mode change 100644 => 100755 create mode 100644 indra/plugins/example_basic/CMakeLists.txt create mode 100644 indra/plugins/example_basic/basic_plugin_example.cpp rename indra/{media_plugins/example => plugins/example_media}/CMakeLists.txt (83%) create mode 100755 indra/plugins/example_media/media_plugin_example.cpp create mode 100644 indra/plugins/filepicker/CMakeLists.txt create mode 100644 indra/plugins/filepicker/llfilepicker.cpp create mode 100644 indra/plugins/filepicker/llfilepicker.h rename indra/{media_plugins => plugins}/gstreamer010/CMakeLists.txt (82%) create mode 100755 indra/plugins/gstreamer010/llmediaimplgstreamer.h create mode 100755 indra/plugins/gstreamer010/llmediaimplgstreamertriviallogging.h rename indra/{media_plugins => plugins}/gstreamer010/llmediaimplgstreamervidplug.cpp (70%) mode change 100644 => 100755 rename indra/{media_plugins => plugins}/gstreamer010/llmediaimplgstreamervidplug.h (65%) mode change 100644 => 100755 rename indra/{media_plugins => plugins}/gstreamer010/media_plugin_gstreamer010.cpp (70%) mode change 100644 => 100755 rename indra/{media_plugins => plugins}/quicktime/CMakeLists.txt (97%) mode change 100644 => 100755 rename indra/{media_plugins => plugins}/quicktime/media_plugin_quicktime.cpp (95%) mode change 100644 => 100755 rename indra/{media_plugins => plugins}/webkit/CMakeLists.txt (88%) create mode 100644 indra/plugins/webkit/dummy_volume_catcher.cpp rename indra/{media_plugins => plugins}/webkit/linux_volume_catcher.cpp (90%) create mode 100755 indra/plugins/webkit/linux_volume_catcher.h rename indra/{media_plugins => plugins}/webkit/linux_volume_catcher_pa_syms.inc (100%) rename indra/{media_plugins => plugins}/webkit/linux_volume_catcher_paglib_syms.inc (100%) rename indra/{media_plugins => plugins}/webkit/mac_volume_catcher.cpp (85%) rename indra/{media_plugins => plugins}/webkit/media_plugin_webkit.cpp (93%) mode change 100644 => 100755 create mode 100644 indra/plugins/webkit/volume_catcher.h rename indra/{media_plugins => plugins}/webkit/windows_volume_catcher.cpp (61%) diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt deleted file mode 100644 index 9858d093e..000000000 --- a/indra/media_plugins/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# -*- cmake -*- - -add_subdirectory(base) - -add_subdirectory(webkit) - -if (LINUX) - add_subdirectory(gstreamer010) -endif (LINUX) - -if (DARWIN OR WINDOWS) - add_subdirectory(quicktime) -endif (DARWIN OR WINDOWS) - -add_subdirectory(example) diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp deleted file mode 100644 index da7de0179..000000000 --- a/indra/media_plugins/example/media_plugin_example.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/** - * @file media_plugin_example.cpp - * @brief Example plugin for LLMedia API plugin system - * - * @cond - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#include "linden_common.h" - -#include "llgl.h" -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" -#include "media_plugin_base.h" - -#include - -//////////////////////////////////////////////////////////////////////////////// -// -class MediaPluginExample : - public MediaPluginBase -{ - public: - MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ); - ~MediaPluginExample(); - - /*virtual*/ void receiveMessage( const char* message_string ); - - private: - bool init(); - void update( F64 milliseconds ); - void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ); - bool mFirstTime; - - time_t mLastUpdateTime; - enum Constants { ENumObjects = 10 }; - unsigned char* mBackgroundPixels; - int mColorR[ ENumObjects ]; - int mColorG[ ENumObjects ]; - int mColorB[ ENumObjects ]; - int mXpos[ ENumObjects ]; - int mYpos[ ENumObjects ]; - int mXInc[ ENumObjects ]; - int mYInc[ ENumObjects ]; - int mBlockSize[ ENumObjects ]; - bool mMouseButtonDown; - bool mStopAction; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -MediaPluginExample::MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ) : - MediaPluginBase( host_send_func, host_user_data ) -{ - mFirstTime = true; - mWidth = 0; - mHeight = 0; - mDepth = 4; - mPixels = 0; - mMouseButtonDown = false; - mStopAction = false; - mLastUpdateTime = 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -MediaPluginExample::~MediaPluginExample() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginExample::receiveMessage( const char* message_string ) -{ -// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; - LLPluginMessage message_in; - - if(message_in.parse(message_string) >= 0) - { - std::string message_class = message_in.getClass(); - std::string message_name = message_in.getName(); - if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) - { - if(message_name == "init") - { - LLPluginMessage message("base", "init_response"); - LLSD versions = LLSD::emptyMap(); - versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; - message.setValueLLSD("versions", versions); - - std::string plugin_version = "Example plugin 1.0..0"; - message.setValue("plugin_version", plugin_version); - sendMessage(message); - } - else if(message_name == "idle") - { - // no response is necessary here. - F64 time = message_in.getValueReal("time"); - - // Convert time to milliseconds for update() - update((int)(time * 1000.0f)); - } - else if(message_name == "cleanup") - { - } - else if(message_name == "shm_added") - { - SharedSegmentInfo info; - info.mAddress = message_in.getValuePointer("address"); - info.mSize = (size_t)message_in.getValueS32("size"); - std::string name = message_in.getValue("name"); - - mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); - - } - else if(message_name == "shm_remove") - { - std::string name = message_in.getValue("name"); - - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if(iter != mSharedSegments.end()) - { - if(mPixels == iter->second.mAddress) - { - // This is the currently active pixel buffer. Make sure we stop drawing to it. - mPixels = NULL; - mTextureSegmentName.clear(); - } - mSharedSegments.erase(iter); - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; - } - - // Send the response so it can be cleaned up. - LLPluginMessage message("base", "shm_remove_response"); - message.setValue("name", name); - sendMessage(message); - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; - } - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) - { - if(message_name == "init") - { - // Plugin gets to decide the texture parameters to use. - mDepth = 4; - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); - message.setValueS32("default_width", 1024); - message.setValueS32("default_height", 1024); - message.setValueS32("depth", mDepth); - message.setValueU32("internalformat", GL_RGBA); - message.setValueU32("format", GL_RGBA); - message.setValueU32("type", GL_UNSIGNED_BYTE); - message.setValueBoolean("coords_opengl", true); - sendMessage(message); - } - else if(message_name == "size_change") - { - std::string name = message_in.getValue("name"); - S32 width = message_in.getValueS32("width"); - S32 height = message_in.getValueS32("height"); - S32 texture_width = message_in.getValueS32("texture_width"); - S32 texture_height = message_in.getValueS32("texture_height"); - - if(!name.empty()) - { - // Find the shared memory region with this name - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if(iter != mSharedSegments.end()) - { - mPixels = (unsigned char*)iter->second.mAddress; - mWidth = width; - mHeight = height; - - mTextureWidth = texture_width; - mTextureHeight = texture_height; - }; - }; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); - message.setValue("name", name); - message.setValueS32("width", width); - message.setValueS32("height", height); - message.setValueS32("texture_width", texture_width); - message.setValueS32("texture_height", texture_height); - sendMessage(message); - - } - else if(message_name == "load_uri") - { - } - else if(message_name == "mouse_event") - { - std::string event = message_in.getValue("event"); - if(event == "down") - { - - } - else if(event == "up") - { - } - else if(event == "double_click") - { - } - } - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; - }; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginExample::write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ) -{ - // make sure we don't write outside the buffer - if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) ) - return; - - if ( mBackgroundPixels != NULL ) - { - unsigned char *pixel = mBackgroundPixels; - pixel += y * mWidth * mDepth; - pixel += ( x * mDepth ); - pixel[ 0 ] = b; - pixel[ 1 ] = g; - pixel[ 2 ] = r; - - setDirty( x, y, x + 1, y + 1 ); - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginExample::update( F64 milliseconds ) -{ - if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 ) - return; - - if ( mPixels == 0 ) - return; - - if ( mFirstTime ) - { - for( int n = 0; n < ENumObjects; ++n ) - { - mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 ); - mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 ); - - mColorR[ n ] = rand() % 0x60 + 0x60; - mColorG[ n ] = rand() % 0x60 + 0x60; - mColorB[ n ] = rand() % 0x60 + 0x60; - - mXInc[ n ] = 0; - while ( mXInc[ n ] == 0 ) - mXInc[ n ] = rand() % 7 - 3; - - mYInc[ n ] = 0; - while ( mYInc[ n ] == 0 ) - mYInc[ n ] = rand() % 9 - 4; - - mBlockSize[ n ] = rand() % 0x30 + 0x10; - }; - - delete [] mBackgroundPixels; - - mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ]; - - mFirstTime = false; - }; - - if ( mStopAction ) - return; - - if ( time( NULL ) > mLastUpdateTime + 3 ) - { - const int num_squares = rand() % 20 + 4; - int sqr1_r = rand() % 0x80 + 0x20; - int sqr1_g = rand() % 0x80 + 0x20; - int sqr1_b = rand() % 0x80 + 0x20; - int sqr2_r = rand() % 0x80 + 0x20; - int sqr2_g = rand() % 0x80 + 0x20; - int sqr2_b = rand() % 0x80 + 0x20; - - for ( int y1 = 0; y1 < num_squares; ++y1 ) - { - for ( int x1 = 0; x1 < num_squares; ++x1 ) - { - int px_start = mWidth * x1 / num_squares; - int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares; - int py_start = mHeight * y1 / num_squares; - int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares; - - for( int y2 = py_start; y2 < py_end; ++y2 ) - { - for( int x2 = px_start; x2 < px_end; ++x2 ) - { - int rowspan = mWidth * mDepth; - - if ( ( y1 % 2 ) ^ ( x1 % 2 ) ) - { - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r; - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g; - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b; - } - else - { - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r; - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g; - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b; - }; - }; - }; - }; - }; - - time( &mLastUpdateTime ); - }; - - memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth ); - - for( int n = 0; n < ENumObjects; ++n ) - { - if ( rand() % 50 == 0 ) - { - mXInc[ n ] = 0; - while ( mXInc[ n ] == 0 ) - mXInc[ n ] = rand() % 7 - 3; - - mYInc[ n ] = 0; - while ( mYInc[ n ] == 0 ) - mYInc[ n ] = rand() % 9 - 4; - }; - - if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] ) - mXInc[ n ] =- mXInc[ n ]; - - if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] ) - mYInc[ n ] =- mYInc[ n ]; - - mXpos[ n ] += mXInc[ n ]; - mYpos[ n ] += mYInc[ n ]; - - for( int y = 0; y < mBlockSize[ n ]; ++y ) - { - for( int x = 0; x < mBlockSize[ n ]; ++x ) - { - mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ]; - mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ]; - mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ]; - }; - }; - }; - - setDirty( 0, 0, mWidth, mHeight ); -}; - -//////////////////////////////////////////////////////////////////////////////// -// -bool MediaPluginExample::init() -{ - LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" ); - message.setValue( "name", "Example Plugin" ); - sendMessage( message ); - - return true; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -int init_media_plugin( LLPluginInstance::sendMessageFunction host_send_func, - void* host_user_data, - LLPluginInstance::sendMessageFunction *plugin_send_func, - void **plugin_user_data ) -{ - MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data ); - *plugin_send_func = MediaPluginExample::staticReceiveMessage; - *plugin_user_data = ( void* )self; - - return 0; -} - diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h deleted file mode 100644 index 6bc272c00..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file llmediaimplgstreamer.h - * @author Tofu Linden - * @brief implementation that supports media playback via GStreamer. - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -// header guard -#ifndef llmediaimplgstreamer_h -#define llmediaimplgstreamer_h - -#if LL_GSTREAMER010_ENABLED - -extern "C" { -#include -#include - -#include "apr_pools.h" -#include "apr_dso.h" -} - - -extern "C" { -gboolean llmediaimplgstreamer_bus_callback (GstBus *bus, - GstMessage *message, - gpointer data); -} - -#endif // LL_GSTREAMER010_ENABLED - -#endif // llmediaimplgstreamer_h diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp deleted file mode 100644 index 2e4baaa9e..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/** - * @file llmediaimplgstreamer_syms.cpp - * @brief dynamic GStreamer symbol-grabbing code - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#if LL_GSTREAMER010_ENABLED - -#include - -extern "C" { -#include - -#include "apr_pools.h" -#include "apr_dso.h" -} - -#include "llmediaimplgstreamertriviallogging.h" - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - -// a couple of stubs for disgusting reasons -GstDebugCategory* -ll_gst_debug_category_new(gchar *name, guint color, gchar *description) -{ - static GstDebugCategory dummy; - return &dummy; -} -void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname) -{ -} - -static bool sSymsGrabbed = false; -static apr_pool_t *sSymGSTDSOMemoryPool = NULL; -static apr_dso_handle_t *sSymGSTDSOHandleG = NULL; -static apr_dso_handle_t *sSymGSTDSOHandleV = NULL; - - -bool grab_gst_syms(std::string gst_dso_name, - std::string gst_dso_name_vid) -{ - if (sSymsGrabbed) - { - // already have grabbed good syms - return TRUE; - } - - bool sym_error = false; - bool rtn = false; - apr_status_t rv; - apr_dso_handle_t *sSymGSTDSOHandle = NULL; - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0) - - //attempt to load the shared libraries - apr_pool_create(&sSymGSTDSOMemoryPool, NULL); - - if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle, - gst_dso_name.c_str(), - sSymGSTDSOMemoryPool) )) - { - INFOMSG("Found DSO: %s", gst_dso_name.c_str()); -#include "llmediaimplgstreamer_syms_raw.inc" - - if ( sSymGSTDSOHandle ) - { - sSymGSTDSOHandleG = sSymGSTDSOHandle; - sSymGSTDSOHandle = NULL; - } - - if ( APR_SUCCESS == - (rv = apr_dso_load(&sSymGSTDSOHandle, - gst_dso_name_vid.c_str(), - sSymGSTDSOMemoryPool) )) - { - INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str()); -#include "llmediaimplgstreamer_syms_rawv.inc" - rtn = !sym_error; - } - else - { - INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str()); - rtn = false; // failure - } - } - else - { - INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str()); - rtn = false; // failure - } - - if (sym_error) - { - WARNMSG("Failed to find necessary symbols in GStreamer libraries."); - } - - if ( sSymGSTDSOHandle ) - { - sSymGSTDSOHandleV = sSymGSTDSOHandle; - sSymGSTDSOHandle = NULL; - } -#undef LL_GST_SYM - - sSymsGrabbed = !!rtn; - return rtn; -} - - -void ungrab_gst_syms() -{ - // should be safe to call regardless of whether we've - // actually grabbed syms. - - if ( sSymGSTDSOHandleG ) - { - apr_dso_unload(sSymGSTDSOHandleG); - sSymGSTDSOHandleG = NULL; - } - - if ( sSymGSTDSOHandleV ) - { - apr_dso_unload(sSymGSTDSOHandleV); - sSymGSTDSOHandleV = NULL; - } - - if ( sSymGSTDSOMemoryPool ) - { - apr_pool_destroy(sSymGSTDSOMemoryPool); - sSymGSTDSOMemoryPool = NULL; - } - - // NULL-out all of the symbols we'd grabbed -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{ll##GSTSYM = NULL;}while(0) -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - - sSymsGrabbed = false; -} - - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h deleted file mode 100644 index d1559089c..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file llmediaimplgstreamer_syms.h - * @brief dynamic GStreamer symbol-grabbing code - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#include "linden_common.h" - -#if LL_GSTREAMER010_ENABLED - -extern "C" { -#include -} - -bool grab_gst_syms(std::string gst_dso_name, - std::string gst_dso_name_vid); -void ungrab_gst_syms(); - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__) -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - -// regrettable hacks to give us better runtime compatibility with older systems -#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) -#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0) - -// regrettable hacks because GStreamer was not designed for runtime loading -#undef GST_TYPE_MESSAGE -#define GST_TYPE_MESSAGE (llgst_message_get_type()) -#undef GST_TYPE_OBJECT -#define GST_TYPE_OBJECT (llgst_object_get_type()) -#undef GST_TYPE_PIPELINE -#define GST_TYPE_PIPELINE (llgst_pipeline_get_type()) -#undef GST_TYPE_ELEMENT -#define GST_TYPE_ELEMENT (llgst_element_get_type()) -#undef GST_TYPE_VIDEO_SINK -#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type()) -// more regrettable hacks to stub-out these .h-exposed GStreamer internals -void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname); -#undef _gst_debug_register_funcptr -#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr -GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description); -#undef _gst_debug_category_new -#define _gst_debug_category_new ll_gst_debug_category_new -#undef __gst_debug_enabled -#define __gst_debug_enabled (0) - -// more hacks -#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M))) - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc deleted file mode 100644 index b33e59363..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc +++ /dev/null @@ -1,51 +0,0 @@ - -// required symbols to grab -LL_GST_SYM(true, gst_pad_peer_accept_caps, gboolean, GstPad *pad, GstCaps *caps); -LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void); -LL_GST_SYM(true, gst_buffer_set_caps, void, GstBuffer*, GstCaps *); -LL_GST_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*); -LL_GST_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err); -LL_GST_SYM(true, gst_message_get_type, GType, void); -LL_GST_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type); -LL_GST_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending); -LL_GST_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state); -LL_GST_SYM(true, gst_object_unref, void, gpointer object); -LL_GST_SYM(true, gst_object_get_type, GType, void); -LL_GST_SYM(true, gst_pipeline_get_type, GType, void); -LL_GST_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline); -LL_GST_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data); -LL_GST_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name); -LL_GST_SYM(true, gst_element_get_type, GType, void); -LL_GST_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template); -LL_GST_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp); -LL_GST_SYM(true, gst_element_class_set_details, void, GstElementClass *klass, const GstElementDetails *details); -LL_GST_SYM(true, gst_caps_unref, void, GstCaps* caps); -LL_GST_SYM(true, gst_caps_ref, GstCaps *, GstCaps* caps); -//LL_GST_SYM(true, gst_caps_is_empty, gboolean, const GstCaps *caps); -LL_GST_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string); -LL_GST_SYM(true, gst_caps_replace, void, GstCaps **caps, GstCaps *newcaps); -LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index); -LL_GST_SYM(true, gst_caps_copy, GstCaps *, const GstCaps * caps); -//LL_GST_SYM(true, gst_caps_intersect, GstCaps *, const GstCaps *caps1, const GstCaps *caps2); -LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type); -LL_GST_SYM(true, _gst_plugin_register_static, void, GstPluginDesc *desc); -LL_GST_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value); -LL_GST_SYM(true, gst_structure_get_value, G_CONST_RETURN GValue *, const GstStructure *structure, const gchar *fieldname); -LL_GST_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value); -LL_GST_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value); -LL_GST_SYM(true, gst_structure_get_name, G_CONST_RETURN gchar *, const GstStructure *structure); -LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64); - -// optional symbols to grab -LL_GST_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled); -LL_GST_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled); -LL_GST_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent); -LL_GST_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur); -LL_GST_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano); - -// GStreamer 'internal' symbols which may not be visible in some runtimes but are still used in expanded GStreamer header macros - yuck! We'll substitute our own stubs for these. -//LL_GST_SYM(true, _gst_debug_register_funcptr, void, GstDebugFuncPtr func, gchar* ptrname); -//LL_GST_SYM(true, _gst_debug_category_new, GstDebugCategory *, gchar *name, guint color, gchar *description); diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc deleted file mode 100644 index 14fbcb48b..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc +++ /dev/null @@ -1,5 +0,0 @@ - -// required symbols to grab -LL_GST_SYM(true, gst_video_sink_get_type, GType, void); - -// optional symbols to grab diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h deleted file mode 100644 index e7b31bec9..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file llmediaimplgstreamertriviallogging.h - * @brief minimal logging utilities. - * - * @cond - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ -#define __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ - -#include - -extern "C" { -#include -#include -} - -///////////////////////////////////////////////////////////////////////// -// Debug/Info/Warning macros. -#define MSGMODULEFOO "(media plugin)" -#define STDERRMSG(...) do{\ - fprintf(stderr, " pid:%d: ", (int)getpid());\ - fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\ - fprintf(stderr, __VA_ARGS__);\ - fputc('\n',stderr);\ - }while(0) -#define NULLMSG(...) do{}while(0) - -#define DEBUGMSG NULLMSG -#define INFOMSG STDERRMSG -#define WARNMSG STDERRMSG -///////////////////////////////////////////////////////////////////////// - -#endif /* __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ */ diff --git a/indra/media_plugins/webkit/dummy_volume_catcher.cpp b/indra/media_plugins/webkit/dummy_volume_catcher.cpp deleted file mode 100644 index d54b31b2a..000000000 --- a/indra/media_plugins/webkit/dummy_volume_catcher.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file dummy_volume_catcher.cpp - * @brief A null implementation of the "VolumeCatcher" class for platforms where it's not implemented yet. - * - * @cond - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#include "volume_catcher.h" - - -class VolumeCatcherImpl -{ -}; - -///////////////////////////////////////////////////// - -VolumeCatcher::VolumeCatcher() -{ - pimpl = NULL; -} - -VolumeCatcher::~VolumeCatcher() -{ -} - -void VolumeCatcher::setVolume(F32 volume) -{ -} - -void VolumeCatcher::setPan(F32 pan) -{ -} - -void VolumeCatcher::pump() -{ -} - diff --git a/indra/media_plugins/webkit/volume_catcher.h b/indra/media_plugins/webkit/volume_catcher.h deleted file mode 100644 index 337f2913d..000000000 --- a/indra/media_plugins/webkit/volume_catcher.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file volume_catcher.h - * @brief Interface to a class with platform-specific implementations that allows control of the audio volume of all sources in the current process. - * - * @cond - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#ifndef VOLUME_CATCHER_H -#define VOLUME_CATCHER_H - -#include "linden_common.h" - -class VolumeCatcherImpl; - -class VolumeCatcher -{ - public: - VolumeCatcher(); - ~VolumeCatcher(); - - void setVolume(F32 volume); // 0.0 - 1.0 - - // Set the left-right pan of audio sources - // where -1.0 = left, 0 = center, and 1.0 = right - void setPan(F32 pan); - - void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume - - private: - VolumeCatcherImpl *pimpl; -}; - -#endif // VOLUME_CATCHER_H diff --git a/indra/plugins/CMakeLists.txt b/indra/plugins/CMakeLists.txt new file mode 100644 index 000000000..de57249ba --- /dev/null +++ b/indra/plugins/CMakeLists.txt @@ -0,0 +1,17 @@ +# -*- cmake -*- + +add_subdirectory(base_basic) +add_subdirectory(base_media) +add_subdirectory(filepicker) +add_subdirectory(webkit) + +if (LINUX) + add_subdirectory(gstreamer010) +endif (LINUX) + +if (WINDOWS OR DARWIN) + add_subdirectory(quicktime) +endif (WINDOWS OR DARWIN) + +add_subdirectory(example_basic) +add_subdirectory(example_media) diff --git a/indra/plugins/base_basic/CMakeLists.txt b/indra/plugins/base_basic/CMakeLists.txt new file mode 100644 index 000000000..1ff52fda5 --- /dev/null +++ b/indra/plugins/base_basic/CMakeLists.txt @@ -0,0 +1,39 @@ +# -*- cmake -*- + +project(basic_plugin_base) + +include(00-Common) +include(LLCommon) +include(LLPlugin) +include(Linking) +include(PluginAPI) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} +) + +### basic_plugin_base + +if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif(WINDOWS) +endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + +set(basic_plugin_base_SOURCE_FILES + basic_plugin_base.cpp +) + +set(basic_plugin_base_HEADER_FILES + CMakeLists.txt + + basic_plugin_base.h +) + +add_library(basic_plugin_base + ${basic_plugin_base_SOURCE_FILES} +) + diff --git a/indra/plugins/base_basic/basic_plugin_base.cpp b/indra/plugins/base_basic/basic_plugin_base.cpp new file mode 100755 index 000000000..90b5964ef --- /dev/null +++ b/indra/plugins/base_basic/basic_plugin_base.cpp @@ -0,0 +1,136 @@ +/** + * @file basic_plugin_base.cpp + * @brief Basic plugin base class for Basic API plugin system + * + * All plugins should be a subclass of BasicPluginBase. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#include "linden_common.h" +#include "basic_plugin_base.h" + + +// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint + +//////////////////////////////////////////////////////////////////////////////// +/// Basic plugin constructor. +/// +/// @param[in] send_message_function Function for sending messages from plugin to plugin loader shell +/// @param[in] plugin_instance Message data for messages from plugin to plugin loader shell +BasicPluginBase::BasicPluginBase(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) +{ + mSendMessageFunction = send_message_function; + mPluginInstance = plugin_instance; +} + +/** + * Receive message from plugin loader shell. + * + * @param[in] message_string Message string + * @param[in] user_data Message data + * + */ +void BasicPluginBase::staticReceiveMessage(char const* message_string, BasicPluginBase** self_ptr) +{ + BasicPluginBase* self = *self_ptr; + if(self != NULL) + { + self->receiveMessage(message_string); + + // If the plugin has processed the delete message, delete it. + if(self->mDeleteMe) + { + delete self; + *self_ptr = NULL; + } + } +} + +// This is the SLPlugin process. +// This is the loaded DSO. +// +// Call this function to send 'message' to the viewer. +/** + * Send message to plugin loader shell. + * + * @param[in] message Message data being sent to plugin loader shell + * + */ +void BasicPluginBase::sendMessage(const LLPluginMessage &message) +{ + std::string output = message.generate(); + mSendMessageFunction(output.c_str(), &mPluginInstance); +} + +#if LL_WINDOWS +# define LLSYMEXPORT __declspec(dllexport) +#elif LL_LINUX +# define LLSYMEXPORT __attribute__ ((visibility("default"))) +#else +# define LLSYMEXPORT /**/ +#endif + +extern "C" +{ + LLSYMEXPORT int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction send_message_function, + LLPluginInstance* plugin_instance, + LLPluginInstance::receiveMessageFunction* receive_message_function, + BasicPluginBase** plugin_object); +} + +/** + * Plugin initialization and entry point. Establishes communication channel for messages between plugin and plugin loader shell. TODO:DOC - Please check! + * + * @param[in] send_message_function Function for sending messages from plugin to viewer + * @param[in] plugin_instance Message data for messages from plugin to plugin loader shell + * @param[out] receive_message_function Function for receiving message from viewer to plugin + * @param[out] plugin_object Pointer to plugin instance + * + * @return int, where 0=success + * + */ +LLSYMEXPORT int +LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction send_message_function, + LLPluginInstance* plugin_instance, + LLPluginInstance::receiveMessageFunction* receive_message_function, + BasicPluginBase** plugin_object) +{ + *receive_message_function = BasicPluginBase::staticReceiveMessage; + return create_plugin(send_message_function, plugin_instance, plugin_object); +} + +#ifdef WIN32 +int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params ) +{ + return 1; +} +#endif diff --git a/indra/media_plugins/base/media_plugin_base.exp b/indra/plugins/base_basic/basic_plugin_base.exp old mode 100755 new mode 100644 similarity index 100% rename from indra/media_plugins/base/media_plugin_base.exp rename to indra/plugins/base_basic/basic_plugin_base.exp diff --git a/indra/plugins/base_basic/basic_plugin_base.h b/indra/plugins/base_basic/basic_plugin_base.h new file mode 100755 index 000000000..bbabb18b7 --- /dev/null +++ b/indra/plugins/base_basic/basic_plugin_base.h @@ -0,0 +1,88 @@ +/** + * @file basic_plugin_base.h + * @brief Basic plugin base class for Basic API plugin system + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#ifndef BASIC_PLUGIN_BASE_H +#define BASIC_PLUGIN_BASE_H + +#include + +#include "linden_common.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" + +class BasicPluginBase +{ +public: + BasicPluginBase(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); + //! Basic plugin destructor. + virtual ~BasicPluginBase() {} + + //! Handle received message from plugin loader shell. + virtual void receiveMessage(char const* message_string) = 0; + + // This function is actually called and then calls the member function above. + static void staticReceiveMessage(char const* message_string, BasicPluginBase** self_ptr); + +protected: + void sendMessage(LLPluginMessage const& message); + + //! Message data being sent to plugin loader shell by mSendMessageFunction. + LLPluginInstance* mPluginInstance; + + //! Function to send message from plugin to plugin loader shell. + LLPluginInstance::sendMessageFunction mSendMessageFunction; + + //! Flag to delete plugin instance (self). + bool mDeleteMe; +}; + +/** The plugin must define this function to create its instance. + * It should look something like this: + * @code + * { + * *plugin_object = new FooPluginBar(send_message_function, plugin_instance); + * return 0; + * } + * @endcode + */ +int create_plugin( + LLPluginInstance::sendMessageFunction send_message_function, + LLPluginInstance* plugin_instance, + BasicPluginBase** plugin_object); + +#endif // BASIC_PLUGIN_BASE + diff --git a/indra/media_plugins/base/CMakeLists.txt b/indra/plugins/base_media/CMakeLists.txt similarity index 81% rename from indra/media_plugins/base/CMakeLists.txt rename to indra/plugins/base_media/CMakeLists.txt index 8d620433a..f2c8d7225 100644 --- a/indra/media_plugins/base/CMakeLists.txt +++ b/indra/plugins/base_media/CMakeLists.txt @@ -12,6 +12,7 @@ include(LLWindow) include(Linking) include(PluginAPI) include(FindOpenGL) +include(BasicPluginBase) include_directories( ${LLPLUGIN_INCLUDE_DIRS} @@ -20,9 +21,9 @@ include_directories( ${LLIMAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} + ${BASIC_PLUGIN_BASE_INCLUDE_DIRS} ) - ### media_plugin_base if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) @@ -47,3 +48,11 @@ add_library(media_plugin_base ${media_plugin_base_SOURCE_FILES} ) +target_link_libraries(media_plugin_base + ${BASIC_PLUGIN_BASE_LIBRARIES} +) + +add_dependencies(media_plugin_base + ${BASIC_PLUGIN_BASE_LIBRARIES} +) + diff --git a/indra/media_plugins/base/media_plugin_base.cpp b/indra/plugins/base_media/media_plugin_base.cpp old mode 100644 new mode 100755 similarity index 66% rename from indra/media_plugins/base/media_plugin_base.cpp rename to indra/plugins/base_media/media_plugin_base.cpp index 47acdfd28..102d18996 --- a/indra/media_plugins/base/media_plugin_base.cpp +++ b/indra/plugins/base_media/media_plugin_base.cpp @@ -40,18 +40,15 @@ // TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint + //////////////////////////////////////////////////////////////////////////////// /// Media plugin constructor. /// -/// @param[in] host_send_func Function for sending messages from plugin to plugin loader shell +/// @param[in] send_message_function Function for sending messages from plugin to plugin loader shell /// @param[in] host_user_data Message data for messages from plugin to plugin loader shell - -MediaPluginBase::MediaPluginBase( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data ) +MediaPluginBase::MediaPluginBase(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) + : BasicPluginBase(send_message_function, plugin_instance) { - mHostSendFunction = host_send_func; - mHostUserData = host_user_data; mDeleteMe = false; mPixels = 0; mWidth = 0; @@ -103,43 +100,6 @@ void MediaPluginBase::setStatus(EStatus status) } } - -/** - * Receive message from plugin loader shell. - * - * @param[in] message_string Message string - * @param[in] user_data Message data - * - */ -void MediaPluginBase::staticReceiveMessage(const char *message_string, void **user_data) -{ - MediaPluginBase *self = (MediaPluginBase*)*user_data; - - if(self != NULL) - { - self->receiveMessage(message_string); - - // If the plugin has processed the delete message, delete it. - if(self->mDeleteMe) - { - delete self; - *user_data = NULL; - } - } -} - -/** - * Send message to plugin loader shell. - * - * @param[in] message Message data being sent to plugin loader shell - * - */ -void MediaPluginBase::sendMessage(const LLPluginMessage &message) -{ - std::string output = message.generate(); - mHostSendFunction(output.c_str(), &mHostUserData); -} - /** * Notifies plugin loader shell that part of display area needs to be redrawn. * @@ -183,28 +143,6 @@ void MediaPluginBase::sendStatus() # define LLSYMEXPORT /**/ #endif -extern "C" -{ - LLSYMEXPORT int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); -} - -/** - * Plugin initialization and entry point. Establishes communication channel for messages between plugin and plugin loader shell. TODO:DOC - Please check! - * - * @param[in] host_send_func Function for sending messages from plugin to plugin loader shell - * @param[in] host_user_data Message data for messages from plugin to plugin loader shell - * @param[out] plugin_send_func Function for plugin to receive messages from plugin loader shell - * @param[out] plugin_user_data Pointer to plugin instance - * - * @return int, where 0=success - * - */ -LLSYMEXPORT int -LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ - return init_media_plugin(host_send_func, host_user_data, plugin_send_func, plugin_user_data); -} - #ifdef WIN32 int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params ) { diff --git a/indra/plugins/base_media/media_plugin_base.exp b/indra/plugins/base_media/media_plugin_base.exp new file mode 100755 index 000000000..d8c7bb712 --- /dev/null +++ b/indra/plugins/base_media/media_plugin_base.exp @@ -0,0 +1,2 @@ +_LLPluginInitEntryPoint + diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/plugins/base_media/media_plugin_base.h old mode 100644 new mode 100755 similarity index 67% rename from indra/media_plugins/base/media_plugin_base.h rename to indra/plugins/base_media/media_plugin_base.h index efb0629a5..5aebbe1a0 --- a/indra/media_plugins/base/media_plugin_base.h +++ b/indra/plugins/base_media/media_plugin_base.h @@ -33,27 +33,17 @@ * @endcond */ -#include "linden_common.h" +#ifndef MEDIA_PLUGIN_BASE_H +#define MEDIA_PLUGIN_BASE_H -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" +#include "basic_plugin_base.h" - -class MediaPluginBase +class MediaPluginBase : public BasicPluginBase { public: - MediaPluginBase(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); - /** Media plugin destructor. */ - virtual ~MediaPluginBase() {} - - /** Handle received message from plugin loader shell. */ - virtual void receiveMessage(const char *message_string) = 0; - - static void staticReceiveMessage(const char *message_string, void **user_data); + MediaPluginBase(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); protected: - /** Plugin status. */ typedef enum { @@ -76,7 +66,6 @@ protected: size_t mSize; }; - void sendMessage(const LLPluginMessage &message); void sendStatus(); std::string statusString(); void setStatus(EStatus status); @@ -87,13 +76,6 @@ protected: /** Map of shared memory names to shared memory. */ typedef std::map SharedSegmentMap; - - /** Function to send message from plugin to plugin loader shell. */ - LLPluginInstance::sendMessageFunction mHostSendFunction; - /** Message data being sent to plugin loader shell by mHostSendFunction. */ - void *mHostUserData; - /** Flag to delete plugin instance (self). */ - bool mDeleteMe; /** Pixel array to display. TODO:DOC are pixels always 24-bit RGB format, aligned on 32-bit boundary? Also: calling this a pixel array may be misleading since 1 pixel > 1 char. */ unsigned char* mPixels; /** TODO:DOC what's this for -- does a texture have its own piece of shared memory? updated on size_change_request, cleared on shm_remove */ @@ -115,22 +97,4 @@ protected: }; -/** The plugin must define this function to create its instance. - * It should look something like this: - * @code - * { - * MediaPluginFoo *self = new MediaPluginFoo(host_send_func, host_user_data); - * *plugin_send_func = MediaPluginFoo::staticReceiveMessage; - * *plugin_user_data = (void*)self; - * - * return 0; - * } - * @endcode - */ -int init_media_plugin( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data, - LLPluginInstance::sendMessageFunction *plugin_send_func, - void **plugin_user_data); - - +#endif // MEDIA_PLUGIN_BASE_H diff --git a/indra/plugins/example_basic/CMakeLists.txt b/indra/plugins/example_basic/CMakeLists.txt new file mode 100644 index 000000000..fdc71a60c --- /dev/null +++ b/indra/plugins/example_basic/CMakeLists.txt @@ -0,0 +1,68 @@ +# -*- cmake -*- + +project(basic_plugin_example) + +include(00-Common) +include(LLCommon) +include(LLPlugin) +include(Linking) +include(PluginAPI) +include(BasicPluginBase) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${BASIC_PLUGIN_BASE_INCLUDE_DIRS} +) + +### basic_plugin_example + +if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif(WINDOWS) +endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + +set(basic_plugin_example_SOURCE_FILES + basic_plugin_example.cpp + ) + +add_library(basic_plugin_example + SHARED + ${basic_plugin_example_SOURCE_FILES} +) + +target_link_libraries(basic_plugin_example + ${LLPLUGIN_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${BASIC_PLUGIN_BASE_LIBRARIES} +) + +add_dependencies(basic_plugin_example + ${LLPLUGIN_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${BASIC_PLUGIN_BASE_LIBRARIES} +) + +if (WINDOWS) + set_target_properties( + basic_plugin_example + PROPERTIES + LINK_FLAGS "/MANIFEST:NO" + ) +endif (WINDOWS) + +if (DARWIN) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name + set_target_properties( + basic_plugin_example + PROPERTIES + PREFIX "" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base_basic/basic_plugin_base.exp" + ) + +endif (DARWIN) diff --git a/indra/plugins/example_basic/basic_plugin_example.cpp b/indra/plugins/example_basic/basic_plugin_example.cpp new file mode 100644 index 000000000..a6a255276 --- /dev/null +++ b/indra/plugins/example_basic/basic_plugin_example.cpp @@ -0,0 +1,123 @@ +/** + * @file basic_plugin_example.cpp + * @brief Example Plugin for a basic plugin. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#include "linden_common.h" +#include "basic_plugin_base.h" + +class BasicPluginExample : public BasicPluginBase +{ + public: + BasicPluginExample(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); + ~BasicPluginExample(); + + /*virtual*/ void receiveMessage(char const* message_string); + + private: + bool init(); +}; + +BasicPluginExample::BasicPluginExample(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) : + BasicPluginBase(send_message_function, plugin_instance) +{ +} + +BasicPluginExample::~BasicPluginExample() +{ +} + +void BasicPluginExample::receiveMessage(char const* message_string) +{ + LLPluginMessage message_in; + + if (message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + + if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if (message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_BASIC] = LLPLUGIN_MESSAGE_CLASS_BASIC_VERSION; + message.setValueLLSD("versions", versions); + + std::string plugin_version = "Basic Plugin Example, version 1.0.0.0"; + message.setValue("plugin_version", plugin_version); + sendMessage(message); + } + else if (message_name == "idle") + { + // This whole message should not have existed imho -- Aleric + } + else + { + std::cerr << "BasicPluginExample::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if (message_class == LLPLUGIN_MESSAGE_CLASS_BASIC) + { + if (message_name == "poke") + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "pokeback"); + sendMessage(message); + } + } + else + { + std::cerr << "BasicPluginExample::receiveMessage: unknown message class: " << message_class << std::endl; + } + } +} + +bool BasicPluginExample::init(void) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "name_text"); + message.setValue("name", "Basic Plugin Example"); + sendMessage(message); + + return true; +} + +int create_plugin(LLPluginInstance::sendMessageFunction send_message_function, + LLPluginInstance* plugin_instance, + BasicPluginBase** plugin_object) +{ + *plugin_object = new BasicPluginExample(send_message_function, plugin_instance); + return 0; +} + diff --git a/indra/media_plugins/example/CMakeLists.txt b/indra/plugins/example_media/CMakeLists.txt similarity index 83% rename from indra/media_plugins/example/CMakeLists.txt rename to indra/plugins/example_media/CMakeLists.txt index 54dc5de1e..99859ae8a 100644 --- a/indra/media_plugins/example/CMakeLists.txt +++ b/indra/plugins/example_media/CMakeLists.txt @@ -14,7 +14,7 @@ include(PluginAPI) include(MediaPluginBase) include(FindOpenGL) -include(ExamplePlugin) +#include(ExamplePlugin) include_directories( ${LLPLUGIN_INCLUDE_DIRS} @@ -26,16 +26,15 @@ include_directories( ${LLWINDOW_INCLUDE_DIRS} ) - ### media_plugin_example -if(NOT WORD_SIZE EQUAL 32) - if(WINDOWS) - add_definitions(/FIXED:NO) - else(WINDOWS) # not windows therefore gcc LINUX and DARWIN - add_definitions(-fPIC) - endif(WINDOWS) -endif(NOT WORD_SIZE EQUAL 32) +if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif(WINDOWS) +endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) set(media_plugin_example_SOURCE_FILES media_plugin_example.cpp @@ -76,7 +75,7 @@ if (DARWIN) PREFIX "" BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@executable_path" - LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base_media/media_plugin_base.exp" ) endif (DARWIN) diff --git a/indra/plugins/example_media/media_plugin_example.cpp b/indra/plugins/example_media/media_plugin_example.cpp new file mode 100755 index 000000000..bdb77fb6e --- /dev/null +++ b/indra/plugins/example_media/media_plugin_example.cpp @@ -0,0 +1,490 @@ +/** + * @file media_plugin_example.cpp + * @brief Example plugin for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#include "linden_common.h" + +#include "llgl.h" +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#include + +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginExample : + public MediaPluginBase +{ + public: + MediaPluginExample(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); + ~MediaPluginExample(); + + /*virtual*/ void receiveMessage( const char* message_string ); + + private: + bool init(); + void update( F64 milliseconds ); + void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ); + bool mFirstTime; + + time_t mLastUpdateTime; + enum Constants { ENumObjects = 10 }; + unsigned char* mBackgroundPixels; + int mColorR[ ENumObjects ]; + int mColorG[ ENumObjects ]; + int mColorB[ ENumObjects ]; + int mXpos[ ENumObjects ]; + int mYpos[ ENumObjects ]; + int mXInc[ ENumObjects ]; + int mYInc[ ENumObjects ]; + int mBlockSize[ ENumObjects ]; + bool mMouseButtonDown; + bool mStopAction; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +MediaPluginExample::MediaPluginExample(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) : + MediaPluginBase(send_message_function, plugin_instance) +{ + mFirstTime = true; + mWidth = 0; + mHeight = 0; + mDepth = 4; + mPixels = 0; + mMouseButtonDown = false; + mStopAction = false; + mLastUpdateTime = 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// +MediaPluginExample::~MediaPluginExample() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginExample::receiveMessage( const char* message_string ) +{ + LLPluginMessage message_in; + + if ( message_in.parse( message_string ) >= 0 ) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + + if ( message_class == LLPLUGIN_MESSAGE_CLASS_BASE ) + { + if ( message_name == "init" ) + { + LLPluginMessage message( "base", "init_response" ); + LLSD versions = LLSD::emptyMap(); + versions[ LLPLUGIN_MESSAGE_CLASS_BASE ] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + message.setValueLLSD( "versions", versions ); + + std::string plugin_version = "Example media plugin, Example Version 1.0.0.0"; + message.setValue( "plugin_version", plugin_version ); + sendMessage( message ); + } + else + if ( message_name == "idle" ) + { + // no response is necessary here. + F64 time = message_in.getValueReal( "time" ); + + // Convert time to milliseconds for update() + update( time ); + } + else + if ( message_name == "cleanup" ) + { + // clean up here + } + else + if ( message_name == "shm_added" ) + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer( "address" ); + info.mSize = ( size_t )message_in.getValueS32( "size" ); + std::string name = message_in.getValue( "name" ); + + mSharedSegments.insert( SharedSegmentMap::value_type( name, info ) ); + + } + else + if ( message_name == "shm_remove" ) + { + std::string name = message_in.getValue( "name" ); + + SharedSegmentMap::iterator iter = mSharedSegments.find( name ); + if( iter != mSharedSegments.end() ) + { + if ( mPixels == iter->second.mAddress ) + { + // This is the currently active pixel buffer. + // Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + }; + mSharedSegments.erase( iter ); + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown shared memory region!" << std::endl; + }; + + // Send the response so it can be cleaned up. + LLPluginMessage message( "base", "shm_remove_response" ); + message.setValue( "name", name ); + sendMessage( message ); + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown base message: " << message_name << std::endl; + }; + } + else + if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA ) + { + if ( message_name == "init" ) + { + // Plugin gets to decide the texture parameters to use. + LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params" ); + message.setValueS32( "default_width", mWidth ); + message.setValueS32( "default_height", mHeight ); + message.setValueS32( "depth", mDepth ); + message.setValueU32( "internalformat", GL_RGBA ); + message.setValueU32( "format", GL_RGBA ); + message.setValueU32( "type", GL_UNSIGNED_BYTE ); + message.setValueBoolean( "coords_opengl", false ); + sendMessage( message ); + } + else if ( message_name == "size_change" ) + { + std::string name = message_in.getValue( "name" ); + S32 width = message_in.getValueS32( "width" ); + S32 height = message_in.getValueS32( "height" ); + S32 texture_width = message_in.getValueS32( "texture_width" ); + S32 texture_height = message_in.getValueS32( "texture_height" ); + + if ( ! name.empty() ) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find( name ); + if ( iter != mSharedSegments.end() ) + { + mPixels = ( unsigned char* )iter->second.mAddress; + mWidth = width; + mHeight = height; + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + init(); + }; + }; + + LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response" ); + message.setValue( "name", name ); + message.setValueS32( "width", width ); + message.setValueS32( "height", height ); + message.setValueS32( "texture_width", texture_width ); + message.setValueS32( "texture_height", texture_height ); + sendMessage( message ); + } + else + if ( message_name == "load_uri" ) + { + std::string uri = message_in.getValue( "uri" ); + if ( ! uri.empty() ) + { + }; + } + else + if ( message_name == "mouse_event" ) + { + std::string event = message_in.getValue( "event" ); + S32 button = message_in.getValueS32( "button" ); + + // left mouse button + if ( button == 0 ) + { + int mouse_x = message_in.getValueS32( "x" ); + int mouse_y = message_in.getValueS32( "y" ); + std::string modifiers = message_in.getValue( "modifiers" ); + + if ( event == "move" ) + { + if ( mMouseButtonDown ) + write_pixel( mouse_x, mouse_y, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80 ); + } + else + if ( event == "down" ) + { + mMouseButtonDown = true; + } + else + if ( event == "up" ) + { + mMouseButtonDown = false; + } + else + if ( event == "double_click" ) + { + }; + }; + } + else + if ( message_name == "key_event" ) + { + std::string event = message_in.getValue( "event" ); + S32 key = message_in.getValueS32( "key" ); + std::string modifiers = message_in.getValue( "modifiers" ); + + if ( event == "down" ) + { + if ( key == ' ') + { + mLastUpdateTime = 0; + update( 0.0f ); + }; + }; + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown media message: " << message_string << std::endl; + }; + } + else + if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER ) + { + if ( message_name == "browse_reload" ) + { + mLastUpdateTime = 0; + mFirstTime = true; + mStopAction = false; + update( 0.0f ); + } + else + if ( message_name == "browse_stop" ) + { + for( int n = 0; n < ENumObjects; ++n ) + mXInc[ n ] = mYInc[ n ] = 0; + + mStopAction = true; + update( 0.0f ); + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown media_browser message: " << message_string << std::endl; + }; + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown message class: " << message_class << std::endl; + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginExample::write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ) +{ + // make sure we don't write outside the buffer + if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) ) + return; + + if ( mBackgroundPixels != NULL ) + { + unsigned char *pixel = mBackgroundPixels; + pixel += y * mWidth * mDepth; + pixel += ( x * mDepth ); + pixel[ 0 ] = b; + pixel[ 1 ] = g; + pixel[ 2 ] = r; + + setDirty( x, y, x + 1, y + 1 ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginExample::update( F64 milliseconds ) +{ + if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 ) + return; + + if ( mPixels == 0 ) + return; + + if ( mFirstTime ) + { + for( int n = 0; n < ENumObjects; ++n ) + { + mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 ); + mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 ); + + mColorR[ n ] = rand() % 0x60 + 0x60; + mColorG[ n ] = rand() % 0x60 + 0x60; + mColorB[ n ] = rand() % 0x60 + 0x60; + + mXInc[ n ] = 0; + while ( mXInc[ n ] == 0 ) + mXInc[ n ] = rand() % 7 - 3; + + mYInc[ n ] = 0; + while ( mYInc[ n ] == 0 ) + mYInc[ n ] = rand() % 9 - 4; + + mBlockSize[ n ] = rand() % 0x30 + 0x10; + }; + + delete [] mBackgroundPixels; + + mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ]; + + mFirstTime = false; + }; + + if ( mStopAction ) + return; + + if ( time( NULL ) > mLastUpdateTime + 3 ) + { + const int num_squares = rand() % 20 + 4; + int sqr1_r = rand() % 0x80 + 0x20; + int sqr1_g = rand() % 0x80 + 0x20; + int sqr1_b = rand() % 0x80 + 0x20; + int sqr2_r = rand() % 0x80 + 0x20; + int sqr2_g = rand() % 0x80 + 0x20; + int sqr2_b = rand() % 0x80 + 0x20; + + for ( int y1 = 0; y1 < num_squares; ++y1 ) + { + for ( int x1 = 0; x1 < num_squares; ++x1 ) + { + int px_start = mWidth * x1 / num_squares; + int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares; + int py_start = mHeight * y1 / num_squares; + int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares; + + for( int y2 = py_start; y2 < py_end; ++y2 ) + { + for( int x2 = px_start; x2 < px_end; ++x2 ) + { + int rowspan = mWidth * mDepth; + + if ( ( y1 % 2 ) ^ ( x1 % 2 ) ) + { + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b; + } + else + { + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b; + }; + }; + }; + }; + }; + + time( &mLastUpdateTime ); + }; + + memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth ); + + for( int n = 0; n < ENumObjects; ++n ) + { + if ( rand() % 50 == 0 ) + { + mXInc[ n ] = 0; + while ( mXInc[ n ] == 0 ) + mXInc[ n ] = rand() % 7 - 3; + + mYInc[ n ] = 0; + while ( mYInc[ n ] == 0 ) + mYInc[ n ] = rand() % 9 - 4; + }; + + if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] ) + mXInc[ n ] =- mXInc[ n ]; + + if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] ) + mYInc[ n ] =- mYInc[ n ]; + + mXpos[ n ] += mXInc[ n ]; + mYpos[ n ] += mYInc[ n ]; + + for( int y = 0; y < mBlockSize[ n ]; ++y ) + { + for( int x = 0; x < mBlockSize[ n ]; ++x ) + { + mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ]; + mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ]; + mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ]; + }; + }; + }; + + setDirty( 0, 0, mWidth, mHeight ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +bool MediaPluginExample::init() +{ + LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" ); + message.setValue( "name", "Example Plugin" ); + sendMessage( message ); + + return true; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +int create_plugin(LLPluginInstance::sendMessageFunction send_message_function, + LLPluginInstance* plugin_instance, + BasicPluginBase** plugin_object) +{ + *plugin_object = new MediaPluginExample(send_message_function, plugin_instance); + return 0; +} diff --git a/indra/plugins/filepicker/CMakeLists.txt b/indra/plugins/filepicker/CMakeLists.txt new file mode 100644 index 000000000..cea18360a --- /dev/null +++ b/indra/plugins/filepicker/CMakeLists.txt @@ -0,0 +1,81 @@ +# -*- cmake -*- + +project(basic_plugin_filepicker) + +include(00-Common) +include(LLCommon) +include(LLPlugin) +include(Linking) +include(PluginAPI) +include(BasicPluginBase) +include(UI) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${BASIC_PLUGIN_BASE_INCLUDE_DIRS} + ${LLUI_INCLUDE_DIRS} +) + +### basic_plugin_filepicker + +if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif(WINDOWS) +endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + +set(basic_plugin_filepicker_SOURCE_FILES + basic_plugin_filepicker.cpp + llfilepicker.cpp + ) + +set(basic_plugin_filepicker_HEADER_FILES + llfilepicker.h + ) + +set_source_files_properties(${basic_plugin_filepicker_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND basic_plugin_filepicker_SOURCE_FILES ${basic_plugin_filepicker_HEADER_FILES}) + +add_library(basic_plugin_filepicker + SHARED + ${basic_plugin_filepicker_SOURCE_FILES} +) + +target_link_libraries(basic_plugin_filepicker + ${LLPLUGIN_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${BASIC_PLUGIN_BASE_LIBRARIES} + ${UI_LIBRARIES} +) + +add_dependencies(basic_plugin_filepicker + ${LLPLUGIN_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${BASIC_PLUGIN_BASE_LIBRARIES} +) + +if (WINDOWS) + set_target_properties( + basic_plugin_filepicker + PROPERTIES + LINK_FLAGS "/MANIFEST:NO" + ) +endif (WINDOWS) + +if (DARWIN) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name + set_target_properties( + basic_plugin_filepicker + PROPERTIES + PREFIX "" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base_basic/basic_plugin_base.exp" + ) + +endif (DARWIN) diff --git a/indra/plugins/filepicker/llfilepicker.cpp b/indra/plugins/filepicker/llfilepicker.cpp new file mode 100644 index 000000000..f9a3ab8c1 --- /dev/null +++ b/indra/plugins/filepicker/llfilepicker.cpp @@ -0,0 +1,1414 @@ +/** + * @file llfilepicker.cpp + * @brief OS-specific file picker + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-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 "llfilepicker.h" +#include "llpreprocessor.h" +#include "llerror.h" +#include "basic_plugin_base.h" // For PLS_INFOS etc. + +#if LL_SDL +#include "llwindowsdl.h" // for some X/GTK utils to help with filepickers +#endif // LL_SDL + +// Translation map. +typedef std::map translation_map_type; +translation_map_type translation_map; + +// A temporary hack to minimize the number of changes from the original llfilepicker.cpp. +#define LLTrans translation +namespace translation +{ + std::string getString(char const* key) + { + translation_map_type::iterator iter = translation_map.find(key); + return (iter != translation_map.end()) ? iter->second : key; + } + + void add(std::string const& key, std::string const& translation) + { + PLS_INFOS << "Adding translation \"" << key << "\" --> \"" << translation << "\"" << PLS_ENDL; + translation_map[key] = translation; + } +} + +#if LL_GTK +namespace LLWindowSDL { + bool ll_try_gtk_init(void) + { + static BOOL done_gtk_diag = FALSE; + static BOOL gtk_is_good = FALSE; + static BOOL done_setlocale = FALSE; + static BOOL tried_gtk_init = FALSE; + + if (!done_setlocale) + { + PLS_INFOS << "Starting GTK Initialization." << PLS_ENDL; + //maybe_lock_display(); + gtk_disable_setlocale(); + //maybe_unlock_display(); + done_setlocale = TRUE; + } + + if (!tried_gtk_init) + { + tried_gtk_init = TRUE; + if (!g_thread_supported ()) g_thread_init (NULL); + //maybe_lock_display(); + gtk_is_good = gtk_init_check(NULL, NULL); + //maybe_unlock_display(); + if (!gtk_is_good) + PLS_WARNS << "GTK Initialization failed." << PLS_ENDL; + } + if (gtk_is_good && !done_gtk_diag) + { + PLS_INFOS << "GTK Initialized." << PLS_ENDL; + PLS_INFOS << "- Compiled against GTK version " + << GTK_MAJOR_VERSION << "." + << GTK_MINOR_VERSION << "." + << GTK_MICRO_VERSION << PLS_ENDL; + PLS_INFOS << "- Running against GTK version " + << gtk_major_version << "." + << gtk_minor_version << "." + << gtk_micro_version << PLS_ENDL; + //maybe_lock_display(); + const gchar* gtk_warning = gtk_check_version( + GTK_MAJOR_VERSION, + GTK_MINOR_VERSION, + GTK_MICRO_VERSION); + //maybe_unlock_display(); + if (gtk_warning) + { + PLS_WARNS << "- GTK COMPATIBILITY WARNING: " << gtk_warning << PLS_ENDL; + gtk_is_good = FALSE; + } + else + { + PLS_INFOS << "- GTK version is good." << PLS_ENDL; + } + done_gtk_diag = TRUE; + } + return gtk_is_good; + } +} +#endif + +// +// Globals +// + +LLFilePicker LLFilePicker::sInstance; + +#if LL_WINDOWS +#define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0" +#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" +#define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0" +#ifdef _CORY_TESTING +#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" +#endif +#define XML_FILTER L"XML files (*.xml)\0*.xml\0" +#define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0" +#define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" +#endif + +// +// Implementation +// +LLFilePickerBase::LLFilePickerBase() + : mCurrentFile(0), + mLocked(FALSE) + +{ + reset(); + +#if LL_WINDOWS + mOFN.lStructSize = sizeof(OPENFILENAMEW); + mOFN.hwndOwner = NULL; // Set later with setWindowID + mOFN.hInstance = NULL; + mOFN.lpstrCustomFilter = NULL; + mOFN.nMaxCustFilter = 0; + mOFN.lpstrFile = NULL; // set in open and close + mOFN.nMaxFile = LL_MAX_PATH; + mOFN.lpstrFileTitle = NULL; + mOFN.nMaxFileTitle = 0; + mOFN.lpstrInitialDir = NULL; + mOFN.lpstrTitle = NULL; + mOFN.Flags = 0; // set in open and close + mOFN.nFileOffset = 0; + mOFN.nFileExtension = 0; + mOFN.lpstrDefExt = NULL; + mOFN.lCustData = 0L; + mOFN.lpfnHook = NULL; + mOFN.lpTemplateName = NULL; +#endif + +#if LL_DARWIN + memset(&mNavOptions, 0, sizeof(mNavOptions)); + OSStatus error = NavGetDefaultDialogCreationOptions(&mNavOptions); + if (error == noErr) + { + mNavOptions.modality = kWindowModalityAppModal; + } +#endif +} + +const std::string LLFilePickerBase::getFirstFile() +{ + mCurrentFile = 0; + return getNextFile(); +} + +const std::string LLFilePickerBase::getNextFile() +{ + if (mCurrentFile >= getFileCount()) + { + mLocked = FALSE; + return std::string(); + } + else + { + return mFiles[mCurrentFile++]; + } +} + +const std::string LLFilePickerBase::getCurFile() +{ + if (mCurrentFile >= getFileCount()) + { + mLocked = FALSE; + return std::string(); + } + else + { + return mFiles[mCurrentFile]; + } +} + +void LLFilePickerBase::reset() +{ + mLocked = FALSE; + mFiles.clear(); + mCurrentFile = 0; +} + +#if LL_WINDOWS + +bool LLFilePickerBase::setupFilter(ELoadFilter filter) +{ + bool res = TRUE; + switch (filter) + { + case FFLOAD_ALL: + mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \ + SOUND_FILTER \ + IMAGE_FILTER \ + ANIM_FILTER \ + L"\0"; + break; + case FFLOAD_WAV: + mOFN.lpstrFilter = SOUND_FILTER \ + L"\0"; + break; + case FFLOAD_IMAGE: + mOFN.lpstrFilter = IMAGE_FILTER \ + L"\0"; + break; + case FFLOAD_ANIM: + mOFN.lpstrFilter = ANIM_FILTER \ + L"\0"; + break; +#ifdef _CORY_TESTING + case FFLOAD_GEOMETRY: + mOFN.lpstrFilter = GEOMETRY_FILTER \ + L"\0"; + break; +#endif + case FFLOAD_XML: + mOFN.lpstrFilter = XML_FILTER \ + L"\0"; + break; + case FFLOAD_SLOBJECT: + mOFN.lpstrFilter = SLOBJECT_FILTER \ + L"\0"; + break; + case FFLOAD_RAW: + mOFN.lpstrFilter = RAW_FILTER \ + L"\0"; + break; + default: + res = FALSE; + break; + } + return res; +} + +// FIXME: Use folder +bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) +{ + if( mLocked ) + { + return FALSE; + } + bool success = FALSE; + + // don't provide default file selection + mFilesW[0] = '\0'; + + mOFN.lpstrFile = mFilesW; + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; + mOFN.nFilterIndex = 1; + + setupFilter(filter); + + // Modal, so pause agent + send_agent_pause(); + + reset(); + + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + success = GetOpenFileName(&mOFN); + if (success) + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + send_agent_resume(); + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; +} + +// FIXME: Use folder +bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) +{ + if( mLocked ) + { + return FALSE; + } + bool success = FALSE; + + // don't provide default file selection + mFilesW[0] = '\0'; + + mOFN.lpstrFile = mFilesW; + mOFN.nFilterIndex = 1; + mOFN.nMaxFile = FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | + OFN_EXPLORER | OFN_ALLOWMULTISELECT; + + setupFilter(filter); + + reset(); + + // Modal, so pause agent + send_agent_pause(); + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + success = GetOpenFileName(&mOFN); // pauses until ok or cancel. + if( success ) + { + // The getopenfilename api doesn't tell us if we got more than + // one file, so we have to test manually by checking string + // lengths. + if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/ + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + else + { + mLocked = TRUE; + WCHAR* tptrw = mFilesW; + std::string dirname; + while(1) + { + if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0' + break; + if (*tptrw == 0) + tptrw++; // shouldn't happen? + std::string filename = utf16str_to_utf8str(llutf16string(tptrw)); + if (dirname.empty()) + dirname = filename + "\\"; + else + mFiles.push_back(dirname + filename); + tptrw += filename.size(); + } + } + } + send_agent_resume(); + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; +} + +// FIXME: Use folder +bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) +{ + if( mLocked ) + { + return FALSE; + } + bool success = FALSE; + + mOFN.lpstrFile = mFilesW; + if (!filename.empty()) + { + llutf16string tstring = utf8str_to_utf16str(filename); + wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ + else + { + mFilesW[0] = '\0'; + } + + switch( filter ) + { + case FFSAVE_ALL: + mOFN.lpstrDefExt = NULL; + mOFN.lpstrFilter = + L"All Files (*.*)\0*.*\0" \ + L"WAV Sounds (*.wav)\0*.wav\0" \ + L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \ + L"\0"; + break; + case FFSAVE_LSL: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"lsl"; + mOFN.lpstrFilter = + L"LSL Files (*.lsl)\0*.lsl\0" + L"Text files (*.txt)\0*.txt\0" + L"\0"; + break; + case FFSAVE_TEXT: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.txt", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"txt"; + mOFN.lpstrFilter = + L"Text files (*.txt)\0*.txt\0" + L"RTF Files (*.rtf)\0*.rtf\0" + L"\0"; + break; + case FFSAVE_WAV: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"wav"; + mOFN.lpstrFilter = + L"WAV Sounds (*.wav)\0*.wav\0" \ + L"\0"; + break; + case FFSAVE_TGA: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"tga"; + mOFN.lpstrFilter = + L"Targa Images (*.tga)\0*.tga\0" \ + L"\0"; + break; + case FFSAVE_BMP: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"bmp"; + mOFN.lpstrFilter = + L"Bitmap Images (*.bmp)\0*.bmp\0" \ + L"\0"; + break; + case FFSAVE_PNG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"png"; + mOFN.lpstrFilter = + L"PNG Images (*.png)\0*.png\0" \ + L"\0"; + break; + case FFSAVE_JPEG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"jpeg"; + mOFN.lpstrFilter = + L"JPEG Images (*.jpeg)\0*.jpeg\0" \ + L"\0"; + break; + case FFSAVE_AVI: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"avi"; + mOFN.lpstrFilter = + L"AVI Movie File (*.avi)\0*.avi\0" \ + L"\0"; + break; + case FFSAVE_ANIM: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"xaf"; + mOFN.lpstrFilter = + L"XAF Anim File (*.xaf)\0*.xaf\0" \ + L"\0"; + break; +#ifdef _CORY_TESTING + case FFSAVE_GEOMETRY: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"slg"; + mOFN.lpstrFilter = + L"SLG SL Geometry File (*.slg)\0*.slg\0" \ + L"\0"; + break; +#endif + case FFSAVE_XML: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + + mOFN.lpstrDefExt = L"xml"; + mOFN.lpstrFilter = + L"XML File (*.xml)\0*.xml\0" \ + L"\0"; + break; + case FFSAVE_COLLADA: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"collada"; + mOFN.lpstrFilter = + L"COLLADA File (*.collada)\0*.collada\0" \ + L"\0"; + break; + case FFSAVE_RAW: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"raw"; + mOFN.lpstrFilter = RAW_FILTER \ + L"\0"; + break; + case FFSAVE_J2C: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"j2c"; + mOFN.lpstrFilter = + L"Compressed Images (*.j2c)\0*.j2c\0" \ + L"\0"; + break; + default: + return FALSE; + } + + + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; + mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; + + reset(); + + // Modal, so pause agent + send_agent_pause(); + { + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! + success = GetSaveFileName(&mOFN); + if (success) + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + gKeyboard->resetKeys(); + } + send_agent_resume(); + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; +} + +#elif LL_DARWIN + +Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode) +{ + Boolean result = true; + ELoadFilter filter = *((ELoadFilter*) callBackUD); + OSStatus error = noErr; + + if (filterMode == kNavFilteringBrowserList && filter != FFLOAD_ALL && (theItem->descriptorType == typeFSRef || theItem->descriptorType == typeFSS)) + { + // navInfo is only valid for typeFSRef and typeFSS + NavFileOrFolderInfo *navInfo = (NavFileOrFolderInfo*) info; + if (!navInfo->isFolder) + { + AEDesc desc; + error = AECoerceDesc(theItem, typeFSRef, &desc); + if (error == noErr) + { + FSRef fileRef; + error = AEGetDescData(&desc, &fileRef, sizeof(fileRef)); + if (error == noErr) + { + LSItemInfoRecord fileInfo; + error = LSCopyItemInfoForRef(&fileRef, kLSRequestExtension | kLSRequestTypeCreator, &fileInfo); + if (error == noErr) + { + if (filter == FFLOAD_IMAGE) + { + if (fileInfo.filetype != 'JPEG' && fileInfo.filetype != 'JPG ' && + fileInfo.filetype != 'BMP ' && fileInfo.filetype != 'TGA ' && + fileInfo.filetype != 'TIFF' && fileInfo.filetype != 'PSD ' && + fileInfo.filetype != 'BMPf' && fileInfo.filetype != 'TPIC' && + fileInfo.filetype != 'PNG ' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("jpeg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("jpg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("bmp"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("tga"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("psd"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("tiff"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("tif"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("png"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + ) + { + result = false; + } + } + else if (filter == FFLOAD_WAV) + { + if (fileInfo.filetype != 'WAVE' && fileInfo.filetype != 'WAV ' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("wave"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("wav"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + ) + { + result = false; + } + } + else if (filter == FFLOAD_ANIM) + { + if (fileInfo.filetype != 'BVH ' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("bvh"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + ) + { + result = false; + } + } +#ifdef _CORY_TESTING + else if (filter == FFLOAD_GEOMETRY) + { + if (fileInfo.filetype != 'SLG ' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("slg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + ) + { + result = false; + } + } +#endif + else if (filter == FFLOAD_SLOBJECT) + { + PLS_WARNS << "*** navOpenFilterProc: FFLOAD_SLOBJECT NOT IMPLEMENTED ***" << PLS_ENDL; + } + else if (filter == FFLOAD_RAW) + { + if (fileInfo.filetype != '\?\?\?\?' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("raw"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + ) + { + result = false; + } + } + + if (fileInfo.extension) + { + CFRelease(fileInfo.extension); + } + } + } + AEDisposeDesc(&desc); + } + } + } + return result; +} + +OSStatus LLFilePickerBase::doNavChooseDialog(ELoadFilter filter) +{ + OSStatus error = noErr; + NavDialogRef navRef = NULL; + NavReplyRecord navReply; + + memset(&navReply, 0, sizeof(navReply)); + + // NOTE: we are passing the address of a local variable here. + // This is fine, because the object this call creates will exist for less than the lifetime of this function. + // (It is destroyed by NavDialogDispose() below.) + error = NavCreateChooseFileDialog(&mNavOptions, NULL, NULL, NULL, navOpenFilterProc, (void*)(&filter), &navRef); + + //gViewerWindow->mWindow->beforeDialog(); + + if (error == noErr) + error = NavDialogRun(navRef); + + //gViewerWindow->mWindow->afterDialog(); + + if (error == noErr) + error = NavDialogGetReply(navRef, &navReply); + + if (navRef) + NavDialogDispose(navRef); + + if (error == noErr && navReply.validRecord) + { + SInt32 count = 0; + SInt32 index; + + // AE indexes are 1 based... + error = AECountItems(&navReply.selection, &count); + for (index = 1; index <= count; index++) + { + FSRef fsRef; + AEKeyword theAEKeyword; + DescType typeCode; + Size actualSize = 0; + char path[MAX_PATH]; /*Flawfinder: ignore*/ + + memset(&fsRef, 0, sizeof(fsRef)); + error = AEGetNthPtr(&navReply.selection, index, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize); + + if (error == noErr) + error = FSRefMakePath(&fsRef, (UInt8*) path, sizeof(path)); + + if (error == noErr) + mFiles.push_back(std::string(path)); + } + } + + return error; +} + +OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, const std::string& filename) +{ + OSStatus error = noErr; + NavDialogRef navRef = NULL; + NavReplyRecord navReply; + + memset(&navReply, 0, sizeof(navReply)); + + // Setup the type, creator, and extension + OSType type, creator; + CFStringRef extension = NULL; + switch (filter) + { + case FFSAVE_WAV: + type = 'WAVE'; + creator = 'TVOD'; + extension = CFSTR(".wav"); + break; + + case FFSAVE_TGA: + type = 'TPIC'; + creator = 'prvw'; + extension = CFSTR(".tga"); + break; + + case FFSAVE_BMP: + type = 'BMPf'; + creator = 'prvw'; + extension = CFSTR(".bmp"); + break; + case FFSAVE_JPEG: + type = 'JPEG'; + creator = 'prvw'; + extension = CFSTR(".jpeg"); + break; + case FFSAVE_PNG: + type = 'PNG '; + creator = 'prvw'; + extension = CFSTR(".png"); + break; + case FFSAVE_AVI: + type = '\?\?\?\?'; + creator = '\?\?\?\?'; + extension = CFSTR(".mov"); + break; + + case FFSAVE_ANIM: + type = '\?\?\?\?'; + creator = '\?\?\?\?'; + extension = CFSTR(".xaf"); + break; + +#ifdef _CORY_TESTING + case FFSAVE_GEOMETRY: + type = '\?\?\?\?'; + creator = '\?\?\?\?'; + extension = CFSTR(".slg"); + break; +#endif + case FFSAVE_RAW: + type = '\?\?\?\?'; + creator = '\?\?\?\?'; + extension = CFSTR(".raw"); + break; + + case FFSAVE_J2C: + type = '\?\?\?\?'; + creator = 'prvw'; + extension = CFSTR(".j2c"); + break; + + case FFSAVE_ALL: + default: + type = '\?\?\?\?'; + creator = '\?\?\?\?'; + extension = CFSTR(""); + break; + } + + // Create the dialog + error = NavCreatePutFileDialog(&mNavOptions, type, creator, NULL, NULL, &navRef); + if (error == noErr) + { + CFStringRef nameString = NULL; + bool hasExtension = true; + + // Create a CFString of the initial file name + if (!filename.empty()) + nameString = CFStringCreateWithCString(NULL, filename.c_str(), kCFStringEncodingUTF8); + else + nameString = CFSTR("Untitled"); + + // Add the extension if one was not provided + if (nameString && !CFStringHasSuffix(nameString, extension)) + { + CFStringRef tempString = nameString; + hasExtension = false; + nameString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), tempString, extension); + CFRelease(tempString); + } + + // Set the name in the dialog + if (nameString) + { + error = NavDialogSetSaveFileName(navRef, nameString); + CFRelease(nameString); + } + else + { + error = paramErr; + } + } + + //gViewerWindow->mWindow->beforeDialog(); + + // Run the dialog + if (error == noErr) + error = NavDialogRun(navRef); + + //gViewerWindow->mWindow->afterDialog(); + + if (error == noErr) + error = NavDialogGetReply(navRef, &navReply); + + if (navRef) + NavDialogDispose(navRef); + + if (error == noErr && navReply.validRecord) + { + SInt32 count = 0; + + // AE indexes are 1 based... + error = AECountItems(&navReply.selection, &count); + if (count > 0) + { + // Get the FSRef to the containing folder + FSRef fsRef; + AEKeyword theAEKeyword; + DescType typeCode; + Size actualSize = 0; + + memset(&fsRef, 0, sizeof(fsRef)); + error = AEGetNthPtr(&navReply.selection, 1, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize); + + if (error == noErr) + { + char path[PATH_MAX]; /*Flawfinder: ignore*/ + char newFileName[SINGLE_FILENAME_BUFFER_SIZE]; /*Flawfinder: ignore*/ + + error = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX); + if (error == noErr) + { + if (CFStringGetCString(navReply.saveFileName, newFileName, sizeof(newFileName), kCFStringEncodingUTF8)) + { + mFiles.push_back(std::string(path) + "/" + std::string(newFileName)); + } + else + { + error = paramErr; + } + } + else + { + error = paramErr; + } + } + } + } + + return error; +} + +// FIXME: Use folder +bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) +{ + if( mLocked ) + return FALSE; + + bool success = FALSE; + + OSStatus error = noErr; + + reset(); + + mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; + // Modal, so pause agent + send_agent_pause(); + { + error = doNavChooseDialog(filter); + } + send_agent_resume(); + if (error == noErr) + { + if (getFileCount()) + success = true; + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; +} + +// FIXME: Use folder +bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) +{ + if( mLocked ) + return FALSE; + + bool success = FALSE; + + OSStatus error = noErr; + + reset(); + + mNavOptions.optionFlags |= kNavAllowMultipleFiles; + // Modal, so pause agent + send_agent_pause(); + { + error = doNavChooseDialog(filter); + } + send_agent_resume(); + if (error == noErr) + { + if (getFileCount()) + success = true; + if (getFileCount() > 1) + mLocked = TRUE; + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; +} + +// FIXME: Use folder +bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) +{ + if( mLocked ) + return FALSE; + bool success = FALSE; + OSStatus error = noErr; + + reset(); + + mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; + + // Modal, so pause agent + send_agent_pause(); + { + error = doNavSaveDialog(filter, filename); + } + send_agent_resume(); + if (error == noErr) + { + if (getFileCount()) + success = true; + } + + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + return success; +} + +#elif LL_LINUX || LL_SOLARIS + +# if LL_GTK + +// static +void LLFilePickerBase::add_to_selectedfiles(gpointer data, gpointer user_data) +{ + // We need to run g_filename_to_utf8 in the user's locale + std::string saved_locale(setlocale(LC_ALL, NULL)); + setlocale(LC_ALL, ""); + + LLFilePickerBase* picker = (LLFilePickerBase*) user_data; + GError *error = NULL; +// gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, +// -1, NULL, NULL, &error); + gchar* filename_utf8 = g_filename_display_name ((gchar*) data); + if (error) + { + // *FIXME. + // This condition should really be notified to the user, e.g. + // through a message box. Just logging it is inappropriate. + + // Ghhhh. g_filename_display_name is new to glib 2.6, and it + // is too new for SL! (Note that the latest glib as of this + // writing is 2.22. *sigh*) LL supplied *makeASCII family are + // also unsuitable since they allow control characters... + + // muhahaha ... Imprudence can ! + + + PLS_WARNS << "g_filename_display_name failed on" << filename_utf8 << ": "<< error->message << PLS_ENDL; + } + + if (filename_utf8) + { + picker->mFiles.push_back(std::string(filename_utf8)); + PLS_DEBUGS << "ADDED FILE " << filename_utf8 << PLS_ENDL; + g_free(filename_utf8); + } + + setlocale(LC_ALL, saved_locale.c_str()); +} + +// static +void LLFilePickerBase::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) +{ + LLFilePicker* picker = (LLFilePicker*)user_data; + + PLS_DEBUGS << "GTK DIALOG RESPONSE " << response << PLS_ENDL; + + if (response == GTK_RESPONSE_ACCEPT) + { + GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); + g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); + g_slist_foreach(file_list, (GFunc)g_free, NULL); + g_slist_free (file_list); + } + + gtk_widget_destroy(widget); + gtk_main_quit(); +} + + +GtkWindow* LLFilePickerBase::buildFilePicker(bool is_save, bool is_folder, std::string const& folder) +{ + if (LLWindowSDL::ll_try_gtk_init()) + { + GtkWidget *win = NULL; + GtkFileChooserAction pickertype = + is_save? + (is_folder? + GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : + GTK_FILE_CHOOSER_ACTION_SAVE) : + (is_folder? + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : + GTK_FILE_CHOOSER_ACTION_OPEN); + + win = gtk_file_chooser_dialog_new(NULL, NULL, + pickertype, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + is_folder ? + GTK_STOCK_APPLY : + (is_save ? + GTK_STOCK_SAVE : + GTK_STOCK_OPEN), + GTK_RESPONSE_ACCEPT, + (gchar *)NULL); + + if (!folder.empty()) + { + gtk_file_chooser_set_current_folder + (GTK_FILE_CHOOSER(win), + folder.c_str()); + } + +# if LL_X11 + // Make GTK tell the window manager to associate this + // dialog with our non-GTK raw X11 window, which should try + // to keep it on top etc. + if (mX11WindowID != None) + { + gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin + GdkWindow *gdkwin = gdk_window_foreign_new(mX11WindowID); + gdk_window_set_transient_for(GTK_WIDGET(win)->window, gdkwin); + } +# endif //LL_X11 + + g_signal_connect (GTK_FILE_CHOOSER(win), + "response", + G_CALLBACK(LLFilePickerBase::chooser_responder), + this); + + gtk_window_set_modal(GTK_WINDOW(win), TRUE); + + /* GTK 2.6: if (is_folder) + gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), + TRUE); */ + + return GTK_WINDOW(win); + } + else + { + return NULL; + } +} + +static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter, + GtkWindow *picker, + std::string filtername) +{ + gtk_file_filter_set_name(gfilter, filtername.c_str()); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), + gfilter); + GtkFileFilter *allfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(allfilter, "*"); + gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); +} + +static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker, + std::string pattern, + std::string filtername) +{ + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, pattern.c_str()); + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; +} + +static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, + std::string mime, + std::string filtername) +{ + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_mime_type(gfilter, mime.c_str()); + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; +} + +static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) +{ + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, "*.wav"); + gtk_file_filter_add_mime_type(gfilter,"audio/x-wav");//not working + + std::string filtername = LLTrans::getString("sound_files") + " (*.wav)"; + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; +} + +static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker) +{ + return add_simple_pattern_filter_to_gtkchooser(picker, "*.bvh", + LLTrans::getString("animation_files") + " (*.bvh)"); +} + +static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) +{ + GtkFileFilter *gfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(gfilter, "*.tga"); + gtk_file_filter_add_mime_type(gfilter, "image/jpeg"); + gtk_file_filter_add_mime_type(gfilter, "image/png"); + gtk_file_filter_add_mime_type(gfilter, "image/bmp"); + std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; + add_common_filters_to_gtkchooser(gfilter, picker, filtername); + return filtername; +} + + +bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) +{ + bool rtn = FALSE; + + //gViewerWindow->mWindow->beforeDialog(); + + reset(); + + GtkWindow* picker = buildFilePicker(true, false, folder); + + if (picker) + { + std::string suggest_name = "untitled"; + std::string suggest_ext = ""; + std::string caption = LLTrans::getString("save_file_verb") + " "; + switch (filter) + { + case FFSAVE_WAV: + caption += add_wav_filter_to_gtkchooser(picker); + suggest_ext = ".wav"; + break; + case FFSAVE_TGA: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); + suggest_ext = ".tga"; + break; + case FFSAVE_BMP: + caption += add_simple_mime_filter_to_gtkchooser + (picker, "image/bmp", LLTrans::getString("bitmap_image_files") + " (*.bmp)"); + suggest_ext = ".bmp"; + break; + case FFSAVE_AVI: + caption += add_simple_mime_filter_to_gtkchooser + (picker, "video/x-msvideo", + LLTrans::getString("avi_movie_file") + " (*.avi)"); + suggest_ext = ".avi"; + break; + case FFSAVE_ANIM: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); + suggest_ext = ".xaf"; + break; + case FFSAVE_XML: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); + suggest_ext = ".xml"; + break; + case FFSAVE_RAW: + caption += add_simple_pattern_filter_to_gtkchooser + (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); + suggest_ext = ".raw"; + break; + case FFSAVE_J2C: + caption += add_simple_mime_filter_to_gtkchooser + (picker, "images/jp2", + LLTrans::getString("compressed_image_files") + " (*.j2c)"); + suggest_ext = ".j2c"; + break; + default:; + break; + } + + gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); + + if (filename.empty()) + { + suggest_name += suggest_ext; + + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER(picker), + suggest_name.c_str()); + } + else + { + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER(picker), filename.c_str()); + } + + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + + rtn = (getFileCount() == 1); + } + + //gViewerWindow->mWindow->afterDialog(); + + return rtn; +} + +bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) +{ + bool rtn = FALSE; + + //gViewerWindow->mWindow->beforeDialog(); + + reset(); + + GtkWindow* picker = buildFilePicker(false, false, folder); + + if (picker) + { + std::string caption = LLTrans::getString("load_file_verb") + " "; + std::string filtername = ""; + switch (filter) + { + case FFLOAD_WAV: + filtername = add_wav_filter_to_gtkchooser(picker); + break; + case FFLOAD_ANIM: + filtername = add_bvh_filter_to_gtkchooser(picker); + break; + case FFLOAD_IMAGE: + filtername = add_imageload_filter_to_gtkchooser(picker); + break; + default:; + break; + } + + caption += filtername; + + gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); + + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + + rtn = (getFileCount() == 1); + } + + //gViewerWindow->mWindow->afterDialog(); + + return rtn; +} + +bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) +{ + bool rtn = FALSE; + + //gViewerWindow->mWindow->beforeDialog(); + + reset(); + + GtkWindow* picker = buildFilePicker(false, false, folder); + + if (picker) + { + gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), + TRUE); + + gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); + + gtk_widget_show_all(GTK_WIDGET(picker)); + gtk_main(); + rtn = !mFiles.empty(); + } + + //gViewerWindow->mWindow->afterDialog(); + + return rtn; +} + +# else // LL_GTK + +// Hacky stubs designed to facilitate fake getSaveFile and getLoadFile with +// static results, when we don't have a real filepicker. + +bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) +{ + reset(); + + PLS_INFOS << "getSaveFile suggested filename is [" << filename << "]" << PLS_ENDL; + if (!filename.empty()) + { + mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename); + return TRUE; + } + return FALSE; +} + +// FIXME: Use folder +bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) +{ + reset(); + + // HACK: Static filenames for 'open' until we implement filepicker + std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; + switch (filter) + { + case FFLOAD_WAV: filename += ".wav"; break; + case FFLOAD_IMAGE: filename += ".tga"; break; + case FFLOAD_ANIM: filename += ".bvh"; break; + default: break; + } + mFiles.push_back(filename); + PLS_INFOS << "getLoadFile: Will try to open file: " << hackyfilename << PLS_ENDL; + return TRUE; +} + +bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) +{ + reset(); + return FALSE; +} + +#endif // LL_GTK + +#else // not implemented + +bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) +{ + reset(); + return FALSE; +} + +bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) +{ + reset(); + return FALSE; +} + +bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) +{ + reset(); + return FALSE; +} + +#endif diff --git a/indra/plugins/filepicker/llfilepicker.h b/indra/plugins/filepicker/llfilepicker.h new file mode 100644 index 000000000..d14612112 --- /dev/null +++ b/indra/plugins/filepicker/llfilepicker.h @@ -0,0 +1,231 @@ +/** + * @file llfilepicker.h + * @brief OS-specific file picker + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-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$ + */ + +// OS specific file selection dialog. This is implemented as a +// singleton class, so call the instance() method to get the working +// instance. When you call getMultipleLoadFile(), it locks the picker +// until you iterate to the end of the list of selected files with +// getNextFile() or call reset(). + +#ifndef LL_LLFILEPICKER_H +#define LL_LLFILEPICKER_H + +#include "stdtypes.h" +#include +#include +#include + +#if LL_DARWIN +#include + +// AssertMacros.h does bad things. +#undef verify +#undef check +#undef require + +#include "llstring.h" + +#endif + +// Need commdlg.h for OPENFILENAMEA +#ifdef LL_WINDOWS +#include +#endif + +// mostly for Linux, possible on others +#if LL_GTK +# include "gtk/gtk.h" +#endif // LL_GTK + +// also mostly for Linux, for some X11-specific filepicker usability tweaks +#if LL_X11 +#include "SDL/SDL_syswm.h" +#endif + +// This class is used as base class of a singleton and is therefore not +// allowed to have any static members or static local variables! +class LLFilePickerBase +{ +public: + enum ELoadFilter + { + FFLOAD_ALL = 1, + FFLOAD_WAV = 2, + FFLOAD_IMAGE = 3, + FFLOAD_ANIM = 4, +#ifdef _CORY_TESTING + FFLOAD_GEOMETRY = 5, +#endif + FFLOAD_XML = 6, + FFLOAD_SLOBJECT = 7, + FFLOAD_RAW = 8, + FFLOAD_TEXT = 9, + }; + + enum ESaveFilter + { + FFSAVE_ALL = 1, + FFSAVE_WAV = 3, + FFSAVE_TGA = 4, + FFSAVE_BMP = 5, + FFSAVE_AVI = 6, + FFSAVE_ANIM = 7, +#ifdef _CORY_TESTING + FFSAVE_GEOMETRY = 8, +#endif + FFSAVE_XML = 9, + FFSAVE_COLLADA = 10, + FFSAVE_RAW = 11, + FFSAVE_J2C = 12, + FFSAVE_PNG = 13, + FFSAVE_JPEG = 14, + FFSAVE_HPA = 15, + FFSAVE_TEXT = 16, + FFSAVE_LSL = 17 + }; + + // open the dialog. This is a modal operation + bool getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder); + bool getLoadFile(ELoadFilter filter, std::string const& folder); + bool getMultipleLoadFiles(ELoadFilter filter, std::string const& folder); + + // Get the filename(s) found. getFirstFile() sets the pointer to + // the start of the structure and allows the start of iteration. + const std::string getFirstFile(); + + // getNextFile() increments the internal representation and + // returns the next file specified by the user. Returns NULL when + // no more files are left. Further calls to getNextFile() are + // undefined. + const std::string getNextFile(); + + // This utility function extracts the current file name without + // doing any incrementing. + const std::string getCurFile(); + + // Returns the index of the current file. + S32 getCurFileNum() const { return mCurrentFile; } + + S32 getFileCount() const { return (S32)mFiles.size(); } + + // See llvfs/lldir.h : getBaseFileName and getDirName to extract base or directory names + + // clear any lists of buffers or whatever, and make sure the file + // picker isn't locked. + void reset(); + +private: + enum + { + SINGLE_FILENAME_BUFFER_SIZE = 1024, + //FILENAME_BUFFER_SIZE = 65536 + FILENAME_BUFFER_SIZE = 65000 + }; + +#if LL_WINDOWS + OPENFILENAMEW mOFN; // for open and save dialogs + WCHAR mFilesW[FILENAME_BUFFER_SIZE]; + +public: + void setWindowID(unsigned long window_id) { mOFN.hwndOwner = (HWND)window_id; } + +private: + bool setupFilter(ELoadFilter filter); +#endif // LL_WINDOWS + +#if LL_DARWIN + NavDialogCreationOptions mNavOptions; + std::vector mFileVector; + UInt32 mFileIndex; + + OSStatus doNavChooseDialog(ELoadFilter filter); + OSStatus doNavSaveDialog(ESaveFilter filter, const std::string& filename); + void getFilePath(SInt32 index); + void getFileName(SInt32 index); + static Boolean navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode); +#endif // LL_DARWIN + +#if LL_GTK + static void add_to_selectedfiles(gpointer data, gpointer user_data); + static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); + // we remember the last path that was accessed for a particular usage + std::map mContextToPathMap; + std::string mCurContextName; +#if LL_X11 + Window mX11WindowID; +#endif + +public: + std::map & get_ContextToPathMap(void) { return mContextToPathMap; } +#if LL_X11 + void setWindowID(unsigned long window_id) { mX11WindowID = (Window)window_id; } +#endif + +#endif // LL_GTK +#if !LL_WINDOWS && !(LL_GTK && LL_X11) + void setWindowID(unsigned long window_id) { PLS_WARNS << "Calling unimplemented LLFilePickerBase::setWindowID" << PLS_ENDL; } +#endif + +private: + std::vector mFiles; + S32 mCurrentFile; + bool mLocked; + bool mMultiFile; + +protected: +#if LL_GTK + GtkWindow* buildFilePicker(bool is_save, bool is_folder, std::string const& folder); +#endif + +protected: + LLFilePickerBase(); +}; + +// True singleton, private constructors (and no friends). +class LLFilePicker : public LLFilePickerBase +{ +public: + // calling this before main() is undefined + static LLFilePicker& instance( void ) { return sInstance; } + +private: + static LLFilePicker sInstance; + + LLFilePicker() { } +}; + +namespace translation +{ + void add(std::string const& key, std::string const& translation); +} + +#endif diff --git a/indra/media_plugins/gstreamer010/CMakeLists.txt b/indra/plugins/gstreamer010/CMakeLists.txt similarity index 82% rename from indra/media_plugins/gstreamer010/CMakeLists.txt rename to indra/plugins/gstreamer010/CMakeLists.txt index 5786bd1e2..f8a2a510e 100644 --- a/indra/media_plugins/gstreamer010/CMakeLists.txt +++ b/indra/plugins/gstreamer010/CMakeLists.txt @@ -30,23 +30,13 @@ include_directories( ### media_plugin_gstreamer010 -if(NOT WORD_SIZE EQUAL 32) - if(WINDOWS) - add_definitions(/FIXED:NO) - else(WINDOWS) # not windows therefore gcc LINUX and DARWIN - add_definitions(-fPIC) - endif(WINDOWS) -endif(NOT WORD_SIZE EQUAL 32) - set(media_plugin_gstreamer010_SOURCE_FILES media_plugin_gstreamer010.cpp - llmediaimplgstreamer_syms.cpp llmediaimplgstreamervidplug.cpp ) set(media_plugin_gstreamer010_HEADER_FILES llmediaimplgstreamervidplug.h - llmediaimplgstreamer_syms.h llmediaimplgstreamertriviallogging.h ) @@ -69,4 +59,3 @@ add_dependencies(media_plugin_gstreamer010 ${LLCOMMON_LIBRARIES} ) - diff --git a/indra/plugins/gstreamer010/llmediaimplgstreamer.h b/indra/plugins/gstreamer010/llmediaimplgstreamer.h new file mode 100755 index 000000000..bfc443b9e --- /dev/null +++ b/indra/plugins/gstreamer010/llmediaimplgstreamer.h @@ -0,0 +1,60 @@ +/** + * @file llmediaimplgstreamer.h + * @author Tofu Linden + * @brief implementation that supports media playback via GStreamer. + * + * @cond + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +// header guard +#ifndef llmediaimplgstreamer_h +#define llmediaimplgstreamer_h + +#if LL_GSTREAMER010_ENABLED + +extern "C" { +#include +#include + +#include "apr_pools.h" +#include "apr_dso.h" +} + + +extern "C" { +gboolean llmediaimplgstreamer_bus_callback (GstBus *bus, + GstMessage *message, + gpointer data); +} + +#endif // LL_GSTREAMER010_ENABLED + +#endif // llmediaimplgstreamer_h diff --git a/indra/plugins/gstreamer010/llmediaimplgstreamertriviallogging.h b/indra/plugins/gstreamer010/llmediaimplgstreamertriviallogging.h new file mode 100755 index 000000000..bb90aa12f --- /dev/null +++ b/indra/plugins/gstreamer010/llmediaimplgstreamertriviallogging.h @@ -0,0 +1,65 @@ +/** + * @file llmediaimplgstreamertriviallogging.h + * @brief minimal logging utilities. + * + * @cond + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ +#define __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ + +#include + +///////////////////////////////////////////////////////////////////////// +// Debug/Info/Warning macros. +#if LL_WINDOWS +#include +#define LL_GETPID GetCurrentProcessId +#else +#include +#include +#define LL_GETPID getpid +#endif +#define MSGMODULEFOO "(media plugin)" +#define STDERRMSG(...) do{\ + fprintf(stderr, " pid:%d: ", (int)LL_GETPID());\ + fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\ + fprintf(stderr, __VA_ARGS__);\ + fputc('\n',stderr);\ + }while(0) +#define NULLMSG(...) do{}while(0) + +#define DEBUGMSG NULLMSG +#define INFOMSG STDERRMSG +#define WARNMSG STDERRMSG +///////////////////////////////////////////////////////////////////////// + +#endif /* __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ */ diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp b/indra/plugins/gstreamer010/llmediaimplgstreamervidplug.cpp old mode 100644 new mode 100755 similarity index 70% rename from indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp rename to indra/plugins/gstreamer010/llmediaimplgstreamervidplug.cpp index cdb7f4fae..5c8a99f0c --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp +++ b/indra/plugins/gstreamer010/llmediaimplgstreamervidplug.cpp @@ -1,28 +1,35 @@ /** - * @file llmediaimplgstreamervidplug.h + * @file llmediaimplgstreamervidplug.cpp * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl * * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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://secondlife.com/developers/opensource/gplv2 * - * 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. + * 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://secondlife.com/developers/opensource/flossexception * - * 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. + * 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. * - * 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 + * 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$ + * * @endcond */ @@ -34,15 +41,29 @@ #include #include -#include "llmediaimplgstreamer_syms.h" #include "llmediaimplgstreamertriviallogging.h" +// #include "llthread.h" #include "llmediaimplgstreamervidplug.h" - GST_DEBUG_CATEGORY_STATIC (gst_slvideo_debug); #define GST_CAT_DEFAULT gst_slvideo_debug +/* Filter signals and args *//* +enum +{ + *//* FILL ME *//* + LAST_SIGNAL +}; + +enum +{ + ARG_0 +}; + +#define SLV_SIZECAPS ", width=(int){1,2,4,8,16,32,64,128,256,512,1024}, height=(int){1,2,4,8,16,32,64,128,256,512,1024} " +#define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS ";" GST_VIDEO_CAPS_BGRx SLV_SIZECAPS +*/ #define SLV_SIZECAPS ", width=(int)[1,2048], height=(int)[1,2048] " #define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS @@ -74,9 +95,9 @@ gst_slvideo_base_init (gpointer gclass) }; GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - llgst_element_class_add_pad_template (element_class, - llgst_static_pad_template_get (&sink_factory)); - llgst_element_class_set_details (element_class, &element_details); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_factory)); + gst_element_class_set_details (element_class, &element_details); } @@ -87,7 +108,7 @@ gst_slvideo_finalize (GObject * object) slvideo = GST_SLVIDEO (object); if (slvideo->caps) { - llgst_caps_unref(slvideo->caps); + gst_caps_unref(slvideo->caps); } G_OBJECT_CLASS(parent_class)->finalize (object); @@ -98,7 +119,7 @@ static GstFlowReturn gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf) { GstSLVideo *slvideo; - llg_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); slvideo = GST_SLVIDEO(bsink); @@ -190,7 +211,7 @@ gst_slvideo_get_caps (GstBaseSink * bsink) GstSLVideo *slvideo; slvideo = GST_SLVIDEO(bsink); - return llgst_caps_ref (slvideo->caps); + return gst_caps_ref (slvideo->caps); } @@ -200,21 +221,32 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) { GstSLVideo *filter; GstStructure *structure; +// GstCaps *intersection; GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); filter = GST_SLVIDEO(bsink); - int width, height; +/* + intersection = gst_caps_intersect (filter->caps, caps); + if (gst_caps_is_empty (intersection)) + { + // no overlap between our caps and requested caps + return FALSE; + } + gst_caps_unref(intersection); +*/ + int width = 0; + int height = 0; gboolean ret; const GValue *fps; const GValue *par; - structure = llgst_caps_get_structure (caps, 0); - ret = llgst_structure_get_int (structure, "width", &width); - ret = ret && llgst_structure_get_int (structure, "height", &height); - fps = llgst_structure_get_value (structure, "framerate"); + structure = gst_caps_get_structure (caps, 0); + ret = gst_structure_get_int (structure, "width", &width); + ret = ret && gst_structure_get_int (structure, "height", &height); + fps = gst_structure_get_value (structure, "framerate"); ret = ret && (fps != NULL); - par = llgst_structure_get_value (structure, "pixel-aspect-ratio"); + par = gst_structure_get_value (structure, "pixel-aspect-ratio"); if (!ret) return FALSE; @@ -224,34 +256,35 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) filter->width = width; filter->height = height; - - filter->fps_n = llgst_value_get_fraction_numerator(fps); - filter->fps_d = llgst_value_get_fraction_denominator(fps); + filter->fps_n = gst_value_get_fraction_numerator(fps); + filter->fps_d = gst_value_get_fraction_denominator(fps); if (par) { - filter->par_n = llgst_value_get_fraction_numerator(par); - filter->par_d = llgst_value_get_fraction_denominator(par); + filter->par_n = gst_value_get_fraction_numerator(par); + filter->par_d = gst_value_get_fraction_denominator(par); } else { filter->par_n = 1; filter->par_d = 1; } + GST_VIDEO_SINK_WIDTH(filter) = width; GST_VIDEO_SINK_HEIGHT(filter) = height; - + // crufty lump - we *always* accept *only* RGBX now. /* + filter->format = SLV_PF_UNKNOWN; - if (0 == strcmp(llgst_structure_get_name(structure), + if (0 == strcmp(gst_structure_get_name(structure), "video/x-raw-rgb")) { int red_mask; int green_mask; int blue_mask; - llgst_structure_get_int(structure, "red_mask", &red_mask); - llgst_structure_get_int(structure, "green_mask", &green_mask); - llgst_structure_get_int(structure, "blue_mask", &blue_mask); + gst_structure_get_int(structure, "red_mask", &red_mask); + gst_structure_get_int(structure, "green_mask", &green_mask); + gst_structure_get_int(structure, "blue_mask", &blue_mask); if ((unsigned int)red_mask == 0xFF000000 && (unsigned int)green_mask == 0x00FF0000 && (unsigned int)blue_mask == 0x0000FF00) @@ -265,12 +298,13 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) filter->format = SLV_PF_BGRX; //fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n"); } - }*/ - + + }*/ + filter->format = SLV_PF_RGBX; GST_OBJECT_UNLOCK(filter); - + return TRUE; } @@ -317,15 +351,15 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, // we can ignore these and reverse-negotiate our preferred dimensions with // the peer if we like - we need to do this to obey dynamic resize requests // flowing in from the app. - structure = llgst_caps_get_structure (caps, 0); - if (!llgst_structure_get_int(structure, "width", &width) || - !llgst_structure_get_int(structure, "height", &height)) + structure = gst_caps_get_structure (caps, 0); + if (!gst_structure_get_int(structure, "width", &width) || + !gst_structure_get_int(structure, "height", &height)) { GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps); return GST_FLOW_NOT_NEGOTIATED; } - GstBuffer *newbuf = llgst_buffer_new(); + GstBuffer *newbuf = gst_buffer_new(); bool made_bufferdata_ptr = false; #define MAXDEPTHHACK 4 @@ -345,19 +379,19 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, GstCaps *desired_caps; GstStructure *desired_struct; - desired_caps = llgst_caps_copy (caps); - desired_struct = llgst_caps_get_structure (desired_caps, 0); + desired_caps = gst_caps_copy (caps); + desired_struct = gst_caps_get_structure (desired_caps, 0); GValue value = {0}; g_value_init(&value, G_TYPE_INT); g_value_set_int(&value, slwantwidth); - llgst_structure_set_value (desired_struct, "width", &value); + gst_structure_set_value (desired_struct, "width", &value); g_value_unset(&value); g_value_init(&value, G_TYPE_INT); g_value_set_int(&value, slwantheight); - llgst_structure_set_value (desired_struct, "height", &value); + gst_structure_set_value (desired_struct, "height", &value); - if (llgst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo), + if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo), desired_caps)) { // todo: re-use buffers from a pool? @@ -368,13 +402,13 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK; GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); - llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps); + gst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps); made_bufferdata_ptr = true; } else { // peer hates our cap suggestion INFOMSG("peer hates us :("); - llgst_caps_unref(desired_caps); + gst_caps_unref(desired_caps); } } } @@ -386,7 +420,7 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK; GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); - llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps); + gst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps); } *buf = GST_BUFFER_CAST(newbuf); @@ -428,6 +462,20 @@ gst_slvideo_class_init (GstSLVideoClass * klass) #undef LLGST_DEBUG_FUNCPTR } +/* +static void +gst_slvideo_update_caps (GstSLVideo * slvideo) +{ + GstCaps *caps; + + // GStreamer will automatically convert colourspace if necessary. + // GStreamer will automatically resize media to one of these enumerated + // powers-of-two that we ask for (yay GStreamer!) + caps = gst_caps_from_string (SLV_ALLCAPS); + + gst_caps_replace (&slvideo->caps, caps); +} +*/ /* initialize the new element * instantiate pads and add them to element @@ -450,24 +498,24 @@ gst_slvideo_init (GstSLVideo * filter, filter->retained_frame_width = filter->width; filter->retained_frame_height = filter->height; filter->retained_frame_format = SLV_PF_UNKNOWN; - GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS); - llgst_caps_replace (&filter->caps, caps); + GstCaps *caps = gst_caps_from_string (SLV_ALLCAPS); + gst_caps_replace (&filter->caps, caps); filter->resize_forced_always = false; filter->resize_try_width = -1; filter->resize_try_height = -1; GST_OBJECT_UNLOCK(filter); + + //gst_slvideo_update_caps(filter); } static void gst_slvideo_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - llg_return_if_fail (GST_IS_SLVIDEO (object)); + g_return_if_fail (GST_IS_SLVIDEO (object)); - switch (prop_id) { - default: + if (prop_id) { G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; } } @@ -475,12 +523,10 @@ static void gst_slvideo_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - llg_return_if_fail (GST_IS_SLVIDEO (object)); + g_return_if_fail (GST_IS_SLVIDEO (object)); - switch (prop_id) { - default: + if (prop_id) { G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; } } @@ -498,7 +544,7 @@ plugin_init (GstPlugin * plugin) GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin", 0, (gchar*)"Second Life Video Sink"); - return llgst_element_register (plugin, "private-slvideo", + return gst_element_register (plugin, "private-slvideo", GST_RANK_NONE, GST_TYPE_SLVIDEO); } @@ -508,20 +554,19 @@ plugin_init (GstPlugin * plugin) some g++ versions buggily avoid __attribute__((constructor)) functions - so we provide an explicit plugin init function. */ -#define PACKAGE (gchar*)"packagehack" -// this macro quietly refers to PACKAGE internally -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - (gchar*)"private-slvideoplugin", - (gchar*)"SL Video sink plugin", - plugin_init, (gchar*)"1.0", (gchar*)"LGPL", - (gchar*)"Second Life", - (gchar*)"http://www.secondlife.com/"); -#undef PACKAGE + void gst_slvideo_init_class (void) { - ll_gst_plugin_register_static (&gst_plugin_desc); - DEBUGMSG("CLASS INIT"); + gst_plugin_register_static( GST_VERSION_MAJOR, + GST_VERSION_MINOR, + (const gchar *)"private-slvideoplugin", + (gchar *)"SL Video sink plugin", + plugin_init, + (const gchar *)"0.1", + GST_LICENSE_UNKNOWN, + (const gchar *)"Second Life", + (const gchar *)"Second Life", + (const gchar *)"http://www.secondlife.com/" ); } #endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h b/indra/plugins/gstreamer010/llmediaimplgstreamervidplug.h old mode 100644 new mode 100755 similarity index 65% rename from indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h rename to indra/plugins/gstreamer010/llmediaimplgstreamervidplug.h index 29d65fa4e..5e8c72c98 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h +++ b/indra/plugins/gstreamer010/llmediaimplgstreamervidplug.h @@ -3,26 +3,33 @@ * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl * * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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://secondlife.com/developers/opensource/gplv2 * - * 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. + * 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://secondlife.com/developers/opensource/flossexception * - * 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. + * 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. * - * 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 + * 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$ + * * @endcond */ @@ -35,6 +42,7 @@ extern "C" { #include #include #include +// #include } G_BEGIN_DECLS diff --git a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/indra/plugins/gstreamer010/media_plugin_gstreamer010.cpp old mode 100644 new mode 100755 similarity index 70% rename from indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp rename to indra/plugins/gstreamer010/media_plugin_gstreamer010.cpp index 352b63583..8d0dc31e2 --- a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp +++ b/indra/plugins/gstreamer010/media_plugin_gstreamer010.cpp @@ -3,31 +3,49 @@ * @brief GStreamer-0.10 plugin for LLMedia API plugin system * * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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://secondlife.com/developers/opensource/gplv2 * - * 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. + * 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://secondlife.com/developers/opensource/flossexception * - * 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. + * 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. * - * 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 + * 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$ + * * @endcond */ #include "linden_common.h" +// Needed for _getcwd() RC +#ifdef LL_WINDOWS +#include +#include +#include +#endif + +#ifdef LL_DARWIN +#include +#endif + #include "llgl.h" #include "llplugininstance.h" @@ -39,6 +57,7 @@ extern "C" { #include +#include } #include "llmediaimplgstreamer.h" @@ -46,14 +65,12 @@ extern "C" { #include "llmediaimplgstreamervidplug.h" -#include "llmediaimplgstreamer_syms.h" - ////////////////////////////////////////////////////////////////////////////// // class MediaPluginGStreamer010 : public MediaPluginBase { public: - MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); ~MediaPluginGStreamer010(); /* virtual */ void receiveMessage(const char *message_string); @@ -61,6 +78,8 @@ public: static bool startup(); static bool closedown(); + static void set_gst_plugin_path(); + gboolean processGSTEvents(GstBus *bus, GstMessage *message); @@ -76,7 +95,7 @@ private: bool play(double rate); bool getTimePos(double &sec_out); - static const double MIN_LOOP_SEC = 1.0F; + #define MIN_LOOP_SEC 1.0F bool mIsLooping; @@ -132,11 +151,12 @@ private: bool mSeekWanted; double mSeekDestination; + + std::string mLastTitle; // Very GStreamer-specific GMainLoop *mPump; // event pump for this media GstElement *mPlaybin; - GstElement *mVisualizer; GstSLVideo *mVideoSink; }; @@ -144,9 +164,9 @@ private: bool MediaPluginGStreamer010::mDoneInit = false; MediaPluginGStreamer010::MediaPluginGStreamer010( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data ) : - MediaPluginBase(host_send_func, host_user_data), + LLPluginInstance::sendMessageFunction send_message_function, + LLPluginInstance* plugin_instance) : + MediaPluginBase(send_message_function, plugin_instance), mBusWatchID ( 0 ), mCurrentRowbytes ( 4 ), mTextureFormatPrimary ( GL_RGBA ), @@ -155,12 +175,11 @@ MediaPluginGStreamer010::MediaPluginGStreamer010( mSeekDestination(0.0), mPump ( NULL ), mPlaybin ( NULL ), - mVisualizer ( NULL ), mVideoSink ( NULL ), mCommand ( COMMAND_NONE ) { std::ostringstream str; - INFOMSG("MediaPluginGStreamer010 constructor - my PID=%u", U32(getpid())); + INFOMSG("MediaPluginGStreamer010 constructor - my PID=%u", U32(LL_GETPID())); } /////////////////////////////////////////////////////////////////////////////// @@ -191,149 +210,179 @@ MediaPluginGStreamer010::processGSTEvents(GstBus *bus, GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING) { DEBUGMSG("Got GST message type: %s", - LLGST_MESSAGE_TYPE_NAME (message)); + GST_MESSAGE_TYPE_NAME (message)); } else { // TODO: grok 'duration' message type DEBUGMSG("Got GST message type: %s", - LLGST_MESSAGE_TYPE_NAME (message)); + GST_MESSAGE_TYPE_NAME (message)); } - switch (GST_MESSAGE_TYPE (message)) { - case GST_MESSAGE_BUFFERING: { - // NEEDS GST 0.10.11+ - if (llgst_message_parse_buffering) + switch (GST_MESSAGE_TYPE (message)) + { + case GST_MESSAGE_BUFFERING: { + // NEEDS GST 0.10.11+ and America discovered by C.Columbus gint percent = 0; - llgst_message_parse_buffering(message, &percent); + gst_message_parse_buffering(message, &percent); DEBUGMSG("GST buffering: %d%%", percent); - } - break; - } - case GST_MESSAGE_STATE_CHANGED: { - GstState old_state; - GstState new_state; - GstState pending_state; - llgst_message_parse_state_changed(message, - &old_state, - &new_state, - &pending_state); -#ifdef LL_GST_REPORT_STATE_CHANGES - // not generally very useful, and rather spammy. - DEBUGMSG("state change (old,,pending): %s,<%s>,%s", - get_gst_state_name(old_state), - get_gst_state_name(new_state), - get_gst_state_name(pending_state)); -#endif // LL_GST_REPORT_STATE_CHANGES - switch (new_state) { - case GST_STATE_VOID_PENDING: - break; - case GST_STATE_NULL: - break; - case GST_STATE_READY: - setStatus(STATUS_LOADED); - break; - case GST_STATE_PAUSED: - setStatus(STATUS_PAUSED); - break; - case GST_STATE_PLAYING: - setStatus(STATUS_PLAYING); break; } - break; - } - case GST_MESSAGE_ERROR: { - GError *err = NULL; - gchar *debug = NULL; + case GST_MESSAGE_STATE_CHANGED: { + GstState old_state; + GstState new_state; + GstState pending_state; + gst_message_parse_state_changed(message, + &old_state, + &new_state, + &pending_state); + #ifdef LL_GST_REPORT_STATE_CHANGES + // not generally very useful, and rather spammy. + DEBUGMSG("state change (old,,pending): %s,<%s>,%s", + get_gst_state_name(old_state), + get_gst_state_name(new_state), + get_gst_state_name(pending_state)); + #endif // LL_GST_REPORT_STATE_CHANGES - llgst_message_parse_error (message, &err, &debug); - WARNMSG("GST error: %s", err?err->message:"(unknown)"); - if (err) - g_error_free (err); - g_free (debug); - - mCommand = COMMAND_STOP; - - setStatus(STATUS_ERROR); - - break; - } - case GST_MESSAGE_INFO: { - if (llgst_message_parse_info) + switch (new_state) + { + case GST_STATE_VOID_PENDING: + break; + case GST_STATE_NULL: + break; + case GST_STATE_READY: + setStatus(STATUS_LOADED); + break; + case GST_STATE_PAUSED: + setStatus(STATUS_PAUSED); + break; + case GST_STATE_PLAYING: + setStatus(STATUS_PLAYING); + break; + } + break; + } + case GST_MESSAGE_ERROR: + { + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_error (message, &err, &debug); + WARNMSG("GST error: %s", err?err->message:"(unknown)"); + if (err) + g_error_free (err); + g_free (debug); + + mCommand = COMMAND_STOP; + + setStatus(STATUS_ERROR); + + break; + } + case GST_MESSAGE_INFO: { GError *err = NULL; gchar *debug = NULL; - llgst_message_parse_info (message, &err, &debug); + gst_message_parse_info (message, &err, &debug); INFOMSG("GST info: %s", err?err->message:"(unknown)"); if (err) g_error_free (err); g_free (debug); + + break; } - break; - } - case GST_MESSAGE_WARNING: { - GError *err = NULL; - gchar *debug = NULL; - - llgst_message_parse_warning (message, &err, &debug); - WARNMSG("GST warning: %s", err?err->message:"(unknown)"); - if (err) - g_error_free (err); - g_free (debug); - - break; - } - case GST_MESSAGE_EOS: - /* end-of-stream */ - DEBUGMSG("GST end-of-stream."); - if (mIsLooping) + case GST_MESSAGE_WARNING: { - DEBUGMSG("looping media..."); - double eos_pos_sec = 0.0F; - bool got_eos_position = getTimePos(eos_pos_sec); + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_warning (message, &err, &debug); + WARNMSG("GST warning: %s", err?err->message:"(unknown)"); + if (err) + g_error_free (err); + g_free (debug); + + break; + } + case GST_MESSAGE_TAG: + { + GstTagList *new_tags; - if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) + gst_message_parse_tag( message, &new_tags ); + + gchar *title = NULL; + + if ( gst_tag_list_get_string(new_tags, GST_TAG_TITLE, &title) ) { - // if we know that the movie is really short, don't - // loop it else it can easily become a time-hog - // because of GStreamer spin-up overhead - DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec); - // inject a COMMAND_PAUSE - mCommand = COMMAND_PAUSE; - } - else - { -#undef LLGST_LOOP_BY_SEEKING -// loop with a stop-start instead of a seek, because it actually seems rather -// faster than seeking on remote streams. -#ifdef LLGST_LOOP_BY_SEEKING - // first, try looping by an explicit rewind - bool seeksuccess = seek(0.0); - if (seeksuccess) + //WARMING("Title: %s", title); + std::string newtitle(title); + gst_tag_list_free(new_tags); + + if ( newtitle != mLastTitle && !newtitle.empty() ) { - play(1.0); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", newtitle ); + sendMessage( message ); + mLastTitle = newtitle; + } + g_free(title); + } + + break; + } + case GST_MESSAGE_EOS: + { + /* end-of-stream */ + DEBUGMSG("GST end-of-stream."); + if (mIsLooping) + { + DEBUGMSG("looping media..."); + double eos_pos_sec = 0.0F; + bool got_eos_position = getTimePos(eos_pos_sec); + + if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) + { + // if we know that the movie is really short, don't + // loop it else it can easily become a time-hog + // because of GStreamer spin-up overhead + DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec); + // inject a COMMAND_PAUSE + mCommand = COMMAND_PAUSE; } else -#endif // LLGST_LOOP_BY_SEEKING - { // use clumsy stop-start to loop - DEBUGMSG("didn't loop by rewinding - stopping and starting instead..."); - stop(); - play(1.0); + { + #undef LLGST_LOOP_BY_SEEKING + // loop with a stop-start instead of a seek, because it actually seems rather + // faster than seeking on remote streams. + #ifdef LLGST_LOOP_BY_SEEKING + // first, try looping by an explicit rewind + bool seeksuccess = seek(0.0); + if (seeksuccess) + { + play(1.0); + } + else + #endif // LLGST_LOOP_BY_SEEKING + { // use clumsy stop-start to loop + DEBUGMSG("didn't loop by rewinding - stopping and starting instead..."); + stop(); + play(1.0); + } } } - } - else // not a looping media - { - // inject a COMMAND_STOP - mCommand = COMMAND_STOP; - } - break; - default: - /* unhandled message */ - break; + else // not a looping media + { + // inject a COMMAND_STOP + mCommand = COMMAND_STOP; + } + } break; + + default: + /* unhandled message */ + break; } /* we want to be notified again the next time there is a message @@ -539,12 +588,8 @@ MediaPluginGStreamer010::pause() { DEBUGMSG("pausing media..."); // todo: error-check this? - if (mDoneInit && mPlaybin) - { - llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); - return true; - } - return false; + gst_element_set_state(mPlaybin, GST_STATE_PAUSED); + return true; } bool @@ -552,12 +597,8 @@ MediaPluginGStreamer010::stop() { DEBUGMSG("stopping media..."); // todo: error-check this? - if (mDoneInit && mPlaybin) - { - llgst_element_set_state(mPlaybin, GST_STATE_READY); - return true; - } - return false; + gst_element_set_state(mPlaybin, GST_STATE_READY); + return true; } bool @@ -567,12 +608,8 @@ MediaPluginGStreamer010::play(double rate) DEBUGMSG("playing media... rate=%f", rate); // todo: error-check this? - if (mDoneInit && mPlaybin) - { - llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); - return true; - } - return false; + gst_element_set_state(mPlaybin, GST_STATE_PLAYING); + return true; } bool @@ -600,7 +637,7 @@ MediaPluginGStreamer010::seek(double time_sec) bool success = false; if (mDoneInit && mPlaybin) { - success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, + success = gst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, GstSeekFlags(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND), @@ -615,15 +652,13 @@ bool MediaPluginGStreamer010::getTimePos(double &sec_out) { bool got_position = false; - if (mDoneInit && mPlaybin) + if (mPlaybin) { gint64 pos; GstFormat timefmt = GST_FORMAT_TIME; - got_position = - llgst_element_query_position && - llgst_element_query_position(mPlaybin, - &timefmt, - &pos); + got_position = gst_element_query_position(mPlaybin, + &timefmt, + &pos); got_position = got_position && (timefmt == GST_FORMAT_TIME); // GStreamer may have other ideas, but we consider the current position @@ -665,7 +700,7 @@ MediaPluginGStreamer010::load() DEBUGMSG("setting up media..."); mIsLooping = false; - mVolume = 0.1234567; // minor hack to force an initial volume update + mVolume = (float) 0.1234567; // minor hack to force an initial volume update // Create a pumpable main-loop for this media mPump = g_main_loop_new (NULL, FALSE); @@ -676,7 +711,7 @@ MediaPluginGStreamer010::load() } // instantiate a playbin element to do the hard work - mPlaybin = llgst_element_factory_make ("playbin", "play"); + mPlaybin = gst_element_factory_make ("playbin", "play"); if (!mPlaybin) { setStatus(STATUS_ERROR); @@ -684,50 +719,21 @@ MediaPluginGStreamer010::load() } // get playbin's bus - GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); + GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); if (!bus) { setStatus(STATUS_ERROR); return false; // error } - mBusWatchID = llgst_bus_add_watch (bus, + mBusWatchID = gst_bus_add_watch (bus, llmediaimplgstreamer_bus_callback, this); - llgst_object_unref (bus); - -#if 0 // not quite stable/correct yet - // get a visualizer element (bonus feature!) - char* vis_name = getenv("LL_GST_VIS_NAME"); - if (!vis_name || - (vis_name && std::string(vis_name)!="none")) - { - if (vis_name) - { - mVisualizer = llgst_element_factory_make (vis_name, "vis"); - } - if (!mVisualizer) - { - mVisualizer = llgst_element_factory_make ("libvisual_jess", "vis"); - if (!mVisualizer) - { - mVisualizer = llgst_element_factory_make ("goom", "vis"); - if (!mVisualizer) - { - mVisualizer = llgst_element_factory_make ("libvisual_lv_scope", "vis"); - if (!mVisualizer) - { - // That's okay, we don't NEED this. - } - } - } - } - } -#endif + gst_object_unref (bus); if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) { // instantiate a custom video sink mVideoSink = - GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo")); + GST_SLVIDEO(gst_element_factory_make ("private-slvideo", "slvideo")); if (!mVideoSink) { WARNMSG("Could not instantiate private-slvideo element."); @@ -740,11 +746,6 @@ MediaPluginGStreamer010::load() g_object_set(mPlaybin, "video-sink", mVideoSink, NULL); } - if (mVisualizer) - { - g_object_set(mPlaybin, "vis-plugin", mVisualizer, NULL); - } - return true; } @@ -762,17 +763,11 @@ MediaPluginGStreamer010::unload () if (mPlaybin) { - llgst_element_set_state (mPlaybin, GST_STATE_NULL); - llgst_object_unref (GST_OBJECT (mPlaybin)); + gst_element_set_state (mPlaybin, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (mPlaybin)); mPlaybin = NULL; } - if (mVisualizer) - { - llgst_object_unref (GST_OBJECT (mVisualizer)); - mVisualizer = NULL; - } - if (mPump) { g_main_loop_quit(mPump); @@ -802,7 +797,10 @@ MediaPluginGStreamer010::startup() // Init the glib type system - we need it. g_type_init(); + set_gst_plugin_path(); + +/* // Get symbols! #if LL_DARWIN if (! grab_gst_syms("libgstreamer-0.10.dylib", @@ -818,24 +816,24 @@ MediaPluginGStreamer010::startup() WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled."); return false; } - - if (llgst_segtrap_set_enabled) - { - llgst_segtrap_set_enabled(FALSE); - } - else - { - WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught."); - } - +*/ +// if (gst_segtrap_set_enabled) +// { + gst_segtrap_set_enabled(FALSE); +// } +// else +// { +// WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught."); +// } +/* #if LL_LINUX // Gstreamer tries a fork during init, waitpid-ing on it, // which conflicts with any installed SIGCHLD handler... struct sigaction tmpact, oldact; - if (llgst_registry_fork_set_enabled) { + if (gst_registry_fork_set_enabled) { // if we can disable SIGCHLD-using forking behaviour, // do it. - llgst_registry_fork_set_enabled(false); + gst_registry_fork_set_enabled(false); } else { // else temporarily install default SIGCHLD handler @@ -846,24 +844,24 @@ MediaPluginGStreamer010::startup() sigaction(SIGCHLD, &tmpact, &oldact); } #endif // LL_LINUX - +*/ // Protect against GStreamer resetting the locale, yuck. static std::string saved_locale; saved_locale = setlocale(LC_ALL, NULL); // finally, try to initialize GStreamer! GError *err = NULL; - gboolean init_gst_success = llgst_init_check(NULL, NULL, &err); + gboolean init_gst_success = gst_init_check(NULL, NULL, &err); // restore old locale setlocale(LC_ALL, saved_locale.c_str() ); - +/* #if LL_LINUX // restore old SIGCHLD handler - if (!llgst_registry_fork_set_enabled) + if (!gst_registry_fork_set_enabled) sigaction(SIGCHLD, &oldact, NULL); #endif // LL_LINUX - +*/ if (!init_gst_success) // fail { if (err) @@ -877,16 +875,139 @@ MediaPluginGStreamer010::startup() } return false; } - + + // Set up logging facilities + gst_debug_remove_log_function( gst_debug_log_default ); +// gst_debug_add_log_function( gstreamer_log, NULL ); + // Init our custom plugins - only really need do this once. gst_slvideo_init_class(); - +/* + // List the plugins GStreamer can find + LL_DEBUGS("MediaImpl") << "Found GStreamer plugins:" << LL_ENDL; + GList *list; + GstRegistry *registry = gst_registry_get_default(); + std::string loaded = ""; + for (list = gst_registry_get_plugin_list(registry); + list != NULL; + list = g_list_next(list)) + { + GstPlugin *list_plugin = (GstPlugin *)list->data; + (bool)gst_plugin_is_loaded(list_plugin) ? loaded = "Yes" : loaded = "No"; + LL_DEBUGS("MediaImpl") << gst_plugin_get_name(list_plugin) << ", loaded? " << loaded << LL_ENDL; + } + gst_plugin_list_free(list); +*/ mDoneInit = true; } return true; } +void MediaPluginGStreamer010::set_gst_plugin_path() +{ + // Linux sets GST_PLUGIN_PATH in wrapper.sh, not here. +#if LL_WINDOWS || LL_DARWIN + + std::string imp_dir = ""; + + // Get the current working directory: +#if LL_WINDOWS + char* raw_dir; + raw_dir = _getcwd(NULL,0); + if( raw_dir != NULL ) + { + imp_dir = std::string( raw_dir ); + } +#elif LL_DARWIN + CFBundleRef main_bundle = CFBundleGetMainBundle(); + if( main_bundle != NULL ) + { + CFURLRef bundle_url = CFBundleCopyBundleURL( main_bundle ); + if( bundle_url != NULL ) + { + #ifndef MAXPATHLEN + #define MAXPATHLEN 1024 + #endif + char raw_dir[MAXPATHLEN]; + if( CFURLGetFileSystemRepresentation( bundle_url, true, (UInt8 *)raw_dir, MAXPATHLEN) ) + { + imp_dir = std::string( raw_dir ) + "/Contents/MacOS/"; + } + CFRelease(bundle_url); + } + } +#endif + + if( imp_dir == "" ) + { + WARNMSG("Could not get application directory, not setting GST_PLUGIN_PATH."); + return; + } + + DEBUGMSG("Imprudence is installed at %s", imp_dir); + + // ":" on Mac and 'Nix, ";" on Windows + std::string separator = G_SEARCHPATH_SEPARATOR_S; + + // Grab the current path, if it's set. + std::string old_plugin_path = ""; + char *old_path = getenv("GST_PLUGIN_PATH"); + if(old_path == NULL) + { + DEBUGMSG("Did not find user-set GST_PLUGIN_PATH."); + } + else + { + old_plugin_path = separator + std::string( old_path ); + } + + + // Search both Imprudence and Imprudence\lib\gstreamer-plugins. + // But we also want to search the path the user has set, if any. + std::string plugin_path = + "GST_PLUGIN_PATH=" + +#if LL_WINDOWS + imp_dir + "\\lib\\gstreamer-plugins" + +#elif LL_DARWIN + imp_dir + separator + + imp_dir + "/../Resources/lib/gstreamer-plugins" + +#endif + old_plugin_path; + + int put_result; + + // Place GST_PLUGIN_PATH in the environment settings +#if LL_WINDOWS + put_result = _putenv( (char*)plugin_path.c_str() ); +#elif LL_DARWIN + put_result = putenv( (char*)plugin_path.c_str() ); +#endif + + if( put_result == -1 ) + { + WARNMSG("Setting GST_PLUGIN_PATH failed!"); + } + else + { + DEBUGMSG("GST_PLUGIN_PATH set to %s", getenv("GST_PLUGIN_PATH")); + } + + // Don't load system plugins. We only want to use ours, to avoid conflicts. +#if LL_WINDOWS + put_result = _putenv( "GST_PLUGIN_SYSTEM_PATH=\"\"" ); +#elif LL_DARWIN + put_result = putenv( "GST_PLUGIN_SYSTEM_PATH=\"\"" ); +#endif + + if( put_result == -1 ) + { + WARNMSG("Setting GST_PLUGIN_SYSTEM_PATH=\"\" failed!"); + } + +#endif // LL_WINDOWS || LL_DARWIN +} + void MediaPluginGStreamer010::sizeChanged() @@ -928,7 +1049,7 @@ MediaPluginGStreamer010::closedown() if (!mDoneInit) return false; // error - ungrab_gst_syms(); +// ungrab_gst_syms(); mDoneInit = false; @@ -949,11 +1070,10 @@ std::string MediaPluginGStreamer010::getVersion() { std::string plugin_version = "GStreamer010 media plugin, GStreamer version "; - if (mDoneInit && - llgst_version) + if (mDoneInit) // && gst_version) { guint major, minor, micro, nano; - llgst_version(&major, &minor, µ, &nano); + gst_version(&major, &minor, µ, &nano); plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO); } else @@ -1211,14 +1331,11 @@ void MediaPluginGStreamer010::receiveMessage(const char *message_string) } } -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +int create_plugin(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance, BasicPluginBase** plugin_object) { if (MediaPluginGStreamer010::startup()) { - MediaPluginGStreamer010 *self = new MediaPluginGStreamer010(host_send_func, host_user_data); - *plugin_send_func = MediaPluginGStreamer010::staticReceiveMessage; - *plugin_user_data = (void*)self; - + *plugin_object = new MediaPluginGStreamer010(send_message_function, plugin_instance); return 0; // okay } else @@ -1234,15 +1351,14 @@ int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void class MediaPluginGStreamer010 : public MediaPluginBase { public: - MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); ~MediaPluginGStreamer010(); /* virtual */ void receiveMessage(const char *message_string); }; MediaPluginGStreamer010::MediaPluginGStreamer010( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data ) : - MediaPluginBase(host_send_func, host_user_data) + LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) : + MediaPluginBase(send_message_function, plugin_instance) { // no-op } @@ -1258,7 +1374,7 @@ void MediaPluginGStreamer010::receiveMessage(const char *message_string) } // We're building without GStreamer enabled. Just refuse to initialize. -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +int create_plugin(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance, BasicPluginBase** plugin_object) { return -1; } diff --git a/indra/media_plugins/quicktime/CMakeLists.txt b/indra/plugins/quicktime/CMakeLists.txt old mode 100644 new mode 100755 similarity index 97% rename from indra/media_plugins/quicktime/CMakeLists.txt rename to indra/plugins/quicktime/CMakeLists.txt index df191f543..c827404c2 --- a/indra/media_plugins/quicktime/CMakeLists.txt +++ b/indra/plugins/quicktime/CMakeLists.txt @@ -30,7 +30,6 @@ if (DARWIN) find_library(CARBON_LIBRARY Carbon) endif (DARWIN) - ### media_plugin_quicktime set(media_plugin_quicktime_SOURCE_FILES @@ -77,7 +76,7 @@ if (QUICKTIME) PREFIX "" BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@executable_path" - LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base_media/media_plugin_base.exp" ) # We use a bunch of deprecated system APIs. diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/plugins/quicktime/media_plugin_quicktime.cpp old mode 100644 new mode 100755 similarity index 95% rename from indra/media_plugins/quicktime/media_plugin_quicktime.cpp rename to indra/plugins/quicktime/media_plugin_quicktime.cpp index 1f516c0c5..a03cadf19 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/plugins/quicktime/media_plugin_quicktime.cpp @@ -40,10 +40,6 @@ #if defined(LL_DARWIN) #include #elif defined(LL_WINDOWS) - #undef __STDC_CONSTANT_MACROS //Needed, as boost/unordered_map.hpp already defines INT32_C, etc. - #if defined(_MSC_VER) && _MSC_VER >= 1600 - #define _STDINT_H //Visual Studio 2010 includes its own stdint header already - #endif #include "MacTypes.h" #include "QTML.h" #include "Movies.h" @@ -58,7 +54,7 @@ class MediaPluginQuickTime : public MediaPluginBase { public: - MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + MediaPluginQuickTime(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); ~MediaPluginQuickTime(); /* virtual */ void receiveMessage(const char *message_string); @@ -768,9 +764,9 @@ private: }; MediaPluginQuickTime::MediaPluginQuickTime( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data ) : - MediaPluginBase(host_send_func, host_user_data), + LLPluginInstance::sendMessageFunction send_message_function, + LLPluginInstance* plugin_instance) : + MediaPluginBase(send_message_function, plugin_instance), mMinWidth( 0 ), mMaxWidth( 2048 ), mMinHeight( 0 ), @@ -1067,12 +1063,9 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) }; } -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +int create_plugin(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance, BasicPluginBase** plugin_object) { - MediaPluginQuickTime *self = new MediaPluginQuickTime(host_send_func, host_user_data); - *plugin_send_func = MediaPluginQuickTime::staticReceiveMessage; - *plugin_user_data = (void*)self; - + *plugin_object = new MediaPluginQuickTime(send_message_function, plugin_instance); return 0; } @@ -1083,15 +1076,15 @@ int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void class MediaPluginQuickTime : public MediaPluginBase { public: - MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + MediaPluginQuickTime(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); ~MediaPluginQuickTime(); /* virtual */ void receiveMessage(const char *message_string); }; MediaPluginQuickTime::MediaPluginQuickTime( - LLPluginInstance::sendMessageFunction host_send_func, - void *host_user_data ) : - MediaPluginBase(host_send_func, host_user_data) + LLPluginInstance::sendMessageFunction send_message_function, + LLPluginInstance* plugin_instance) : + MediaPluginBase(send_message_function, plugin_instance) { // no-op } @@ -1107,7 +1100,7 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) } // We're building without quicktime enabled. Just refuse to initialize. -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +int create_plugin(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance, BasicPluginBase** plugin_object) { return -1; } diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/plugins/webkit/CMakeLists.txt similarity index 88% rename from indra/media_plugins/webkit/CMakeLists.txt rename to indra/plugins/webkit/CMakeLists.txt index 3b1f67954..1ffa2608a 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/plugins/webkit/CMakeLists.txt @@ -30,17 +30,8 @@ include_directories( ${LLQTWEBKIT_INCLUDE_DIR} ) - ### media_plugin_webkit -if(NOT WORD_SIZE EQUAL 32) - if(WINDOWS) - add_definitions(/FIXED:NO) - else(WINDOWS) # not windows therefore gcc LINUX and DARWIN - add_definitions(-fPIC) - endif(WINDOWS) -endif(NOT WORD_SIZE EQUAL 32) - set(media_plugin_webkit_SOURCE_FILES media_plugin_webkit.cpp ) @@ -60,11 +51,9 @@ set(media_plugin_webkit_LINK_LIBRARIES # Select which VolumeCatcher implementation to use if (LINUX) - if (PULSEAUDIO_FOUND) + if (PULSEAUDIO) list(APPEND media_plugin_webkit_SOURCE_FILES linux_volume_catcher.cpp) - else (PULSEAUDIO_FOUND) - list(APPEND media_plugin_webkit_SOURCE_FILES dummy_volume_catcher.cpp) - endif (PULSEAUDIO_FOUND) + endif (PULSEAUDIO) list(APPEND media_plugin_webkit_LINK_LIBRARIES ${UI_LIBRARIES} # for glib/GTK ) @@ -78,6 +67,9 @@ elseif (DARWIN) ) elseif (WINDOWS) list(APPEND media_plugin_webkit_SOURCE_FILES windows_volume_catcher.cpp) +else (LINUX) + # All other platforms use the dummy volume catcher for now. + list(APPEND media_plugin_webkit_SOURCE_FILES dummy_volume_catcher.cpp) endif (LINUX) set_source_files_properties(${media_plugin_webkit_HEADER_FILES} @@ -114,7 +106,7 @@ if (DARWIN) PREFIX "" BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@executable_path" - LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base_media/media_plugin_base.exp" ) # copy the webkit dylib to the build directory diff --git a/indra/plugins/webkit/dummy_volume_catcher.cpp b/indra/plugins/webkit/dummy_volume_catcher.cpp new file mode 100644 index 000000000..4df988789 --- /dev/null +++ b/indra/plugins/webkit/dummy_volume_catcher.cpp @@ -0,0 +1,65 @@ +/** + * @file dummy_volume_catcher.cpp + * @brief A null implementation of the "VolumeCatcher" class for platforms where it's not implemented yet. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#include "volume_catcher.h" + + +class VolumeCatcherImpl +{ +}; + +///////////////////////////////////////////////////// + +VolumeCatcher::VolumeCatcher() +{ + pimpl = NULL; +} + +VolumeCatcher::~VolumeCatcher() +{ +} + +void VolumeCatcher::setVolume(F32 volume) +{ +} + +void VolumeCatcher::setPan(F32 pan) +{ +} + +void VolumeCatcher::pump() +{ +} + diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/plugins/webkit/linux_volume_catcher.cpp similarity index 90% rename from indra/media_plugins/webkit/linux_volume_catcher.cpp rename to indra/plugins/webkit/linux_volume_catcher.cpp index 321d1f91f..cc3836ea5 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/plugins/webkit/linux_volume_catcher.cpp @@ -3,26 +3,33 @@ * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources * * @cond - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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://secondlife.com/developers/opensource/gplv2 * - * 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. + * 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://secondlife.com/developers/opensource/flossexception * - * 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. + * 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. * - * 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 + * 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$ + * * @endcond */ @@ -35,8 +42,9 @@ 5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call */ +# include //imprudence + #include "linden_common.h" -#include #include "volume_catcher.h" diff --git a/indra/plugins/webkit/linux_volume_catcher.h b/indra/plugins/webkit/linux_volume_catcher.h new file mode 100755 index 000000000..d4a1b38f9 --- /dev/null +++ b/indra/plugins/webkit/linux_volume_catcher.h @@ -0,0 +1,56 @@ +/** + * @file linux_volume_catcher.h + * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#ifndef LINUX_VOLUME_CATCHER_H +#define LINUX_VOLUME_CATCHER_H + +#include "linden_common.h" + +class LinuxVolumeCatcherImpl; + +class LinuxVolumeCatcher +{ + public: + LinuxVolumeCatcher(); + ~LinuxVolumeCatcher(); + + void setVolume(F32 volume); // 0.0 - 1.0 + void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume + + private: + LinuxVolumeCatcherImpl *pimpl; +}; + +#endif // LINUX_VOLUME_CATCHER_H diff --git a/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc b/indra/plugins/webkit/linux_volume_catcher_pa_syms.inc similarity index 100% rename from indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc rename to indra/plugins/webkit/linux_volume_catcher_pa_syms.inc diff --git a/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc b/indra/plugins/webkit/linux_volume_catcher_paglib_syms.inc similarity index 100% rename from indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc rename to indra/plugins/webkit/linux_volume_catcher_paglib_syms.inc diff --git a/indra/media_plugins/webkit/mac_volume_catcher.cpp b/indra/plugins/webkit/mac_volume_catcher.cpp similarity index 85% rename from indra/media_plugins/webkit/mac_volume_catcher.cpp rename to indra/plugins/webkit/mac_volume_catcher.cpp index 8a06bb848..190823f73 100644 --- a/indra/media_plugins/webkit/mac_volume_catcher.cpp +++ b/indra/plugins/webkit/mac_volume_catcher.cpp @@ -3,26 +3,33 @@ * @brief A Mac OS X specific hack to control the volume level of all audio channels opened by a process. * * @cond - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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://secondlife.com/developers/opensource/gplv2 * - * 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. + * 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://secondlife.com/developers/opensource/flossexception * - * 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. + * 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. * - * 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 + * 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$ + * * @endcond */ diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/plugins/webkit/media_plugin_webkit.cpp old mode 100644 new mode 100755 similarity index 93% rename from indra/media_plugins/webkit/media_plugin_webkit.cpp rename to indra/plugins/webkit/media_plugin_webkit.cpp index 4ae84e952..97920cf9f --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/plugins/webkit/media_plugin_webkit.cpp @@ -33,9 +33,10 @@ * @endcond */ +#include "linden_common.h" + #include "llqtwebkit.h" -#include "linden_common.h" #include "indra_constants.h" // for indra keyboard codes #include "llgl.h" @@ -44,6 +45,7 @@ #include "llpluginmessage.h" #include "llpluginmessageclasses.h" #include "media_plugin_base.h" +#include // set to 1 if you're using the version of llqtwebkit that's QPixmap-ified #if LL_LINUX @@ -64,7 +66,6 @@ extern "C" { # include # include #endif -#include #if LL_WINDOWS // *NOTE:Mani - This captures the module handle for the dll. This is used below @@ -78,6 +79,20 @@ extern "C" { } #endif +#ifdef LL_STANDALONE +#include +#elif defined(LL_LINUX) +// We don't provide Qt headers for non-standalone, therefore define this here. +// Our prebuilt is built with QT_NAMESPACE undefined. +#define QT_MANGLE_NAMESPACE(name) name +#define Q_INIT_RESOURCE(name) \ + do { extern int QT_MANGLE_NAMESPACE(qInitResources_ ## name) (); \ + QT_MANGLE_NAMESPACE(qInitResources_ ## name) (); } while (0) +#else +// Apparently this symbol doesn't exist in the windows and Mac tar balls provided by LL. +#define Q_INIT_RESOURCE(name) /*nothing*/ +#endif + //////////////////////////////////////////////////////////////////////////////// // class MediaPluginWebKit : @@ -85,7 +100,7 @@ class MediaPluginWebKit : public LLEmbeddedBrowserWindowObserver { public: - MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + MediaPluginWebKit(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); ~MediaPluginWebKit(); /*virtual*/ void receiveMessage(const char *message_string); @@ -123,7 +138,6 @@ private: F32 mBackgroundR; F32 mBackgroundG; F32 mBackgroundB; - std::string mTarget; VolumeCatcher mVolumeCatcher; @@ -312,7 +326,11 @@ private: LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); // create single browser window - mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget); +#if LLQTWEBKIT_API_VERSION >= 2 + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow(mWidth, mHeight /*, mTarget*/ ); // We don't have mTarget yet. +#else + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight ); +#endif // tell LLQtWebKit about the size of the browser window LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); @@ -322,6 +340,12 @@ private: // append details to agent string LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); + +// Viewer 2+ -- MC +#if LL_WINDOWS + // Set up window open behavior + LLQtWebKit::getInstance()->setWindowOpenBehavior(mBrowserWindowId, LLQtWebKit::WOB_SIMULATE_BLANK_HREF_CLICK); +#endif #if !LL_QTWEBKIT_USES_PIXMAPS // don't flip bitmap @@ -513,9 +537,16 @@ private: void onClickLinkHref(const EventType& event) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); +#if LLQTWEBKIT_API_VERSION >= 2 message.setValue("uri", event.getEventUri()); message.setValue("target", event.getStringValue()); message.setValue("uuid", event.getStringValue2()); +#else + // This will work as long as we don't need "uuid", which will be needed for MoaP. + message.setValue("uri", event.getStringValue()); + message.setValue("target", event.getStringValue2()); + message.setValueU32("target_type", event.getLinkType()); +#endif sendMessage(message); } @@ -524,10 +555,13 @@ private: void onClickLinkNoFollow(const EventType& event) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); +#if LLQTWEBKIT_API_VERSION >= 2 message.setValue("uri", event.getEventUri()); +#else + message.setValue("uri", event.getStringValue()); +#endif sendMessage(message); } - //////////////////////////////////////////////////////////////////////////////// // virtual @@ -540,42 +574,6 @@ private: // message.setValueBoolean("dead", (event.getIntValue() != 0)) sendMessage(message); } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onWindowCloseRequested(const EventType& event) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request"); - message.setValue("uuid", event.getStringValue()); - sendMessage(message); - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onWindowGeometryChangeRequested(const EventType& event) - { - int x, y, width, height; - event.getRectValue(x, y, width, height); - - // This sometimes gets called with a zero-size request. Don't pass these along. - if(width > 0 && height > 0) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change"); - message.setValue("uuid", event.getStringValue()); - message.setValueS32("x", x); - message.setValueS32("y", y); - message.setValueS32("width", width); - message.setValueS32("height", height); - sendMessage(message); - } - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - std::string onRequestFilePicker( const EventType& eventIn ) - { - return blockingPickFile(); - } LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers) { @@ -721,31 +719,11 @@ private: } } - - std::string mPickedFile; - - std::string blockingPickFile(void) - { - mPickedFile.clear(); - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file"); - message.setValueBoolean("blocking_request", true); - - // The "blocking_request" key in the message means this sendMessage call will block until a response is received. - sendMessage(message); - - return mPickedFile; - } - - void onPickFileResponse(const std::string &file) - { - mPickedFile = file; - } }; -MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : - MediaPluginBase(host_send_func, host_user_data) +MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) : + MediaPluginBase(send_message_function, plugin_instance) { // std::cerr << "MediaPluginWebKit constructor" << std::endl; @@ -766,6 +744,9 @@ MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_ mJavascriptEnabled = true; // default to on mPluginsEnabled = true; // default to on mUserAgent = "LLPluginMedia Web Browser"; + + // Initialize WebCore resource. + Q_INIT_RESOURCE(WebCore); } MediaPluginWebKit::~MediaPluginWebKit() @@ -879,8 +860,6 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) { if(message_name == "init") { - mTarget = message_in.getValue("target"); - // This is the media init message -- all necessary data for initialization should have been received. if(initBrowser()) { @@ -1100,14 +1079,10 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE ); checkEditState(); } - if(message_name == "pick_file_response") - { - onPickFileResponse(message_in.getValue("file")); - } else { // std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; - } + }; } else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) { @@ -1207,17 +1182,6 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) } } } - else if(message_name == "proxy_window_opened") - { - std::string target = message_in.getValue("target"); - std::string uuid = message_in.getValue("uuid"); - LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid); - } - else if(message_name == "proxy_window_closed") - { - std::string uuid = message_in.getValue("uuid"); - LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid); - } else { // std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl; @@ -1235,12 +1199,9 @@ void MediaPluginWebKit::setVolume(F32 volume) mVolumeCatcher.setVolume(volume); } -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +int create_plugin(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance, BasicPluginBase** plugin_object) { - MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data); - *plugin_send_func = MediaPluginWebKit::staticReceiveMessage; - *plugin_user_data = (void*)self; - + *plugin_object = new MediaPluginWebKit(send_message_function, plugin_instance); return 0; } diff --git a/indra/plugins/webkit/volume_catcher.h b/indra/plugins/webkit/volume_catcher.h new file mode 100644 index 000000000..855e99fc0 --- /dev/null +++ b/indra/plugins/webkit/volume_catcher.h @@ -0,0 +1,61 @@ +/** + * @file volume_catcher.h + * @brief Interface to a class with platform-specific implementations that allows control of the audio volume of all sources in the current process. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + * @endcond + */ + +#ifndef VOLUME_CATCHER_H +#define VOLUME_CATCHER_H + +#include "linden_common.h" + +class VolumeCatcherImpl; + +class VolumeCatcher +{ + public: + VolumeCatcher(); + ~VolumeCatcher(); + + void setVolume(F32 volume); // 0.0 - 1.0 + + // Set the left-right pan of audio sources + // where -1.0 = left, 0 = center, and 1.0 = right + void setPan(F32 pan); + + void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume + + private: + VolumeCatcherImpl *pimpl; +}; + +#endif // VOLUME_CATCHER_H diff --git a/indra/media_plugins/webkit/windows_volume_catcher.cpp b/indra/plugins/webkit/windows_volume_catcher.cpp similarity index 61% rename from indra/media_plugins/webkit/windows_volume_catcher.cpp rename to indra/plugins/webkit/windows_volume_catcher.cpp index 46a7a3db6..64f70c419 100644 --- a/indra/media_plugins/webkit/windows_volume_catcher.cpp +++ b/indra/plugins/webkit/windows_volume_catcher.cpp @@ -3,30 +3,39 @@ * @brief A Windows implementation of volume level control of all audio channels opened by a process. * * @cond - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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://secondlife.com/developers/opensource/gplv2 * - * 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. + * 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://secondlife.com/developers/opensource/flossexception * - * 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. + * 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. * - * 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 + * 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$ + * * @endcond */ #include "volume_catcher.h" +# define WIN32_LEAN_AND_MEAN +# include #include #include "llmemory.h" class VolumeCatcherImpl : public LLSingleton From c46c86ca4bbad98c32a6350a34309389026ac551 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 6 May 2011 16:29:43 +0200 Subject: [PATCH 08/87] Split plugin classes and derive AIFilePicker from BasicPluginBase (part 4). Add back fixes that were in Singularity (in indra/media_plugins) but not in imprudence. Also: Add "shutdown" plugin message and terminate file picker plugins cleanly. The DSO (libbasic_plugin_filepicker.so) now tells the child process / plugin loader (SLPlugin) to terminate (using the 'shutdown' message), and AIFilePicker::finish_impl destroys the plugin object on the viewer side when it's ... finished thus. Also added a large comment that gives an overview of all classes involved on the viewer side. Additional fixes for filepicker. Plugin refactor bug fix: mDeleteMe was uninitialized in AIPluginFilePicker. --- indra/llplugin/llpluginclassbasic.h | 3 ++ indra/llplugin/llpluginprocesschild.cpp | 9 ++++ indra/llplugin/llpluginprocesschild.h | 2 +- indra/llplugin/llpluginprocessparent.cpp | 5 ++ indra/llplugin/llpluginprocessparent.h | 4 ++ indra/newview/llviewerwindow.cpp | 4 +- indra/newview/statemachine/aifilepicker.cpp | 6 ++- indra/newview/statemachine/aifilepicker.h | 53 ++++++++++++++++++- .../plugins/base_basic/basic_plugin_base.cpp | 22 ++++++-- indra/plugins/base_basic/basic_plugin_base.h | 3 ++ .../plugins/base_media/media_plugin_base.cpp | 1 - indra/plugins/example_basic/CMakeLists.txt | 4 +- indra/plugins/example_media/CMakeLists.txt | 4 +- indra/plugins/filepicker/CMakeLists.txt | 4 +- .../filepicker/basic_plugin_filepicker.cpp | 6 +++ indra/plugins/filepicker/llfilepicker.cpp | 2 +- .../media_plugin_gstreamer010.cpp | 2 +- .../quicktime/media_plugin_quicktime.cpp | 4 ++ indra/plugins/webkit/CMakeLists.txt | 4 +- indra/plugins/webkit/linux_volume_catcher.cpp | 3 +- indra/plugins/webkit/media_plugin_webkit.cpp | 39 ++------------ 21 files changed, 129 insertions(+), 55 deletions(-) diff --git a/indra/llplugin/llpluginclassbasic.h b/indra/llplugin/llpluginclassbasic.h index a9e4dba46..6c0602608 100644 --- a/indra/llplugin/llpluginclassbasic.h +++ b/indra/llplugin/llpluginclassbasic.h @@ -113,6 +113,9 @@ protected: // Inherited from LLPluginProcessParentOwner. /*virtual*/ void receivePluginMessage(LLPluginMessage const&); + // Inherited from LLPluginProcessParentOwner. + /*virtual*/ void receivedShutdown() { mPlugin->exitState(); } + //-------------------------------------- // Debug use only // diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index 2c47087ab..f844c5a2b 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -553,6 +553,15 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message) } } } + else if (message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) + { + std::string message_name = parsed.getName(); + if(message_name == "shutdown") + { + // The plugin is finished. + setState(STATE_UNLOADING); + } + } } if(passMessage) diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h index 5d643d792..66082db7c 100644 --- a/indra/llplugin/llpluginprocesschild.h +++ b/indra/llplugin/llpluginprocesschild.h @@ -88,7 +88,7 @@ private: STATE_PLUGIN_LOADED, // plugin library has been loaded STATE_PLUGIN_INITIALIZING, // plugin is processing init message STATE_RUNNING, // steady state (processing messages) - STATE_UNLOADING, // plugin has sent shutdown_response and needs to be unloaded + STATE_UNLOADING, // plugin has sent shutdown and needs to be unloaded STATE_UNLOADED, // plugin has been unloaded STATE_ERROR, // generic bailout state STATE_DONE // state machine will sit in this state after either error or normal termination. diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 35931426d..df2f0b512 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -1001,6 +1001,11 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) LL_DEBUGS("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL; } + else if(message_name == "shutdown") + { + LL_INFOS("Plugin") << "received shutdown message" << LL_ENDL; + mOwner->receivedShutdown(); + } else if(message_name == "shm_add_response") { // Nothing to do here. diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index a82407d05..1ec5ef4c3 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -53,6 +53,7 @@ public: virtual ~LLPluginProcessParentOwner(); virtual void receivePluginMessage(const LLPluginMessage &message) = 0; virtual bool receivePluginMessageEarly(const LLPluginMessage &message) {return false;}; + virtual void receivedShutdown() = 0; // This will only be called when the plugin has died unexpectedly virtual void pluginLaunchFailed() {}; virtual void pluginDied() {}; @@ -88,6 +89,9 @@ public: // Go to the proper error state void errorState(void); + // Go to exit state. + void exitState(void) { setState(STATE_EXITING); } + void setSleepTime(F64 sleep_time, bool force_send = false); F64 getSleepTime(void) const { return mSleepTime; }; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 2139e75d8..2e684633c 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4031,7 +4031,7 @@ void LLViewerWindow::saveImageNumbered(LLPointer image) void LLViewerWindow::saveImageNumbered_filepicker_callback(LLPointer image, std::string const& extension, AIFilePicker* filepicker, bool success) { llassert((bool)*filepicker == success); - if (success) + if (success && !filepicker->isCanceled()) { // Copy the directory + file name std::string filepath = filepicker->getFilename(); @@ -4041,7 +4041,7 @@ void LLViewerWindow::saveImageNumbered_filepicker_callback(LLPointerdeleteMe(); } void LLViewerWindow::saveImageNumbered_continued(LLPointer image, std::string const& extension) diff --git a/indra/newview/statemachine/aifilepicker.cpp b/indra/newview/statemachine/aifilepicker.cpp index cd6856100..35d875dfd 100644 --- a/indra/newview/statemachine/aifilepicker.cpp +++ b/indra/newview/statemachine/aifilepicker.cpp @@ -314,7 +314,11 @@ void AIFilePicker::abort_impl(void) void AIFilePicker::finish_impl(void) { - mPluginManager = NULL; // This deletes the plugin, since mPluginManager is a LLPointer. + if (mPluginManager) + { + mPluginManager->destroyPlugin(); + mPluginManager = NULL; + } mFilter.clear(); // Check that open is called before calling run (again). } diff --git a/indra/newview/statemachine/aifilepicker.h b/indra/newview/statemachine/aifilepicker.h index 008afb1d7..fd5bd0cc2 100644 --- a/indra/newview/statemachine/aifilepicker.h +++ b/indra/newview/statemachine/aifilepicker.h @@ -67,6 +67,56 @@ enum ESaveFilter FFSAVE_LSL }; +/* + + AIFilePicker is an AIStateMachine, that has a LLViewerPluginManager (mPluginManager) + to manage a plugin that runs the actual filepicker in a separate process. + + The relationship with the plugin is as follows: + +new AIFilePicker + + AIFilePicker::mPluginManager = new LLViewerPluginManager + + LLPluginProcessParentOwner LLPluginMessagePipeOwner + | | LLPluginMessagePipeOwner::mOwner = LLPluginProcessParentOwner + | | LLPluginMessagePipeOwner::mMessagePipe = LLPluginMessagePipe + | | LLPluginMessagePipeOwner::receiveMessageRaw calls + v | LLPluginProcessParent::receiveMessageRaw + LLPluginClassBasic v + | LLPluginClassBasic::mPlugin = new LLPluginProcessParent ---> new LLPluginMessagePipe + | LLPluginProcessParent::mOwner = (LLPluginProcessParentOwner*)LLPluginClassBasic + | LLPluginProcessParent::sendMessage calls + | LLPluginMessagePipeOwner::writeMessageRaw calls + | mMessagePipe->LLPluginMessagePipe::addMessage + | LLPluginProcessParent::receiveMessageRaw calls + | LLPluginProcessParent::receiveMessage calls + | LLPluginProcessParentOwner::receivePluginMessage == AIPluginFilePicker::receivePluginMessage + | + | LLPluginClassBasic::sendMessage calls mPlugin->LLPluginProcessParent::sendMessage + | + v + LLViewerPluginManager::mPluginBase = new AIPluginFilePicker + AIPluginFilePicker::receivePluginMessage calls + AIFilePicker::receivePluginMessage + + AIPluginFilePicker::mStateMachine = AIFilePicker + + Where the entry point to send messages to the plugin is LLPluginClassBasic::sendMessage, + and the end point for messages received from the plugin is AIFilePicker::receivePluginMessage. + + Termination happens by receiving the "canceled" or "done" message, + which sets the state to AIFilePicker_canceled or AIFilePicker_done + respectively, causing a call to AIStateMachine::finish(), which calls + AIFilePicker::finish_impl which destroys the plugin (mPluginBase) + and the plugin manager (mPluginManager). + + AIStateMachine::finish() also calls the registered callback function, + which should call AIStateMachine::deleteMe(), causing the AIFilePicker + to be deleted. + +*/ + // A file picker state machine. // // Before calling run(), call open() to pass needed parameters. @@ -151,7 +201,8 @@ public: static std::string launcher_name(void) { return gDirUtilp->getLLPluginLauncher(); } static char const* plugin_basename(void) { return "basic_plugin_filepicker"; } - /*virtual*/ void receivePluginMessage(LLPluginMessage const& message) { mStateMachine->receivePluginMessage(message); } + /*virtual*/ void receivePluginMessage(LLPluginMessage const& message) { mStateMachine->receivePluginMessage(message); } + /*virtual*/ void receivedShutdown(void) { /* Nothing -- we terminate on deletion (from AIStateMachine::mainloop) */ } private: AIFilePicker* mStateMachine; diff --git a/indra/plugins/base_basic/basic_plugin_base.cpp b/indra/plugins/base_basic/basic_plugin_base.cpp index 90b5964ef..d7d486502 100755 --- a/indra/plugins/base_basic/basic_plugin_base.cpp +++ b/indra/plugins/base_basic/basic_plugin_base.cpp @@ -46,10 +46,9 @@ /// /// @param[in] send_message_function Function for sending messages from plugin to plugin loader shell /// @param[in] plugin_instance Message data for messages from plugin to plugin loader shell -BasicPluginBase::BasicPluginBase(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) +BasicPluginBase::BasicPluginBase(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) : + mPluginInstance(plugin_instance), mSendMessageFunction(send_message_function), mDeleteMe(false) { - mSendMessageFunction = send_message_function; - mPluginInstance = plugin_instance; } /** @@ -79,6 +78,12 @@ void BasicPluginBase::staticReceiveMessage(char const* message_string, BasicPlug // This is the loaded DSO. // // Call this function to send 'message' to the viewer. +// Note: mSendMessageFunction points to LLPluginInstance::staticReceiveMessage, so indirectly this +// just calls LLPluginInstance::receiveMessage (mPluginInstance->receiveMessage) where +// mPluginInstance is the LLPluginInstance created in LLPluginProcessChild::idle during +// state STATE_PLUGIN_LOADING. That function then immediately calls mOwner->receivePluginMessage +// which is implemented as LLPluginProcessChild::receivePluginMessage, the same +// LLPluginProcessChild object that created the LLPluginInstance. /** * Send message to plugin loader shell. * @@ -91,6 +96,17 @@ void BasicPluginBase::sendMessage(const LLPluginMessage &message) mSendMessageFunction(output.c_str(), &mPluginInstance); } +/** + * Send shutdown message to the plugin loader shell. + * + * This will cause the SLPlugin process that loaded this DSO to be terminated. + */ +void BasicPluginBase::sendShutdownMessage(void) +{ + LLPluginMessage shutdownmessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shutdown"); + sendMessage(shutdownmessage); +} + #if LL_WINDOWS # define LLSYMEXPORT __declspec(dllexport) #elif LL_LINUX diff --git a/indra/plugins/base_basic/basic_plugin_base.h b/indra/plugins/base_basic/basic_plugin_base.h index bbabb18b7..f615fce87 100755 --- a/indra/plugins/base_basic/basic_plugin_base.h +++ b/indra/plugins/base_basic/basic_plugin_base.h @@ -57,6 +57,9 @@ public: // This function is actually called and then calls the member function above. static void staticReceiveMessage(char const* message_string, BasicPluginBase** self_ptr); + // Shoot down the whole process. + void sendShutdownMessage(void); + protected: void sendMessage(LLPluginMessage const& message); diff --git a/indra/plugins/base_media/media_plugin_base.cpp b/indra/plugins/base_media/media_plugin_base.cpp index 102d18996..20769f2f7 100755 --- a/indra/plugins/base_media/media_plugin_base.cpp +++ b/indra/plugins/base_media/media_plugin_base.cpp @@ -49,7 +49,6 @@ MediaPluginBase::MediaPluginBase(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) : BasicPluginBase(send_message_function, plugin_instance) { - mDeleteMe = false; mPixels = 0; mWidth = 0; mHeight = 0; diff --git a/indra/plugins/example_basic/CMakeLists.txt b/indra/plugins/example_basic/CMakeLists.txt index fdc71a60c..98f5d1657 100644 --- a/indra/plugins/example_basic/CMakeLists.txt +++ b/indra/plugins/example_basic/CMakeLists.txt @@ -17,13 +17,13 @@ include_directories( ### basic_plugin_example -if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) +if(NOT WORD_SIZE EQUAL 32) if(WINDOWS) add_definitions(/FIXED:NO) else(WINDOWS) # not windows therefore gcc LINUX and DARWIN add_definitions(-fPIC) endif(WINDOWS) -endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) +endif (NOT WORD_SIZE EQUAL 32) set(basic_plugin_example_SOURCE_FILES basic_plugin_example.cpp diff --git a/indra/plugins/example_media/CMakeLists.txt b/indra/plugins/example_media/CMakeLists.txt index 99859ae8a..0a8214eef 100644 --- a/indra/plugins/example_media/CMakeLists.txt +++ b/indra/plugins/example_media/CMakeLists.txt @@ -28,13 +28,13 @@ include_directories( ### media_plugin_example -if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) +if(NOT WORD_SIZE EQUAL 32) if(WINDOWS) add_definitions(/FIXED:NO) else(WINDOWS) # not windows therefore gcc LINUX and DARWIN add_definitions(-fPIC) endif(WINDOWS) -endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) +endif (NOT WORD_SIZE EQUAL 32) set(media_plugin_example_SOURCE_FILES media_plugin_example.cpp diff --git a/indra/plugins/filepicker/CMakeLists.txt b/indra/plugins/filepicker/CMakeLists.txt index cea18360a..d3b233e01 100644 --- a/indra/plugins/filepicker/CMakeLists.txt +++ b/indra/plugins/filepicker/CMakeLists.txt @@ -19,13 +19,13 @@ include_directories( ### basic_plugin_filepicker -if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) +if(NOT WORD_SIZE EQUAL 32) if(WINDOWS) add_definitions(/FIXED:NO) else(WINDOWS) # not windows therefore gcc LINUX and DARWIN add_definitions(-fPIC) endif(WINDOWS) -endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + endif (NOT WORD_SIZE EQUAL 32) set(basic_plugin_filepicker_SOURCE_FILES basic_plugin_filepicker.cpp diff --git a/indra/plugins/filepicker/basic_plugin_filepicker.cpp b/indra/plugins/filepicker/basic_plugin_filepicker.cpp index bd415c64a..498dff3f1 100644 --- a/indra/plugins/filepicker/basic_plugin_filepicker.cpp +++ b/indra/plugins/filepicker/basic_plugin_filepicker.cpp @@ -150,6 +150,10 @@ void FilepickerPlugin::receiveMessage(char const* message_string) message.setValue("plugin_version", plugin_version); sendMessage(message); } + else if (message_name == "cleanup") + { + // We have no resources that need care. Just do nothing. + } else if (message_name == "idle") { // This whole message should not have existed imho -- Aleric @@ -213,6 +217,8 @@ void FilepickerPlugin::receiveMessage(char const* message_string) message.setValueLLSD("filenames", filenames); sendMessage(message); } + // We're done. Exit the whole application. + sendShutdownMessage(); } else { diff --git a/indra/plugins/filepicker/llfilepicker.cpp b/indra/plugins/filepicker/llfilepicker.cpp index f9a3ab8c1..1b54265ff 100644 --- a/indra/plugins/filepicker/llfilepicker.cpp +++ b/indra/plugins/filepicker/llfilepicker.cpp @@ -1048,7 +1048,7 @@ void LLFilePickerBase::chooser_responder(GtkWidget *widget, gint response, gpoin if (response == GTK_RESPONSE_ACCEPT) { GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); - g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); + g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, picker); g_slist_foreach(file_list, (GFunc)g_free, NULL); g_slist_free (file_list); } diff --git a/indra/plugins/gstreamer010/media_plugin_gstreamer010.cpp b/indra/plugins/gstreamer010/media_plugin_gstreamer010.cpp index 8d0dc31e2..38a6805fe 100755 --- a/indra/plugins/gstreamer010/media_plugin_gstreamer010.cpp +++ b/indra/plugins/gstreamer010/media_plugin_gstreamer010.cpp @@ -652,7 +652,7 @@ bool MediaPluginGStreamer010::getTimePos(double &sec_out) { bool got_position = false; - if (mPlaybin) + if (mDoneInit && mPlaybin) { gint64 pos; GstFormat timefmt = GST_FORMAT_TIME; diff --git a/indra/plugins/quicktime/media_plugin_quicktime.cpp b/indra/plugins/quicktime/media_plugin_quicktime.cpp index a03cadf19..1c15b7483 100755 --- a/indra/plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/plugins/quicktime/media_plugin_quicktime.cpp @@ -40,6 +40,10 @@ #if defined(LL_DARWIN) #include #elif defined(LL_WINDOWS) + #undef __STDC_CONSTANT_MACROS //Needed, as boost/unordered_map.hpp already defines INT32_C, etc. + #if defined(_MSC_VER) && _MSC_VER >= 1600 + #define _STDINT_H //Visual Studio 2010 includes its own stdint header already + #endif #include "MacTypes.h" #include "QTML.h" #include "Movies.h" diff --git a/indra/plugins/webkit/CMakeLists.txt b/indra/plugins/webkit/CMakeLists.txt index 1ffa2608a..49ea3e7f6 100644 --- a/indra/plugins/webkit/CMakeLists.txt +++ b/indra/plugins/webkit/CMakeLists.txt @@ -51,9 +51,9 @@ set(media_plugin_webkit_LINK_LIBRARIES # Select which VolumeCatcher implementation to use if (LINUX) - if (PULSEAUDIO) + if (PULSEAUDIO_FOUND) list(APPEND media_plugin_webkit_SOURCE_FILES linux_volume_catcher.cpp) - endif (PULSEAUDIO) + endif (PULSEAUDIO_FOUND) list(APPEND media_plugin_webkit_LINK_LIBRARIES ${UI_LIBRARIES} # for glib/GTK ) diff --git a/indra/plugins/webkit/linux_volume_catcher.cpp b/indra/plugins/webkit/linux_volume_catcher.cpp index cc3836ea5..ca1b1cfa2 100644 --- a/indra/plugins/webkit/linux_volume_catcher.cpp +++ b/indra/plugins/webkit/linux_volume_catcher.cpp @@ -42,9 +42,8 @@ 5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call */ -# include //imprudence - #include "linden_common.h" +# include #include "volume_catcher.h" diff --git a/indra/plugins/webkit/media_plugin_webkit.cpp b/indra/plugins/webkit/media_plugin_webkit.cpp index 97920cf9f..8067e25bc 100755 --- a/indra/plugins/webkit/media_plugin_webkit.cpp +++ b/indra/plugins/webkit/media_plugin_webkit.cpp @@ -79,20 +79,6 @@ extern "C" { } #endif -#ifdef LL_STANDALONE -#include -#elif defined(LL_LINUX) -// We don't provide Qt headers for non-standalone, therefore define this here. -// Our prebuilt is built with QT_NAMESPACE undefined. -#define QT_MANGLE_NAMESPACE(name) name -#define Q_INIT_RESOURCE(name) \ - do { extern int QT_MANGLE_NAMESPACE(qInitResources_ ## name) (); \ - QT_MANGLE_NAMESPACE(qInitResources_ ## name) (); } while (0) -#else -// Apparently this symbol doesn't exist in the windows and Mac tar balls provided by LL. -#define Q_INIT_RESOURCE(name) /*nothing*/ -#endif - //////////////////////////////////////////////////////////////////////////////// // class MediaPluginWebKit : @@ -138,6 +124,7 @@ private: F32 mBackgroundR; F32 mBackgroundG; F32 mBackgroundB; + std::string mTarget; VolumeCatcher mVolumeCatcher; @@ -326,11 +313,7 @@ private: LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); // create single browser window -#if LLQTWEBKIT_API_VERSION >= 2 - mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow(mWidth, mHeight /*, mTarget*/ ); // We don't have mTarget yet. -#else - mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight ); -#endif + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow(mWidth, mHeight, mTarget); // tell LLQtWebKit about the size of the browser window LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); @@ -537,16 +520,9 @@ private: void onClickLinkHref(const EventType& event) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); -#if LLQTWEBKIT_API_VERSION >= 2 message.setValue("uri", event.getEventUri()); message.setValue("target", event.getStringValue()); message.setValue("uuid", event.getStringValue2()); -#else - // This will work as long as we don't need "uuid", which will be needed for MoaP. - message.setValue("uri", event.getStringValue()); - message.setValue("target", event.getStringValue2()); - message.setValueU32("target_type", event.getLinkType()); -#endif sendMessage(message); } @@ -555,11 +531,7 @@ private: void onClickLinkNoFollow(const EventType& event) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); -#if LLQTWEBKIT_API_VERSION >= 2 message.setValue("uri", event.getEventUri()); -#else - message.setValue("uri", event.getStringValue()); -#endif sendMessage(message); } @@ -744,9 +716,6 @@ MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction send_ mJavascriptEnabled = true; // default to on mPluginsEnabled = true; // default to on mUserAgent = "LLPluginMedia Web Browser"; - - // Initialize WebCore resource. - Q_INIT_RESOURCE(WebCore); } MediaPluginWebKit::~MediaPluginWebKit() @@ -773,6 +742,8 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) { if(message_name == "init") { + mTarget = message_in.getValue("target"); + LLPluginMessage message("base", "init_response"); LLSD versions = LLSD::emptyMap(); versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; @@ -1082,7 +1053,7 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) else { // std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; - }; + } } else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) { From 80bbf5d0832ad9d59a9e437371e0bfe7de29d66b Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 8 May 2011 15:14:29 +0200 Subject: [PATCH 09/87] Fix underlinkage of libmedia_plugin_gstreamer.so Needed for the newer plugin code. This is basically just a copy of indra/cmake/GStreamer010Plugin.cmake from Imprudence. --- indra/cmake/GStreamer010Plugin.cmake | 56 ++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/indra/cmake/GStreamer010Plugin.cmake b/indra/cmake/GStreamer010Plugin.cmake index 2b45a1abc..90ed35c81 100644 --- a/indra/cmake/GStreamer010Plugin.cmake +++ b/indra/cmake/GStreamer010Plugin.cmake @@ -6,11 +6,13 @@ if (STANDALONE) pkg_check_modules(GSTREAMER010 REQUIRED gstreamer-0.10) pkg_check_modules(GSTREAMER010_PLUGINS_BASE REQUIRED gstreamer-plugins-base-0.10) -elseif (LINUX) + +else (STANDALONE) + + # Possibly libxml and glib should have their own .cmake file instead... use_prebuilt_binary(glib) # gstreamer needs glib - use_prebuilt_binary(gstreamer) - # possible libxml should have its own .cmake file instead use_prebuilt_binary(libxml) + use_prebuilt_binary(gstreamer) set(GSTREAMER010_FOUND ON FORCE BOOL) set(GSTREAMER010_PLUGINS_BASE_FOUND ON FORCE BOOL) set(GSTREAMER010_INCLUDE_DIRS @@ -18,23 +20,47 @@ elseif (LINUX) ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0 ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libxml2 ) + +endif (STANDALONE) + +if (WINDOWS) # We don't need to explicitly link against gstreamer itself, because # LLMediaImplGStreamer probes for the system's copy at runtime. - set(GSTREAMER010_LIBRARIES - gobject-2.0 - gmodule-2.0 - dl - gthread-2.0 - rt - glib-2.0 - ) -endif (STANDALONE) + set(GSTREAMER010_LIBRARIES + libgstvideo + libgstaudio + libgstbase-0.10 + libgstreamer-0.10 + gobject-2.0 + gmodule-2.0 + gthread-2.0 + glib-2.0 + ) +else (WINDOWS) + # We don't need to explicitly link against gstreamer itself, because + # LLMediaImplGStreamer probes for the system's copy at runtime. + set(GSTREAMER010_LIBRARIES + gstvideo-0.10 + gstaudio-0.10 + gstbase-0.10 + gstreamer-0.10 + gobject-2.0 + gmodule-2.0 + dl + gthread-2.0 + rt + glib-2.0 + ) + + +endif (WINDOWS) + if (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND) set(GSTREAMER010 ON CACHE BOOL "Build with GStreamer-0.10 streaming media support.") + add_definitions(-DLL_GSTREAMER010_ENABLED=1) endif (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND) -if (GSTREAMER010) - add_definitions(-DLL_GSTREAMER010_ENABLED=1) -endif (GSTREAMER010) + + From 75ff0fc04d91771f3af035a0484e1b8f4bd0791b Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 8 May 2011 15:31:51 +0200 Subject: [PATCH 10/87] Add more support for debugging plugins. Added support for plugin debug messages and better error reporting when something goes wrong during start up of SLPlugin. Also added more debug output regarding general plugin messages as well as debug output related to AIFilePicker. --- indra/llcommon/llerror.cpp | 54 ++++-- indra/llcommon/llprocesslauncher.cpp | 179 ++++++++++++++++-- indra/llplugin/llpluginclassmedia.cpp | 2 +- indra/llplugin/llpluginmessage.h | 7 + indra/llplugin/llpluginprocesschild.cpp | 1 + indra/llplugin/llpluginprocessparent.cpp | 40 +++- indra/newview/app_settings/logcontrol.xml | 9 + indra/newview/llviewermedia.cpp | 2 + indra/newview/statemachine/aifilepicker.cpp | 2 + indra/newview/statemachine/aifilepicker.h | 4 + .../plugins/base_basic/basic_plugin_base.cpp | 21 ++ indra/plugins/base_basic/basic_plugin_base.h | 43 ++++- .../filepicker/basic_plugin_filepicker.cpp | 2 +- indra/plugins/filepicker/llfilepicker.cpp | 2 +- 14 files changed, 330 insertions(+), 38 deletions(-) diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index a9c4380a1..73ec354bc 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -46,6 +46,7 @@ # include #endif // !LL_WINDOWS #include +#include #include "llapp.h" #include "llapr.h" @@ -1076,28 +1077,49 @@ namespace LLError switch (site.mLevel) { - case LEVEL_DEBUG: prefix << "DEBUG: "; break; - case LEVEL_INFO: prefix << "INFO: "; break; - case LEVEL_WARN: prefix << "WARNING: "; break; - case LEVEL_ERROR: prefix << "ERROR: "; break; - default: prefix << "XXX: "; break; + case LEVEL_DEBUG: prefix << "DEBUG"; break; + case LEVEL_INFO: prefix << "INFO"; break; + case LEVEL_WARN: prefix << "WARNING"; break; + case LEVEL_ERROR: prefix << "ERROR"; break; + default: prefix << "XXX"; break; }; - - if (settings_w->printLocation) + + bool need_function = true; + if (site.mBroadTag && *site.mBroadTag != '\0') { - prefix << abbreviateFile(site.mFile) - << "(" << site.mLine << ") : "; + prefix << "(\"" << site.mBroadTag << "\")"; +#if LL_DEBUG + // Suppress printing mFunction if mBroadTag is set, starts with + // "Plugin " and ends with "child": a debug message from a plugin. + size_t taglen = strlen(site.mBroadTag); + if (taglen >= 12 && strncmp(site.mBroadTag, "Plugin ", 7) == 0 && + strcmp(site.mBroadTag + taglen - 5, "child") == 0) + { + need_function = false; + } +#endif } + + prefix << ": "; - #if LL_WINDOWS - // DevStudio: __FUNCTION__ already includes the full class name - #else - if (site.mClassInfo != typeid(NoClassInfo)) + if (need_function) { - prefix << className(site.mClassInfo) << "::"; + if (settings_w->printLocation) + { + prefix << abbreviateFile(site.mFile) + << "(" << site.mLine << ") : "; + } + +#if LL_WINDOWS + // DevStudio: __FUNCTION__ already includes the full class name +#else + if (need_function && site.mClassInfo != typeid(NoClassInfo)) + { + prefix << className(site.mClassInfo) << "::"; + } +#endif + prefix << site.mFunction << ": "; } - #endif - prefix << site.mFunction << ": "; if (site.mPrintOnce) { diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp index e27aaa3c5..ee120fc94 100644 --- a/indra/llcommon/llprocesslauncher.cpp +++ b/indra/llcommon/llprocesslauncher.cpp @@ -32,7 +32,11 @@ #include "linden_common.h" +#include +#include +#include #include "llprocesslauncher.h" +#include "aiaprpool.h" #include #if LL_DARWIN || LL_LINUX @@ -142,6 +146,7 @@ bool LLProcessLauncher::isRunning(void) return (mProcessHandle != 0); } + bool LLProcessLauncher::kill(void) { bool result = true; @@ -201,6 +206,79 @@ static bool reap_pid(pid_t pid) return result; } +#if LL_DEBUG +// Define this to create a temporary pipe(2) between parent and child process, so +// that the child process can report error messages that it encounters when +// trying to execve(2). Most notably failing to start due to missing libraries +// or undefined symbols. +#define DEBUG_PIPE_CHILD_ERROR_REPORTING 1 +#endif + +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + +// Called by child process. +static void write_pipe(apr_file_t* out, char const* message) +{ + apr_size_t const bytes_to_write = strlen(message) + 1; // +1 for the length byte. + assert(bytes_to_write < 256); + char buf[256]; + strncpy(buf + 1, message, sizeof(buf) - 1); + *reinterpret_cast(buf) = bytes_to_write - 1; + + apr_size_t bytes_written; + apr_status_t status = apr_file_write_full(out, buf, bytes_to_write, &bytes_written); + if (status != APR_SUCCESS) + { + std::cerr << "apr_file_write_full: " << apr_strerror(status, buf, sizeof(buf)) << std::endl; + } + else if (bytes_written != bytes_to_write) + { + std::cerr << "apr_file_write_full: bytes_written (" << bytes_written << ") != bytes_to_write (" << bytes_to_write << ")!" << std::endl; + } + status = apr_file_flush(out); + if (status != APR_SUCCESS) + { + std::cerr << "apr_file_flush: " << apr_strerror(status, buf, sizeof(buf)) << std::endl; + } + +#ifdef _DEBUG + std::cerr << "apr_file_write_full: Wrote " << bytes_written << " bytes to the pipe." << std::endl; +#endif +} + +// Called by parent process. +static std::string read_pipe(apr_file_t* in, bool timeout_ok = false) +{ + char buf[256]; + unsigned char bytes_to_read; + apr_size_t bytes_read; + apr_status_t status = apr_file_read_full(in, &bytes_to_read, 1, &bytes_read); + if (status != APR_SUCCESS) + { + if (APR_STATUS_IS_TIMEUP(status) && timeout_ok) + { + return "TIMEOUT"; + } + llwarns << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << llendl; + assert(APR_STATUS_IS_EOF(status)); + return "END OF FILE"; + } + assert(bytes_read == 1); + status = apr_file_read_full(in, buf, bytes_to_read, &bytes_read); + if (status != APR_SUCCESS) + { + llwarns << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << llendl; + assert(status == APR_SUCCESS); // Fail + } + assert(bytes_read == bytes_to_read); + + std::string received(buf, bytes_read); + llinfos << "Received: \"" << received << "\" (bytes read: " << bytes_read << ")" << llendl; + return received; +} + +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + int LLProcessLauncher::launch(void) { // If there was already a process associated with this object, kill it. @@ -237,23 +315,96 @@ int LLProcessLauncher::launch(void) } } - // flush all buffers before the child inherits them - ::fflush(NULL); - - pid_t id = vfork(); - if(id == 0) + pid_t id; { - // child process - - ::execv(mExecutable.c_str(), (char * const *)fake_argv); - - // If we reach this point, the exec failed. - // Use _exit() instead of exit() per the vfork man page. - _exit(0); +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + // Set up a pipe to the child process for error reporting. + apr_file_t* in; + apr_file_t* out; + AIAPRPool pool; + pool.create(); + apr_status_t status = apr_file_pipe_create_ex(&in, &out, APR_FULL_BLOCK, pool()); + assert(status == APR_SUCCESS); + bool success = (status == APR_SUCCESS); + if (success) + { + apr_interval_time_t const timeout = 10000000; // 10 seconds. + status = apr_file_pipe_timeout_set(in, timeout); + assert(status == APR_SUCCESS); + success = (status == APR_SUCCESS); + } +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + + // flush all buffers before the child inherits them + ::fflush(NULL); + + id = vfork(); + if (id == 0) + { + // child process + +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + // Tell parent process we're about to call execv. + write_pipe(out, "CALLING EXECV"); +#ifdef _DEBUG + char const* display = getenv("DISPLAY"); + std::cerr << "Calling ::execv(\"" << mExecutable << '"'; + for(int j = 0; j < i; ++j) + std::cerr << ", \"" << fake_argv[j] << '"'; + std::cerr << ") with DISPLAY=\"" << (display ? display : "NULL") << '"' << std::endl; +#endif +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + + ::execv(mExecutable.c_str(), (char * const *)fake_argv); + +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + status = APR_FROM_OS_ERROR(apr_get_os_error()); + char message[256]; + char errbuf[128]; + apr_strerror(status, errbuf, sizeof(errbuf)); + snprintf(message, sizeof(message), "Child process: execv: %s: %s", mExecutable.c_str(), errbuf); + write_pipe(out, message); +#ifdef _DEBUG + std::cerr << "::execv() failed." << std::endl; +#endif +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + + // If we reach this point, the exec failed. + // Use _exit() instead of exit() per the vfork man page. + _exit(0); + } + + // parent process + +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + // Close unused pipe end. + apr_file_close(out); + + if (success) + { + // Attempt to do error reporting. + std::string message = read_pipe(in); + success = (message == "CALLING EXECV"); + assert(success); + if (success) + { + status = apr_file_pipe_timeout_set(in, 2000000); // Only wait 2 seconds. + message = read_pipe(in, true); + if (message != "TIMEOUT" && message != "END OF FILE") + { + // Most likely execv failed. + llwarns << message << llendl; + assert(false); // Fail in debug mode. + } + } + } + + // Clean up. + apr_file_close(in); +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + } - // parent process - if(current_wd >= 0) { // restore the previous working directory diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 2bbad6011..c8b903e58 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -674,7 +674,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mDirtyRect.unionWith(newDirtyRect); } - LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" + LL_DEBUGS("PluginUpdated") << "adjusted incoming rect is: (" << newDirtyRect.mLeft << ", " << newDirtyRect.mTop << ", " << newDirtyRect.mRight << ", " diff --git a/indra/llplugin/llpluginmessage.h b/indra/llplugin/llpluginmessage.h index 3c7b91750..7bc4ea12d 100644 --- a/indra/llplugin/llpluginmessage.h +++ b/indra/llplugin/llpluginmessage.h @@ -100,6 +100,13 @@ public: // Returns -1 on failure, otherwise returns the number of key/value pairs in the message. int parse(const std::string &message); + enum LLPLUGIN_LOG_LEVEL { + LOG_LEVEL_DEBUG, + LOG_LEVEL_INFO, + LOG_LEVEL_WARN, + LOG_LEVEL_ERR, + }; + // For debugging purposes. friend std::ostream& operator<<(std::ostream& os, LLPluginMessage const& message) { return os << message.mMessage; } diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index f844c5a2b..3ba765bf6 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -227,6 +227,7 @@ void LLPluginProcessChild::idle(void) case STATE_DONE: // just sit here. + LL_WARNS("Plugin") << "Calling LLPluginProcessChild::idle while in STATE_DONE!" << LL_ENDL; break; } diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index df2f0b512..fc94ee849 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -598,7 +598,16 @@ void LLPluginProcessParent::sendMessage(const LLPluginMessage &message) } std::string buffer = message.generate(); - LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL; +#if LL_DEBUG + if (message.getName() == "mouse_event") + { + LL_DEBUGS("PluginMouseEvent") << "Sending: " << buffer << LL_ENDL; + } + else + { + LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL; + } +#endif writeMessageRaw(buffer); // Try to send message immediately. @@ -876,7 +885,7 @@ void LLPluginProcessParent::servicePoll() // It parses the message and passes it on to LLPluginProcessParent::receiveMessage. void LLPluginProcessParent::receiveMessageRaw(const std::string &message) { - LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL; + LL_DEBUGS("PluginRaw") << "Received: " << message << LL_ENDL; LLPluginMessage parsed; if(parsed.parse(message) != -1) @@ -998,8 +1007,7 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) mCPUUsage = message.getValueReal("cpu_usage"); - LL_DEBUGS("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL; - + LL_DEBUGS("PluginHeartbeat") << "cpu usage reported as " << mCPUUsage << LL_ENDL; } else if(message_name == "shutdown") { @@ -1024,6 +1032,30 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) mSharedMemoryRegions.erase(iter); } } + else if(message_name == "log_message") + { + std::string msg=message.getValue("message"); + S32 level=message.getValueS32("log_level"); + + switch(level) + { + case LLPluginMessage::LOG_LEVEL_DEBUG: + LL_DEBUGS("Plugin child")< ShaderLoading Openjpeg + + Plugin + Plugin child + + PluginRaw child + + + + diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index ca21f6d0c..ced145d34 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -399,10 +399,12 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ if(LLFile::stat(launcher_name, &s)) { LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; + llassert(false); // Fail in debugging mode. } else if(LLFile::stat(plugin_name, &s)) { LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; + llassert(false); // Fail in debugging mode. } else { diff --git a/indra/newview/statemachine/aifilepicker.cpp b/indra/newview/statemachine/aifilepicker.cpp index 35d875dfd..33ef0c16c 100644 --- a/indra/newview/statemachine/aifilepicker.cpp +++ b/indra/newview/statemachine/aifilepicker.cpp @@ -338,10 +338,12 @@ void AIFilePicker::receivePluginMessage(const LLPluginMessage &message) std::string message_name = message.getName(); if (message_name == "canceled") { + LL_DEBUGS("Plugin") << "received message \"canceled\"" << LL_ENDL; set_state(AIFilePicker_canceled); } else if (message_name == "done") { + LL_DEBUGS("Plugin") << "received message \"done\"" << LL_ENDL; LLSD filenames = message.getValueLLSD("filenames"); mFilenames.clear(); for(LLSD::array_iterator filename = filenames.beginArray(); filename != filenames.endArray(); ++filename) diff --git a/indra/newview/statemachine/aifilepicker.h b/indra/newview/statemachine/aifilepicker.h index fd5bd0cc2..b1caf4701 100644 --- a/indra/newview/statemachine/aifilepicker.h +++ b/indra/newview/statemachine/aifilepicker.h @@ -175,6 +175,9 @@ private: std::string get_folder(std::string const& default_path, std::string const& context); protected: + // Call deleteMe(), not delete. + /*virtual*/ ~AIFilePicker() { LL_DEBUGS("Plugin") << "Calling AIFilePicker::~AIFilePicker()" << LL_ENDL; } + // Handle initializing the object. /*virtual*/ void initialize_impl(void); @@ -197,6 +200,7 @@ class AIPluginFilePicker : public LLPluginClassBasic { LOG_CLASS(AIPluginFilePicker); public: AIPluginFilePicker(AIFilePicker* state_machine) : mStateMachine(state_machine) { } + /*virtual*/ ~AIPluginFilePicker() { LL_DEBUGS("Plugin") << "Calling AIPluginFilePicker::~AIPluginFilePicker()" << LL_ENDL; } static std::string launcher_name(void) { return gDirUtilp->getLLPluginLauncher(); } static char const* plugin_basename(void) { return "basic_plugin_filepicker"; } diff --git a/indra/plugins/base_basic/basic_plugin_base.cpp b/indra/plugins/base_basic/basic_plugin_base.cpp index d7d486502..f791b5887 100755 --- a/indra/plugins/base_basic/basic_plugin_base.cpp +++ b/indra/plugins/base_basic/basic_plugin_base.cpp @@ -41,6 +41,9 @@ // TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint +// Used for logging. +BasicPluginBase* BasicPluginBase::sPluginBase; + //////////////////////////////////////////////////////////////////////////////// /// Basic plugin constructor. /// @@ -49,6 +52,8 @@ BasicPluginBase::BasicPluginBase(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance) : mPluginInstance(plugin_instance), mSendMessageFunction(send_message_function), mDeleteMe(false) { + llassert(!sPluginBase); + sPluginBase = this; } /** @@ -93,9 +98,25 @@ void BasicPluginBase::staticReceiveMessage(char const* message_string, BasicPlug void BasicPluginBase::sendMessage(const LLPluginMessage &message) { std::string output = message.generate(); + PLS_DEBUGS << "BasicPluginBase::sendMessage: Sending: " << output << PLS_ENDL; mSendMessageFunction(output.c_str(), &mPluginInstance); } +/** + * Send debug log message to plugin loader shell. + * + * @param[in] message Log message being sent to plugin loader shell + * @param[in] level Log message level, enum of LLPluginMessage::LLPLUGIN_LOG_LEVEL + * + */ +void BasicPluginBase::sendLogMessage(std::string const& message, LLPluginMessage::LLPLUGIN_LOG_LEVEL level) +{ + LLPluginMessage logmessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "log_message"); + logmessage.setValue("message", message); + logmessage.setValueS32("log_level",level); + mSendMessageFunction(logmessage.generate().c_str(), &mPluginInstance); +} + /** * Send shutdown message to the plugin loader shell. * diff --git a/indra/plugins/base_basic/basic_plugin_base.h b/indra/plugins/base_basic/basic_plugin_base.h index f615fce87..492b408e7 100755 --- a/indra/plugins/base_basic/basic_plugin_base.h +++ b/indra/plugins/base_basic/basic_plugin_base.h @@ -38,6 +38,8 @@ #include +#include + #include "linden_common.h" #include "llplugininstance.h" @@ -49,7 +51,7 @@ class BasicPluginBase public: BasicPluginBase(LLPluginInstance::sendMessageFunction send_message_function, LLPluginInstance* plugin_instance); //! Basic plugin destructor. - virtual ~BasicPluginBase() {} + virtual ~BasicPluginBase() { sPluginBase = NULL; } //! Handle received message from plugin loader shell. virtual void receiveMessage(char const* message_string) = 0; @@ -57,6 +59,12 @@ public: // This function is actually called and then calls the member function above. static void staticReceiveMessage(char const* message_string, BasicPluginBase** self_ptr); + // Pointer to self used for logging (this object should be a singleton). + static BasicPluginBase* sPluginBase; + + // Used for log messages. Use macros below. + void sendLogMessage(std::string const& message, LLPluginMessage::LLPLUGIN_LOG_LEVEL level); + // Shoot down the whole process. void sendShutdownMessage(void); @@ -87,5 +95,38 @@ int create_plugin( LLPluginInstance* plugin_instance, BasicPluginBase** plugin_object); +#if LL_DEBUG +#define LL_DEBUG_PLUGIN_MESSAGES 1 +#else +#define LL_DEBUG_PLUGIN_MESSAGES 0 +#endif + +/** Convenience macros for calling BasicPluginBase::sendLogMessage. + * To log a message, use one of: + * @code + * PLS_DEBUGS << "Hello debug!" << PLS_ENDL; + * PLS_INFOS << "Hello info!" << PLS_ENDL; + * PLS_WARNS << "Hello warning!" << PLS_ENDL; + * PLS_ERRS << "Hello error!" << PLS_ENDL; + * @endcode + */ +#define PLS_LOG_MESSAGE(level, generate_code) \ + do { \ + if (generate_code && BasicPluginBase::sPluginBase) \ + { \ + LLPluginMessage::LLPLUGIN_LOG_LEVEL _pls_log_msg_level = level;\ + std::ostringstream _pls_log_msg_stream; \ + _pls_log_msg_stream +#define PLS_ENDL \ + LLError::End(); \ + BasicPluginBase::sPluginBase->sendLogMessage(_pls_log_msg_stream.str(), _pls_log_msg_level); \ + } \ + } while(0) +// Only send plugin log messages of level info and lower when compiled with debugging. +#define PLS_DEBUGS PLS_LOG_MESSAGE(LLPluginMessage::LOG_LEVEL_DEBUG, LL_DEBUG_PLUGIN_MESSAGES) +#define PLS_INFOS PLS_LOG_MESSAGE(LLPluginMessage::LOG_LEVEL_INFO, LL_DEBUG_PLUGIN_MESSAGES) +#define PLS_WARNS PLS_LOG_MESSAGE(LLPluginMessage::LOG_LEVEL_WARN, 1) +#define PLS_ERRS PLS_LOG_MESSAGE(LLPluginMessage::LOG_LEVEL_ERR, 1) + #endif // BASIC_PLUGIN_BASE diff --git a/indra/plugins/filepicker/basic_plugin_filepicker.cpp b/indra/plugins/filepicker/basic_plugin_filepicker.cpp index 498dff3f1..b30131479 100644 --- a/indra/plugins/filepicker/basic_plugin_filepicker.cpp +++ b/indra/plugins/filepicker/basic_plugin_filepicker.cpp @@ -140,7 +140,7 @@ void FilepickerPlugin::receiveMessage(char const* message_string) { if (message_name == "init") { - LLPluginMessage message("base", "init_response"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASE, "init_response"); LLSD versions = LLSD::emptyMap(); versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; versions[LLPLUGIN_MESSAGE_CLASS_BASIC] = LLPLUGIN_MESSAGE_CLASS_BASIC_VERSION; diff --git a/indra/plugins/filepicker/llfilepicker.cpp b/indra/plugins/filepicker/llfilepicker.cpp index 1b54265ff..b9c616195 100644 --- a/indra/plugins/filepicker/llfilepicker.cpp +++ b/indra/plugins/filepicker/llfilepicker.cpp @@ -56,7 +56,7 @@ namespace translation void add(std::string const& key, std::string const& translation) { - PLS_INFOS << "Adding translation \"" << key << "\" --> \"" << translation << "\"" << PLS_ENDL; + PLS_DEBUGS << "Adding translation \"" << key << "\" --> \"" << translation << "\"" << PLS_ENDL; translation_map[key] = translation; } } From 81550aa6de858c94b2ff3e914d83e187831e24fb Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 9 May 2011 20:22:04 +0200 Subject: [PATCH 11/87] Workaround for gcc 4.2.x. g++ 4.2 (and possibly earlier) apparently call a copy constructor when passing a temporary to a function that takes a const reference. Added code to allow copy-constructing the AI*Access classes for this compiler. g++-4.2.x also bails out when it encounters files that do not end on a newline. So, also added those where they were missing. --- indra/llaudio/llaudiodecodemgr.cpp | 2 +- indra/llcommon/aithreadsafe.h | 41 +++++++++++++++++++- indra/newview/ascentfloatercontactgroups.cpp | 2 +- indra/newview/ascentfloatercontactgroups.h | 2 +- indra/newview/ascentprefssys.h | 2 +- indra/newview/dsaparam.cpp | 2 +- indra/newview/emerald.cpp | 2 +- indra/newview/emeraldboobutils.cpp | 2 +- indra/newview/llpanelobject.cpp | 2 +- indra/newview/llphysicsmotion.cpp | 2 +- indra/newview/llpreviewgesture.cpp | 2 +- indra/newview/llpreviewscript.cpp | 2 +- indra/newview/llsavedsettingsglue.cpp | 2 +- indra/newview/qtoolalign.cpp | 2 +- indra/newview/qtoolalign.h | 2 +- indra/newview/scriptcounter.h | 2 +- indra/newview/wlfPanel_AdvSettings.cpp | 2 +- 17 files changed, 55 insertions(+), 18 deletions(-) diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index 908eca5a6..41930f539 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -723,4 +723,4 @@ BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) } return FALSE; -} \ No newline at end of file +} diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h index 70cd2a3db..0163c01b2 100644 --- a/indra/llcommon/aithreadsafe.h +++ b/indra/llcommon/aithreadsafe.h @@ -36,6 +36,11 @@ #include "llthread.h" #include "llerror.h" +// g++ 4.2.x (and before?) have the bug that when you try to pass a temporary +// to a function taking a const reference, it still calls the copy constructor. +// Define this to hack around that. +#define AI_NEED_ACCESS_CC (defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || (__GNUC__ < 4))) + template struct AIReadAccessConst; template struct AIReadAccess; template struct AIWriteAccess; @@ -66,6 +71,10 @@ protected: // Accessors. T const* ptr() const { return reinterpret_cast(mMemory); } T* ptr() { return reinterpret_cast(mMemory); } + +#if AI_NEED_ACCESS_CC + int mAccessCopyCount; +#endif }; /** @@ -239,12 +248,18 @@ struct AIReadAccessConst mState(readlocked) { mWrapper.mRWLock.rdlock(); +#if AI_NEED_ACCESS_CC + mWrapper.mAccessCopyCount = 1; +#endif } //! Destruct the AI*Access object. // These should never be dynamically allocated, so there is no need to make this virtual. ~AIReadAccessConst() { +#if AI_NEED_ACCESS_CC + if (--(this->mWrapper.mAccessCopyCount) > 0) return; +#endif if (mState == readlocked) mWrapper.mRWLock.rdunlock(); else if (mState == writelocked) @@ -267,9 +282,14 @@ protected: AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to. state_type const mState; //!< The lock state that mWrapper is in. +#if !AI_NEED_ACCESS_CC private: // Disallow copy constructing directly. AIReadAccessConst(AIReadAccessConst const&); +#else +public: + AIReadAccessConst(AIReadAccessConst const& orig) : mWrapper(orig.mWrapper), mState(orig.mState) { mWrapper.mAccessCopyCount++; } +#endif }; /** @@ -461,7 +481,13 @@ template struct AIAccess { //! Construct a AIAccess from a non-constant AIThreadSafeSimple. - AIAccess(AIThreadSafeSimple& wrapper) : mWrapper(wrapper) { this->mWrapper.mMutex.lock(); } + AIAccess(AIThreadSafeSimple& wrapper) : mWrapper(wrapper) + { + this->mWrapper.mMutex.lock(); +#if AI_NEED_ACCESS_CC + this->mWrapper.mAccessCopyCount = 1; +#endif + } //! Access the underlaying object for (read and) write access. T* operator->() const { return this->mWrapper.ptr(); } @@ -469,14 +495,25 @@ struct AIAccess //! Access the underlaying object for (read and) write access. T& operator*() const { return *this->mWrapper.ptr(); } - ~AIAccess() { this->mWrapper.mMutex.unlock(); } + ~AIAccess() + { +#if AI_NEED_ACCESS_CC + if (--(this->mWrapper.mAccessCopyCount) > 0) return; +#endif + this->mWrapper.mMutex.unlock(); + } protected: AIThreadSafeSimple& mWrapper; //!< Reference to the object that we provide access to. +#if !AI_NEED_ACCESS_CC private: // Disallow copy constructing directly. AIAccess(AIAccess const&); +#else +public: + AIAccess(AIAccess const& orig) : mWrapper(orig.mWrapper) { this->mWrapper.mAccessCopyCount++; } +#endif }; #endif diff --git a/indra/newview/ascentfloatercontactgroups.cpp b/indra/newview/ascentfloatercontactgroups.cpp index 80f8a2204..d4097493d 100644 --- a/indra/newview/ascentfloatercontactgroups.cpp +++ b/indra/newview/ascentfloatercontactgroups.cpp @@ -238,4 +238,4 @@ void ASFloaterContactGroups::populateGroupList() } } } -} \ No newline at end of file +} diff --git a/indra/newview/ascentfloatercontactgroups.h b/indra/newview/ascentfloatercontactgroups.h index ed9fa44f1..809dce781 100644 --- a/indra/newview/ascentfloatercontactgroups.h +++ b/indra/newview/ascentfloatercontactgroups.h @@ -92,4 +92,4 @@ email for me right now, also in all cap. my father not very understand of free softwares and he make a fun of RMS. -*/ \ No newline at end of file +*/ diff --git a/indra/newview/ascentprefssys.h b/indra/newview/ascentprefssys.h index f9e507d9f..d62c9bdf1 100644 --- a/indra/newview/ascentprefssys.h +++ b/indra/newview/ascentprefssys.h @@ -100,4 +100,4 @@ protected: BOOL mSpellDisplay; }; -#endif \ No newline at end of file +#endif diff --git a/indra/newview/dsaparam.cpp b/indra/newview/dsaparam.cpp index e4c89d40e..c7720e61e 100644 --- a/indra/newview/dsaparam.cpp +++ b/indra/newview/dsaparam.cpp @@ -66,4 +66,4 @@ DSA *get_dsa2048() if ((dsa->p == NULL) || (dsa->q == NULL) || (dsa->g == NULL)) { DSA_free(dsa); return(NULL); } return(dsa); - } \ No newline at end of file + } diff --git a/indra/newview/emerald.cpp b/indra/newview/emerald.cpp index 1d89381cf..c2a31a65f 100644 --- a/indra/newview/emerald.cpp +++ b/indra/newview/emerald.cpp @@ -590,4 +590,4 @@ EDSA::~EDSA() { delete mDSAImpl; mDSAImpl = NULL; -} \ No newline at end of file +} diff --git a/indra/newview/emeraldboobutils.cpp b/indra/newview/emeraldboobutils.cpp index 12b784a7e..6d1238976 100644 --- a/indra/newview/emeraldboobutils.cpp +++ b/indra/newview/emeraldboobutils.cpp @@ -186,4 +186,4 @@ EmeraldBoobState EmeraldBoobUtils::idleUpdate(const EmeraldGlobalBoobConfig &con newState.boobGrav = llclamp(newState.boobGrav, -1.5f, 2.0f); return newState; -} \ No newline at end of file +} diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index f6ce2fe3b..9f8561835 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -2771,4 +2771,4 @@ void LLPanelObject::onPasteRotClip(void* user_data) calcp->setVar(LLCalc::Y_ROT, mClipboardRot.mV[VY]); calcp->setVar(LLCalc::Z_ROT, mClipboardRot.mV[VZ]); self->sendRotation(FALSE); -} \ No newline at end of file +} diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index e9a127cf3..793f3fb1b 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -770,4 +770,4 @@ void LLPhysicsMotion::reset() mCharacter->setVisualParamWeight((*iter).mParam,(*iter).mParam->getDefaultWeight()); } } -} \ No newline at end of file +} diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index d26c7a64b..1c7a57abc 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -1789,4 +1789,4 @@ void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture, void* data) self->mPreviewGesture = NULL; self->refresh(); -} \ No newline at end of file +} diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index ad54f5009..7b6bab72e 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -2669,4 +2669,4 @@ void LLLiveLSLEditor::saveAs() fclose(fp); fp = NULL; } -// \ No newline at end of file +// diff --git a/indra/newview/llsavedsettingsglue.cpp b/indra/newview/llsavedsettingsglue.cpp index 0e58b5f89..72879837f 100644 --- a/indra/newview/llsavedsettingsglue.cpp +++ b/indra/newview/llsavedsettingsglue.cpp @@ -182,4 +182,4 @@ void LLSavedSettingsGlue::setColor4(const std::string &name, LLColor4 value) gSavedSettings.setColor4(name, value); else gSavedPerAccountSettings.setColor4(name, value); -}*/ \ No newline at end of file +}*/ diff --git a/indra/newview/qtoolalign.cpp b/indra/newview/qtoolalign.cpp index 166c93f6a..b40faef40 100644 --- a/indra/newview/qtoolalign.cpp +++ b/indra/newview/qtoolalign.cpp @@ -626,4 +626,4 @@ void QToolAlign::align() LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); -} \ No newline at end of file +} diff --git a/indra/newview/qtoolalign.h b/indra/newview/qtoolalign.h index 168453da4..1bef073ba 100644 --- a/indra/newview/qtoolalign.h +++ b/indra/newview/qtoolalign.h @@ -46,4 +46,4 @@ private: BOOL mForce; }; -#endif // Q_QTOOLALIGN_H \ No newline at end of file +#endif // Q_QTOOLALIGN_H diff --git a/indra/newview/scriptcounter.h b/indra/newview/scriptcounter.h index 3e1f305fd..b1c737189 100644 --- a/indra/newview/scriptcounter.h +++ b/indra/newview/scriptcounter.h @@ -75,4 +75,4 @@ private: static bool doDelete; static std::stringstream sstr; static int countingDone; -}; \ No newline at end of file +}; diff --git a/indra/newview/wlfPanel_AdvSettings.cpp b/indra/newview/wlfPanel_AdvSettings.cpp index 757853c61..aef9e3276 100644 --- a/indra/newview/wlfPanel_AdvSettings.cpp +++ b/indra/newview/wlfPanel_AdvSettings.cpp @@ -178,4 +178,4 @@ void wlfPanel_AdvSettings::onChangePresetName(LLUICtrl* ctrl, void * userData) current_preset = combo_box->getSelectedValue().asString(); LLWaterParamManager::instance()->loadPreset(current_preset); } -} \ No newline at end of file +} From e0b0fa4f58f83ea4c2c666f55637dfc994c66d15 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 10 May 2011 04:27:57 +0200 Subject: [PATCH 12/87] Use AIFilePicker everywhere. Also upgrade the file picker filters with the new extensions found in the orginal file picker code of Singularity. Also improve AIFilePicker a bit: added hasFilename() and now deleting the statemachine automatically by default: it's no longer needed to call deleteMe from the callback. --- indra/llvfs/lldir.cpp | 6 +- indra/newview/floaterlocalassetbrowse.cpp | 22 +- indra/newview/floaterlocalassetbrowse.h | 2 + indra/newview/llassetuploadresponders.cpp | 6 +- indra/newview/llfilepicker.cpp | 19 + indra/newview/llfilepicker.h | 4 - indra/newview/llfloaterblacklist.cpp | 27 +- indra/newview/llfloaterblacklist.h | 5 + indra/newview/llfloatercustomize.cpp | 34 +- indra/newview/llfloatercustomize.h | 3 + indra/newview/llfloaterfriends.cpp | 32 +- indra/newview/llfloaterfriends.h | 3 + indra/newview/llfloaterregioninfo.cpp | 39 +- indra/newview/llfloaterregioninfo.h | 3 + indra/newview/llfloatervfs.cpp | 31 +- indra/newview/llfloatervfs.h | 4 + indra/newview/llinventoryactions.cpp | 18 +- indra/newview/llinventorybackup.cpp | 125 +++--- indra/newview/llinventorybackup.h | 9 +- indra/newview/llinventorybridge.cpp | 33 +- indra/newview/llinventorybridge.h | 3 +- indra/newview/llpanelavatar.cpp | 17 +- indra/newview/llpanelavatar.h | 5 + indra/newview/llpanelpick.cpp | 35 +- indra/newview/llpanelpick.h | 5 +- indra/newview/llpreviewanim.cpp | 29 +- indra/newview/llpreviewanim.h | 3 + indra/newview/llpreviewnotecard.cpp | 22 +- indra/newview/llpreviewnotecard.h | 2 + indra/newview/llpreviewscript.cpp | 39 +- indra/newview/llpreviewscript.h | 3 + indra/newview/llpreviewsound.cpp | 28 +- indra/newview/llpreviewsound.h | 3 + indra/newview/llpreviewtexture.cpp | 18 +- indra/newview/llpreviewtexture.h | 2 + indra/newview/lluploaddialog.cpp | 4 - indra/newview/llviewermenu.cpp | 43 ++- indra/newview/llviewermenufile.cpp | 359 ++++++++---------- indra/newview/llviewermenufile.h | 2 - indra/newview/llviewerobjectbackup.cpp | 35 +- indra/newview/llviewerobjectbackup.h | 2 + indra/newview/llviewerwindow.cpp | 20 +- indra/newview/llviewerwindow.h | 4 +- indra/newview/statemachine/aifilepicker.cpp | 81 +++- indra/newview/statemachine/aifilepicker.h | 42 +- indra/newview/statemachine/aistatemachine.cpp | 19 +- .../filepicker/basic_plugin_filepicker.cpp | 56 ++- indra/plugins/filepicker/llfilepicker.cpp | 316 +++++++++++++-- indra/plugins/filepicker/llfilepicker.h | 39 +- 49 files changed, 1097 insertions(+), 564 deletions(-) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 29b50d7bc..28fcd7751 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -524,7 +524,11 @@ std::string LLDir::getTempFilename() const std::string LLDir::getScrubbedFileName(const std::string uncleanFileName) { std::string name(uncleanFileName); - const std::string illegalChars(getForbiddenFileChars()); + std::string illegalChars(getForbiddenFileChars()); +#if LL_LINUX || LL_SOLARIS + // Spaces in filenames are REALLY annoying on UNIX. + illegalChars += ' '; +#endif // replace any illegal file chars with and underscore '_' for( unsigned int i = 0; i < illegalChars.length(); i++ ) { diff --git a/indra/newview/floaterlocalassetbrowse.cpp b/indra/newview/floaterlocalassetbrowse.cpp index 76fa162b1..c643c636d 100644 --- a/indra/newview/floaterlocalassetbrowse.cpp +++ b/indra/newview/floaterlocalassetbrowse.cpp @@ -55,7 +55,7 @@ this feature is still a work in progress. #include #include "llviewertexturelist.h" #include "llviewerobjectlist.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewermenufile.h" #include "llfloaterimagepreview.h" #include "llfile.h" @@ -453,23 +453,27 @@ LocalAssetBrowser::~LocalAssetBrowser() void LocalAssetBrowser::AddBitmap() { - LLFilePicker& picker = LLFilePicker::instance(); - if ( !picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE) ) - { return; } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_IMAGE, "", "image", true); + filepicker->run(boost::bind(&LocalAssetBrowser::AddBitmap_continued, filepicker)); +} + +void LocalAssetBrowser::AddBitmap_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; bool change_happened = false; - std::string filename = picker.getFirstFile(); - while( !filename.empty() ) + std::vector const& filenames(filepicker->getFilenames()); + for(std::vector::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { - LocalBitmap* unit = new LocalBitmap( filename ); + LocalBitmap* unit = new LocalBitmap(*filename); if ( unit->getIfValidBool() ) { loaded_bitmaps.push_back( unit ); change_happened = true; } - - filename = picker.getNextFile(); } if ( change_happened ) diff --git a/indra/newview/floaterlocalassetbrowse.h b/indra/newview/floaterlocalassetbrowse.h index 6ee1c75a3..42620e314 100644 --- a/indra/newview/floaterlocalassetbrowse.h +++ b/indra/newview/floaterlocalassetbrowse.h @@ -169,6 +169,7 @@ class LocalBitmap */ +class AIFilePicker; class LocalAssetBrowser { @@ -181,6 +182,7 @@ class LocalAssetBrowser static void setLayerUpdated(bool toggle) { mLayerUpdated = toggle; } static void setSculptUpdated(bool toggle) { mSculptUpdated = toggle; } static void AddBitmap(void); + static void AddBitmap_continued(AIFilePicker* filepicker); static void DelBitmap( std::vector, S32 column = BITMAPLIST_COL_ID ); /* UpdateTextureCtrlList was made public cause texturectrl requests it once on spawn diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 042a53632..2992e60bd 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -293,7 +293,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) view->getPanel()->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO); if((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type) - && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD) + /* FIXME: && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD */) { view->getPanel()->openSelected(); } @@ -309,7 +309,8 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) // remove the "Uploading..." message LLUploadDialog::modalUploadFinished(); - + +#if 0 // FIXME: This needs to be done in some other way. // *FIX: This is a pretty big hack. What this does is check the // file picker if there are any more pending uploads. If so, // upload that file. @@ -339,6 +340,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) everyone_perms, display_name, callback, expected_upload_cost, userdata); } +#endif } LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index fb327e5a6..2a325c0bb 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -788,6 +788,15 @@ Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *c result = false; } } + else if (filter == FFLOAD_XML) + { + if (fileInfo.filetype != 'XML ' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("xml"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + ) + { + result = false; + } + } #ifdef _CORY_TESTING else if (filter == FFLOAD_GEOMETRY) { @@ -1327,6 +1336,12 @@ static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker) LLTrans::getString("animation_files") + " (*.bvh)"); } +static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) +{ + return add_simple_mime_filter_to_gtkchooser(picker, "text/xml", + LLTrans::getString("xml_file") + " (*.xml)"); +} + static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { GtkFileFilter *gfilter = gtk_file_filter_new(); @@ -1454,6 +1469,9 @@ BOOL LLFilePickerBase::getOpenFile( ELoadFilter filter ) case FFLOAD_IMAGE: filtername = add_imageload_filter_to_gtkchooser(picker); break; + case FFLOAD_XML: + filtername = add_xml_filter_to_gtkchooser(picker); + break; default:; break; } @@ -1530,6 +1548,7 @@ BOOL LLFilePickerBase::getOpenFile( ELoadFilter filter ) case FFLOAD_WAV: filename += ".wav"; break; case FFLOAD_IMAGE: filename += ".tga"; break; case FFLOAD_ANIM: filename += ".bvh"; break; + case FFLOAD_XML: filename += ".xml"; break; default: break; } mFiles.push_back(filename); diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 8063a7068..3be94f8e0 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -185,13 +185,9 @@ private: #if LL_DARWIN NavDialogCreationOptions mNavOptions; - std::vector mFileVector; - UInt32 mFileIndex; OSStatus doNavChooseDialog(ELoadFilter filter); OSStatus doNavSaveDialog(ESaveFilter filter, const std::string& filename); - void getFilePath(SInt32 index); - void getFileName(SInt32 index); static Boolean navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode); #endif diff --git a/indra/newview/llfloaterblacklist.cpp b/indra/newview/llfloaterblacklist.cpp index e565f1434..ff76ec407 100644 --- a/indra/newview/llfloaterblacklist.cpp +++ b/indra/newview/llfloaterblacklist.cpp @@ -7,7 +7,7 @@ #include "llsdserialize.h" #include "llscrolllistctrl.h" #include "llcheckboxctrl.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewerwindow.h" #include "llviewercontrol.h" #include "lldate.h" @@ -241,10 +241,17 @@ void LLFloaterBlacklist::saveToDisk() //static void LLFloaterBlacklist::onClickSave(void* user_data) { - LLFilePicker& file_picker = LLFilePicker::instance(); - if(file_picker.getSaveFile( LLFilePicker::FFSAVE_BLACKLIST, LLDir::getScrubbedFileName("untitled.blacklist"))) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("untitled.blacklist", FFSAVE_BLACKLIST); + filepicker->run(boost::bind(&LLFloaterBlacklist::onClickSave_continued, filepicker)); +} + +//static +void LLFloaterBlacklist::onClickSave_continued(AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) { - std::string file_name = file_picker.getFirstFile(); + std::string file_name = filepicker->getFilename(); llofstream export_file(file_name); LLSD data; for(std::map::iterator iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) @@ -259,10 +266,16 @@ void LLFloaterBlacklist::onClickSave(void* user_data) //static void LLFloaterBlacklist::onClickLoad(void* user_data) { - LLFilePicker& file_picker = LLFilePicker::instance(); - if(file_picker.getOpenFile(LLFilePicker::FFLOAD_BLACKLIST)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_BLACKLIST); + filepicker->run(boost::bind(&LLFloaterBlacklist::onClickLoad_continued, filepicker)); +} + +void LLFloaterBlacklist::onClickLoad_continued(AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) { - std::string file_name = file_picker.getFirstFile(); + std::string file_name = filepicker->getFilename(); llifstream xml_file(file_name); if(!xml_file.is_open()) return; LLSD data; diff --git a/indra/newview/llfloaterblacklist.h b/indra/newview/llfloaterblacklist.h index c35185721..c718fd71d 100644 --- a/indra/newview/llfloaterblacklist.h +++ b/indra/newview/llfloaterblacklist.h @@ -2,6 +2,9 @@ #ifndef LL_LLFLOATERBLACKLIST_H #define LL_LLFLOATERBLACKLIST_H #include "llfloater.h" + +class AIFilePicker; + class LLFloaterBlacklist : LLFloater { public: @@ -42,7 +45,9 @@ private: static void onClickAdd(void* user_data); static void onClickClear(void* user_data); static void onClickSave(void* user_data); + static void onClickSave_continued(AIFilePicker* filepicker); static void onClickLoad(void* user_data); + static void onClickLoad_continued(AIFilePicker* filepicker); static void onClickCopyUUID(void* user_data); static void onClickRemove(void* user_data); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 6a313c2bd..b8e23f387 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -75,7 +75,7 @@ #include "llviewercontrol.h" #include "lluictrlfactory.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "hippogridmanager.h" using namespace LLVOAvatarDefines; @@ -1846,14 +1846,20 @@ void LLFloaterCustomize::setCurrentWearableType( EWearableType type ) // reX: new function void LLFloaterCustomize::onBtnImport( void* userdata ) { - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getOpenFile( LLFilePicker::FFLOAD_XML ) ) - { - // User canceled import. - return; - } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_XML); + filepicker->run(boost::bind(&LLFloaterCustomize::onBtnImport_continued, filepicker)); +} - const std::string filename = file_picker.getFirstFile(); +void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + { + // User canceled import. + return; + } + + const std::string filename = filepicker->getFilename(); FILE* fp = LLFile::fopen(filename, "rb"); @@ -1900,8 +1906,14 @@ void LLFloaterCustomize::onBtnImport( void* userdata ) // reX: new function void LLFloaterCustomize::onBtnExport( void* userdata ) { - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_XML ) ) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("", FFSAVE_XML); + filepicker->run(boost::bind(&LLFloaterCustomize::onBtnExport_continued, filepicker)); +} + +void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) { // User canceled export. return; @@ -1910,7 +1922,7 @@ void LLFloaterCustomize::onBtnExport( void* userdata ) LLViewerInventoryItem* item; BOOL is_modifiable; - const std::string filename = file_picker.getFirstFile(); + const std::string filename = filepicker->getFilename(); FILE* fp = LLFile::fopen(filename, "wb"); diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index ceb49af01..84af37f70 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -64,6 +64,7 @@ class LLVisualParam; class LLVisualParamReset; class LLWearableSaveAsDialog; class LLPanelEditWearable; +class AIFilePicker; ///////////////////////////////////////////////////////////////////// // LLFloaterCustomize @@ -110,7 +111,9 @@ public: static void onBtnMakeOutfit( void* userdata ); static void onMakeOutfitCommit( LLMakeOutfitDialog* dialog, void* userdata ); static void onBtnImport( void* userdata ); + static void onBtnImport_continued(AIFilePicker* filepicker); static void onBtnExport( void* userdata ); + static void onBtnExport_continued(AIFilePicker* filepicker); static void onTabChanged( void* userdata, bool from_click ); static void onTabPrecommit( void* userdata, bool from_click ); diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp index 255547933..c210caa1c 100644 --- a/indra/newview/llfloaterfriends.cpp +++ b/indra/newview/llfloaterfriends.cpp @@ -67,7 +67,7 @@ #include "llvoiceclient.h" #include "llsdserialize.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewermenufile.h" #include "llviewermenu.h" @@ -1080,17 +1080,22 @@ void LLPanelFriends::onClickRemove(void* user_data) void LLPanelFriends::onClickExport(void* user_data) { - LLPanelFriends* panelp = (LLPanelFriends*)user_data; std::string agn; gAgent.getName(agn); - std::string filename = agn+".friendlist"; - LLFilePicker& picker = LLFilePicker::instance(); - if(!picker.getSaveFile( LLFilePicker::FFSAVE_ALL, filename ) ) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(agn + ".friendlist", FFSAVE_ALL); + filepicker->run(boost::bind(&LLPanelFriends::onClickExport_continued, user_data, filepicker)); +} + +void LLPanelFriends::onClickExport_continued(void* user_data, AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) { // User canceled save. return; } - filename = picker.getFirstFile(); + std::string const filename = filepicker->getFilename(); + LLPanelFriends* panelp = (LLPanelFriends*)user_data; std::vector selected = panelp->mFriendsList->getAllData();//->getAllSelected(); LLSD llsd; @@ -1126,19 +1131,22 @@ void LLPanelFriends::onClickExport(void* user_data) bool LLPanelFriends::merging; void LLPanelFriends::onClickImport(void* user_data) +{ + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(); + filepicker->run(boost::bind(&LLPanelFriends::onClickImport_filepicker_continued, filepicker)); +} + //THIS CODE IS DESIGNED SO THAT EXP/IMP BETWEEN GRIDS WILL FAIL //because assuming someone having the same name on another grid is the same person is generally a bad idea //i might add the option to query the user as to intelligently detecting matching names on a alternative grid // jcool410 +void LLPanelFriends::onClickImport_filepicker_continued(AIFilePicker* filepicker) { - //LLPanelFriends* panelp = (LLPanelFriends*)user_data; - //is_agent_friend( - - const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ALL); - - if (filename.empty()) + if (!filepicker->hasFilename()) return; + std::string filename = filepicker->getFilename(); llifstream importer(filename); LLSD data; LLSDSerialize::fromXMLDocument(data, importer); diff --git a/indra/newview/llfloaterfriends.h b/indra/newview/llfloaterfriends.h index 20c996d23..e6223cfb2 100644 --- a/indra/newview/llfloaterfriends.h +++ b/indra/newview/llfloaterfriends.h @@ -45,6 +45,7 @@ class LLFriendObserver; class LLRelationship; class LLScrollListItem; class LLScrollListCtrl; +class AIFilePicker; /** * @class LLPanelFriends @@ -144,7 +145,9 @@ private: static void onClickAddFriend(void* user_data); static void onClickRemove(void* user_data); static void onClickExport(void* user_data); + static void onClickExport_continued(void* user_data, AIFilePicker* filepicker); static void onClickImport(void* user_data); + static void onClickImport_filepicker_continued(AIFilePicker* filepicker); public: static void FriendImportState(LLUUID id, bool accepted); private: diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 03f616af3..994fe3ad3 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -53,7 +53,7 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llfloaterdaycycle.h" #include "llfloatergodtools.h" // for send_sim_wide_deletes() #include "llfloatertopobjects.h" // added to fix SL-32336 @@ -1324,41 +1324,50 @@ void LLPanelRegionTerrainInfo::onChangeSunHour(LLUICtrl* ctrl, void*) // static void LLPanelRegionTerrainInfo::onClickDownloadRaw(void* data) { - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getSaveFile(LLFilePicker::FFSAVE_RAW, "terrain.raw")) + LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("terrain.raw", FFSAVE_RAW); + filepicker->run(boost::bind(&LLPanelRegionTerrainInfo::onClickUploadRaw_continued, self, filepicker)); +} + +void LLPanelRegionTerrainInfo::onClickDownloadRaw_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) { - llwarns << "No file" << llendl; return; } - std::string filepath = picker.getFirstFile(); + std::string filepath = filepicker->getFilename(); gXferManager->expectFileForRequest(filepath); - LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; strings_t strings; strings.push_back("download filename"); strings.push_back(filepath); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); } // static void LLPanelRegionTerrainInfo::onClickUploadRaw(void* data) { - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(LLFilePicker::FFLOAD_RAW)) - { - llwarns << "No file" << llendl; + LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_RAW); + filepicker->run(boost::bind(&LLPanelRegionTerrainInfo::onClickUploadRaw_continued, self, filepicker)); +} + +void LLPanelRegionTerrainInfo::onClickUploadRaw_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) return; - } - std::string filepath = picker.getFirstFile(); + + std::string filepath = filepicker->getFilename(); gXferManager->expectFileForTransfer(filepath); - LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; strings_t strings; strings.push_back("upload filename"); strings.push_back(filepath); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); LLNotifications::instance().add("RawUploadStarted"); } diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index fd0d9ce63..5871e3525 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -51,6 +51,7 @@ class LLNameListCtrl; class LLSliderCtrl; class LLSpinCtrl; class LLTextBox; +class AIFilePicker; class LLPanelRegionGeneralInfo; class LLPanelRegionDebugInfo; @@ -242,7 +243,9 @@ protected: static void onChangeSunHour(LLUICtrl* ctrl, void*); static void onClickDownloadRaw(void*); + void onClickDownloadRaw_continued(AIFilePicker* filepicker); static void onClickUploadRaw(void*); + void onClickUploadRaw_continued(AIFilePicker* filepicker); static void onClickBakeTerrain(void*); bool callbackBakeTerrain(const LLSD& notification, const LLSD& response); }; diff --git a/indra/newview/llfloatervfs.cpp b/indra/newview/llfloatervfs.cpp index 2db5b3459..0192e76b9 100644 --- a/indra/newview/llfloatervfs.cpp +++ b/indra/newview/llfloatervfs.cpp @@ -4,7 +4,7 @@ #include "lluictrlfactory.h" #include "llscrolllistctrl.h" #include "llcheckboxctrl.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "lllocalinventory.h" #include "llviewerwindow.h" #include "llassetconverter.h" @@ -229,25 +229,32 @@ void LLFloaterVFS::setEditEnabled(bool enabled) childSetEnabled("reload_btn", enabled); // WORKS! childSetEnabled("remove_btn", enabled); } + // static void LLFloaterVFS::onClickAdd(void* user_data) { - LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; - if(!floaterp) return; - LLUUID asset_id; - LLAssetType::EType asset_type = LLAssetType::AT_NONE; - asset_id.generate(); - LLFilePicker& file_picker = LLFilePicker::instance(); - if(file_picker.getOpenFile(LLFilePicker::FFLOAD_ALL)) + if(!user_data) return; + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(); + filepicker->run(boost::bind(&LLFloaterVFS::onClickAdd_continued, user_data, filepicker)); +} + +// static +void LLFloaterVFS::onClickAdd_continued(void* user_data, AIFilePicker* filepicker) +{ + LLFloaterVFS* self = (LLFloaterVFS*)user_data; + if (filepicker->hasFilename()) { - std::string file_name = file_picker.getFirstFile(); + std::string file_name = filepicker->getFilename(); std::string temp_filename = file_name + ".tmp"; - asset_type = LLAssetConverter::convert(file_name, temp_filename); + LLAssetType::EType asset_type = LLAssetConverter::convert(file_name, temp_filename); if(asset_type == LLAssetType::AT_NONE) { // todo: show a warning return; } + LLUUID asset_id; + asset_id.generate(); S32 file_size; LLAPRFile fp; fp.open(temp_filename, LL_APR_RB, LLAPRFile::global, &file_size); @@ -302,8 +309,8 @@ void LLFloaterVFS::onClickAdd(void* user_data) file.mID = asset_id; file.mType = asset_type; file.mName = gDirUtilp->getBaseFileName(file_name, true); - floaterp->add(file); - /*if(floaterp->getChild("create_pretend_item")->get()) + self->add(file); + /*if(self->getChild("create_pretend_item")->get()) { LLLocalInventory::addItem(file.mName, (int)file.mType, file.mID, true); }*/ diff --git a/indra/newview/llfloatervfs.h b/indra/newview/llfloatervfs.h index 7218b1090..47d1d8755 100644 --- a/indra/newview/llfloatervfs.h +++ b/indra/newview/llfloatervfs.h @@ -3,6 +3,9 @@ #define LL_LLFLOATERVFS_H #include "llfloater.h" #include "llassettype.h" + +class AIFilePicker; + class LLFloaterVFS : LLFloater { typedef struct @@ -27,6 +30,7 @@ public: void reloadEntry(entry file); void removeEntry(); static void onClickAdd(void* user_data); + static void onClickAdd_continued(void* user_data, AIFilePicker* filepicker); static void onClickClear(void* user_data); static void onClickReloadAll(void* user_data); static void onCommitFileList(LLUICtrl* ctrl, void* user_data); diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index b770a531d..8b04a1744 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -91,6 +91,7 @@ #include "llinventorybackup.h" //#include "llcheats.h" //#include "llnotecardmagic.h" +#include "statemachine/aifilepicker.h" // const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not) @@ -569,14 +570,19 @@ class LLLoadInvCacheFloater : public inventory_listener_t { LLInventoryModel* model = mPtr->getPanel()->getModel(); if(!model) return false; - LLFilePicker& file_picker = LLFilePicker::instance(); - if(file_picker.getOpenFile( LLFilePicker::FFLOAD_INVGZ )) - { - std::string file_name = file_picker.getFirstFile(); - LLLocalInventory::loadInvCache(file_name); - } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_INVGZ, "", "invgz"); + filepicker->run(boost::bind(&LLLoadInvCacheFloater::filepicker_callback, this, filepicker)); return true; } + + void filepicker_callback(AIFilePicker* filepicker) + { + if(filepicker->hasFilename()) + { + LLLocalInventory::loadInvCache(filepicker->getFilename()); + } + } }; class LLRefreshInvModel : public inventory_listener_t diff --git a/indra/newview/llinventorybackup.cpp b/indra/newview/llinventorybackup.cpp index a5ce38e59..c6f687272 100644 --- a/indra/newview/llinventorybackup.cpp +++ b/indra/newview/llinventorybackup.cpp @@ -4,7 +4,7 @@ #include "llinventorybackup.h" #include "llinventorymodel.h" #include "llviewerinventory.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "lldirpicker.h" #include "llviewertexturelist.h" // gTextureList #include "llagent.h" // gAgent @@ -158,64 +158,64 @@ bool LLInventoryBackup::itemIsFolder(LLInventoryItem* item) } // static -LLFilePicker::ESaveFilter LLInventoryBackup::getSaveFilter(LLInventoryItem* item) +ESaveFilter LLInventoryBackup::getSaveFilter(LLInventoryItem* item) { LLAssetType::EType type = item->getType(); EWearableType wear = (EWearableType)(item->getFlags() & 0xFF); switch(type) { case LLAssetType::AT_TEXTURE: - return LLFilePicker::FFSAVE_TGA; + return FFSAVE_TGA; case LLAssetType::AT_SOUND: - return LLFilePicker::FFSAVE_OGG; + return FFSAVE_OGG; case LLAssetType::AT_SCRIPT: case LLAssetType::AT_LSL_TEXT: - return LLFilePicker::FFSAVE_LSL; + return FFSAVE_LSL; case LLAssetType::AT_ANIMATION: - return LLFilePicker::FFSAVE_ANIMATN; + return FFSAVE_ANIMATN; case LLAssetType::AT_GESTURE: - return LLFilePicker::FFSAVE_GESTURE; + return FFSAVE_GESTURE; case LLAssetType::AT_NOTECARD: - return LLFilePicker::FFSAVE_NOTECARD; + return FFSAVE_NOTECARD; case LLAssetType::AT_LANDMARK: - return LLFilePicker::FFSAVE_LANDMARK; + return FFSAVE_LANDMARK; case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: switch(wear) { case WT_EYES: - return LLFilePicker::FFSAVE_EYES; + return FFSAVE_EYES; case WT_GLOVES: - return LLFilePicker::FFSAVE_GLOVES; + return FFSAVE_GLOVES; case WT_HAIR: - return LLFilePicker::FFSAVE_HAIR; + return FFSAVE_HAIR; case WT_JACKET: - return LLFilePicker::FFSAVE_JACKET; + return FFSAVE_JACKET; case WT_PANTS: - return LLFilePicker::FFSAVE_PANTS; + return FFSAVE_PANTS; case WT_SHAPE: - return LLFilePicker::FFSAVE_SHAPE; + return FFSAVE_SHAPE; case WT_SHIRT: - return LLFilePicker::FFSAVE_SHIRT; + return FFSAVE_SHIRT; case WT_SHOES: - return LLFilePicker::FFSAVE_SHOES; + return FFSAVE_SHOES; case WT_SKIN: - return LLFilePicker::FFSAVE_SKIN; + return FFSAVE_SKIN; case WT_SKIRT: - return LLFilePicker::FFSAVE_SKIRT; + return FFSAVE_SKIRT; case WT_SOCKS: - return LLFilePicker::FFSAVE_SOCKS; + return FFSAVE_SOCKS; case WT_UNDERPANTS: - return LLFilePicker::FFSAVE_UNDERPANTS; + return FFSAVE_UNDERPANTS; case WT_UNDERSHIRT: - return LLFilePicker::FFSAVE_UNDERSHIRT; + return FFSAVE_UNDERSHIRT; case WT_PHYSICS: - return LLFilePicker::FFSAVE_PHYSICS; + return FFSAVE_PHYSICS; default: - return LLFilePicker::FFSAVE_ALL; + return FFSAVE_ALL; } default: - return LLFilePicker::FFSAVE_ALL; + return FFSAVE_ALL; } } @@ -352,28 +352,9 @@ void LLInventoryBackup::imageCallback(BOOL success, return; } - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( getSaveFilter(item), LLDir::getScrubbedFileName(item->getName())) ) - { - // User canceled or we failed to acquire save file. - return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); - - LLPointer image_tga = new LLImageTGA; - if( !image_tga->encode( src ) ) - { - LLSD args; - args["ERROR_MESSAGE"] = "Couldn't encode file."; - LLNotifications::instance().add("ErrorMessage", args); - } - else if( !image_tga->save( filename ) ) - { - LLSD args; - args["ERROR_MESSAGE"] = "Couldn't write file."; - LLNotifications::instance().add("ErrorMessage", args); - } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(LLDir::getScrubbedFileName(item->getName()), getSaveFilter(item)); + filepicker->run(boost::bind(&LLInventoryBackup::imageCallback_continued, src, filepicker)); } else { @@ -381,6 +362,28 @@ void LLInventoryBackup::imageCallback(BOOL success, } } +void LLInventoryBackup::imageCallback_continued(LLImageRaw* src, AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; + + std::string filename = filepicker->getFilename(); + + LLPointer image_tga = new LLImageTGA; + if( !image_tga->encode( src ) ) + { + LLSD args; + args["ERROR_MESSAGE"] = "Couldn't encode file."; + LLNotifications::instance().add("ErrorMessage", args); + } + else if( !image_tga->save( filename ) ) + { + LLSD args; + args["ERROR_MESSAGE"] = "Couldn't write file."; + LLNotifications::instance().add("ErrorMessage", args); + } +} + // static void LLInventoryBackup::assetCallback(LLVFS *vfs, const LLUUID& asset_uuid, @@ -402,7 +405,7 @@ void LLInventoryBackup::assetCallback(LLVFS *vfs, LLVFile file(vfs, asset_uuid, type, LLVFile::READ); S32 size = file.getSize(); - char* buffer = new char[size]; + char* buffer = new char[size]; // Deleted in assetCallback_continued. if (buffer == NULL) { llerrs << "Memory Allocation Failed" << llendl; @@ -413,18 +416,22 @@ void LLInventoryBackup::assetCallback(LLVFS *vfs, // Write it back out... - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( getSaveFilter(item), LLDir::getScrubbedFileName(item->getName())) ) - { - // User canceled or we failed to acquire save file. - return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(LLDir::getScrubbedFileName(item->getName()), getSaveFilter(item)); + filepicker->run(boost::bind(&LLInventoryBackup::assetCallback_continued, buffer, size, filepicker)); +} - std::ofstream export_file(filename.c_str(), std::ofstream::binary); - export_file.write(buffer, size); - export_file.close(); +// static +void LLInventoryBackup::assetCallback_continued(char* buffer, S32 size, AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) + { + std::string filename = filepicker->getFilename(); + std::ofstream export_file(filename.c_str(), std::ofstream::binary); + export_file.write(buffer, size); + export_file.close(); + } + delete [] buffer; } // static diff --git a/indra/newview/llinventorybackup.h b/indra/newview/llinventorybackup.h index 98664a9a5..16d9a3ad1 100644 --- a/indra/newview/llinventorybackup.h +++ b/indra/newview/llinventorybackup.h @@ -11,11 +11,10 @@ #include "llviewerinventory.h" #include "llfolderview.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewertexture.h" #include "llfloater.h" - class LLInventoryBackupOrder { public: @@ -94,10 +93,12 @@ private: }; +class AIFilePicker; + class LLInventoryBackup { public: - static LLFilePicker::ESaveFilter getSaveFilter(LLInventoryItem* item); + static ESaveFilter getSaveFilter(LLInventoryItem* item); static std::string getExtension(LLInventoryItem* item); static std::string getUniqueFilename(std::string filename, std::string extension); static std::string getUniqueDirname(std::string dirname); @@ -120,10 +121,12 @@ private: S32 discard_level, BOOL final, void* userdata); + static void imageCallback_continued(LLImageRaw* src, AIFilePicker* filepicker); static void assetCallback(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); + static void assetCallback_continued(char* buffer, S32 size, AIFilePicker* filepicker); static void climb(LLInventoryCategory* cat, std::vector& cats, std::vector& items); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 3455caf19..aa6dc78d5 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -99,6 +99,7 @@ //#include "llcheats.h" #include "dofloaterhex.h" #include "hgfloatertexteditor.h" +#include "statemachine/aifilepicker.h" // // Editing wearables from inventory is an include-hungry feature -.- -SG @@ -1106,30 +1107,26 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, else if("reupload" == action) { LLInventoryItem* item = model->getItem(mUUID); - if(!item) return; - - LLFilePicker& picker = LLFilePicker::instance(); - std::string filename; - - switch(item->getType()) + if (item && item->getType() == LLAssetType::AT_TEXTURE) { - case LLAssetType::AT_TEXTURE: - if(!picker.getOpenFile(LLFilePicker::FFLOAD_IMAGE)) - return; - filename = picker.getFirstFile(); - if(!filename.empty()) - { - LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename, item); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml"); - } - break; - default: - break; + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_IMAGE, "", "image"); + filepicker->run(boost::bind(&LLItemBridge::showFloaterImagePreview, item, filepicker)); } } // } +// static +void LLItemBridge::showFloaterImagePreview(LLInventoryItem* item, AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) + { + LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filepicker->getFilename(), item); + LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml"); + } +} + void LLItemBridge::selectItem() { LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index a3108d653..2a668e684 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -277,6 +277,7 @@ protected: LLInventoryType::EType mInvType; }; +class AIFilePicker; class LLItemBridge : public LLInvFVBridge { @@ -303,7 +304,7 @@ public: virtual BOOL hasChildren() const { return FALSE; } virtual BOOL isUpToDate() const { return TRUE; } - + static void showFloaterImagePreview(LLInventoryItem* item, AIFilePicker* filepicker); // override for LLInvFVBridge virtual void clearDisplayName() { mDisplayName.clear(); } diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 52e812924..9a3add526 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -1213,20 +1213,27 @@ void LLPanelAvatarPicks::onClickNew(void* data) } //Pick import and export - RK +// static void LLPanelAvatarPicks::onClickImport(void* data) { LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; - LLPanelPick* panel_pick = new LLPanelPick(FALSE); - LLTabContainer* tabs = self->getChild("picks tab"); + self->mPanelPick = new LLPanelPick(FALSE); + self->mPanelPick->importNewPick(&LLPanelAvatarPicks::onClickImport_continued, data); +} - bool import = panel_pick->importNewPick(); - if(tabs && import) +// static +void LLPanelAvatarPicks::onClickImport_continued(void* data, bool import) +{ + LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; + LLTabContainer* tabs = self->getChild("picks tab"); + if(tabs && import && self->mPanelPick) { - tabs->addTabPanel(panel_pick, panel_pick->getPickName()); + tabs->addTabPanel(self->mPanelPick, self->mPanelPick->getPickName()); tabs->selectLastTab(); } } +// static void LLPanelAvatarPicks::onClickExport(void* data) { LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 24de55cb5..812da4571 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -57,6 +57,7 @@ class LLViewerObject; class LLMessageSystem; class LLIconCtrl; class LLMediaCtrl; +class LLPanelPick; enum EOnlineStatus { @@ -265,9 +266,13 @@ private: //Pick import and export - RK static void onClickImport(void* data); + static void onClickImport_continued(void* self, bool import); static void onClickExport(void* data); bool callbackDelete(const LLSD& notification, const LLSD& response); + + // Used to pass it from onClickImport to onClickImport_continued. + LLPanelPick* mPanelPick; }; diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index c7f31f1f9..9af829e9b 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -66,7 +66,7 @@ //For pick import and export - RK -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewernetwork.h" #include "llsdserialize.h" #include "hippogridmanager.h" @@ -201,14 +201,19 @@ void LLPanelPick::initNewPick() } //Imports a new pick from an xml - RK -bool LLPanelPick::importNewPick() +void LLPanelPick::importNewPick(void (*callback)(void*, bool), void* data) { - LLFilePicker& file_picker = LLFilePicker::instance(); + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_XML, "", "export"); + filepicker->run(boost::bind(&LLPanelPick::importNewPick_continued, this, callback, data, filepicker)); +} - if(!file_picker.getOpenFile(LLFilePicker::FFLOAD_XML)) return false;// User canceled load. - else +void LLPanelPick::importNewPick_continued(void (*callback)(void*, bool), void* data, AIFilePicker* filepicker) +{ + bool result = false; + if (filepicker->hasFilename()) { - std::string file = file_picker.getFirstFile(); + std::string file = filepicker->getFilename(); llifstream importer(file); LLSD data; @@ -231,19 +236,25 @@ bool LLPanelPick::importNewPick() mImporting = true; sendPickInfoUpdate(); - return true; + result = true; } + (*callback)(data, result); } //Exports a pick to an XML - RK void LLPanelPick::exportPick() { - LLFilePicker& file_picker = LLFilePicker::instance(); - - if(!file_picker.getSaveFile(LLFilePicker::FFSAVE_XML)) - return;// User canceled save. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("", FFSAVE_XML, "", "export"); + filepicker->run(boost::bind(&LLPanelPick::exportPick_continued, this, filepicker)); +} - std::string destination = file_picker.getFirstFile(); +void LLPanelPick::exportPick_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; + + std::string destination = filepicker->getFilename(); LLSD datas; diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 49b07924c..bfa702251 100644 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -50,6 +50,7 @@ class LLTextEditor; class LLTextureCtrl; class LLUICtrl; class LLMessageSystem; +class AIFilePicker; class LLPanelPick : public LLPanel { @@ -70,8 +71,10 @@ public: void initNewPick(); //Pick import and export - RK - bool importNewPick(); + void importNewPick(void (*callback)(void*, bool), void* data); + void importNewPick_continued(void (*callback)(void*, bool), void* data, AIFilePicker* filepicker); void exportPick(); + void exportPick_continued(AIFilePicker* filepicker); // We need to know the creator id so the database knows which partition // to query for the pick data. diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index f9cb5f210..85349883b 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -40,7 +40,7 @@ #include "llvoavatar.h" #include "llagent.h" // gAgent #include "llkeyframemotion.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "lllineeditor.h" #include "lluictrlfactory.h" #include "lluictrlfactory.h" @@ -392,21 +392,22 @@ void LLPreviewAnim::gotAssetForSave(LLVFS *vfs, // Write it back out... - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_ANIMATN, LLDir::getScrubbedFileName(self->getItem()->getName())) ) - { - // User canceled or we failed to acquire save file. - return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(LLDir::getScrubbedFileName(self->getItem()->getName()) + ".animatn", FFSAVE_ANIMATN); + filepicker->run(boost::bind(&LLPreviewAnim::gotAssetForSave_continued, buffer, size, filepicker)); +} - std::ofstream export_file(filename.c_str(), std::ofstream::binary); - export_file.write(buffer, size); - export_file.close(); - +// static +void LLPreviewAnim::gotAssetForSave_continued(char* buffer, S32 size, AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + { + std::string filename = filepicker->getFilename(); + std::ofstream export_file(filename.c_str(), std::ofstream::binary); + export_file.write(buffer, size); + export_file.close(); + } delete[] buffer; - buffer = NULL; } // virtual diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index 115419fb6..3b9c53025 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -36,6 +36,8 @@ #include "llpreview.h" #include "llcharacter.h" +class AIFilePicker; + class LLPreviewAnim : public LLPreview { public: @@ -59,6 +61,7 @@ public: const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); + static void gotAssetForSave_continued(char* buffer, S32 size, AIFilePicker* filepicker); static void copyAnimID(void* userdata); // static void endAnimCallback( void *userdata ); diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index c2c3e8869..6acdc32ba 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -61,7 +61,7 @@ #include "lllineeditor.h" #include "lluictrlfactory.h" // -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" // ///---------------------------------------------------------------------------- @@ -717,17 +717,18 @@ void LLPreviewNotecard::saveAs() if(item) { // gAssetStorage->getAssetData(item->getAssetUUID(), LLAssetType::AT_NOTECARD, LLPreviewNotecard::gotAssetForSave, this, TRUE); - default_filename = LLDir::getScrubbedFileName(item->getName()); + default_filename = LLDir::getScrubbedFileName(item->getName()) + ".notecard"; } - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_NOTECARD, default_filename ) ) - { - // User canceled or we failed to acquire save file. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(default_filename, FFSAVE_NOTECARD); + filepicker->run(boost::bind(&LLPreviewNotecard::saveAs_continued, this, filepicker)); +} + +void LLPreviewNotecard::saveAs_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); LLViewerTextEditor* editor = getChild("Notecard Editor"); @@ -738,8 +739,9 @@ void LLPreviewNotecard::saveAs() return; } - S32 size = buffer.length() + 1; + S32 size = buffer.length(); + std::string filename = filepicker->getFilename(); std::ofstream export_file(filename.c_str(), std::ofstream::binary); export_file.write(buffer.c_str(), size); export_file.close(); diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index c3bf0e2f9..04568bf65 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -46,6 +46,7 @@ class LLTextEditor; class LLViewerTextEditor; class LLButton; +class AIFilePicker; class LLPreviewNotecard : public LLPreview { @@ -128,6 +129,7 @@ protected: // virtual BOOL canSaveAs() const; virtual void saveAs(); + void saveAs_continued(AIFilePicker* filepicker); // }; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 7b6bab72e..a58f1180e 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -54,6 +54,7 @@ #include "lltextbox.h" #include "lltooldraganddrop.h" #include "llvfile.h" +#include "statemachine/aifilepicker.h" #include "llagent.h" #include "llnotify.h" @@ -1700,23 +1701,23 @@ void LLPreviewLSL::saveAs() const LLInventoryItem *item = getItem(); if(item) { - default_filename = LLDir::getScrubbedFileName(item->getName()); + default_filename = LLDir::getScrubbedFileName(item->getName()) + ".lsl"; } - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_LSL, default_filename ) ) - { - // User canceled or we failed to acquire save file. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(default_filename, FFSAVE_LSL); + filepicker->run(boost::bind(&LLPreviewLSL::saveAs_continued, this, filepicker)); +} + +void LLPreviewLSL::saveAs_continued(AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); std::string utf8text = mScriptEd->mEditor->getText(); - LLFILE* fp = LLFile::fopen(filename, "wb"); + LLFILE* fp = LLFile::fopen(filepicker->getFilename(), "wb"); fputs(utf8text.c_str(), fp); fclose(fp); - fp = NULL; } // /// --------------------------------------------------------------------------- @@ -2654,19 +2655,19 @@ void LLLiveLSLEditor::saveAs() default_filename = LLDir::getScrubbedFileName(item->getName()); } - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_LSL, default_filename ) ) - { - // User canceled or we failed to acquire save file. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(default_filename, FFSAVE_LSL); + filepicker->run(boost::bind(&LLLiveLSLEditor::saveAs_continued, this, filepicker)); +} + +void LLLiveLSLEditor::saveAs_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); std::string utf8text = mScriptEd->mEditor->getText(); - LLFILE* fp = LLFile::fopen(filename, "wb"); + LLFILE* fp = LLFile::fopen(filepicker->getFilename(), "wb"); fputs(utf8text.c_str(), fp); fclose(fp); - fp = NULL; } // diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 58959e445..aa03a6c2e 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -53,6 +53,7 @@ struct LLEntryAndEdCore; class LLMenuBarGL; class LLFloaterScriptSearch; class LLKeywordToken; +class AIFilePicker; // Inner, implementation class. LLPreviewScript and LLLiveLSLEditor each own one of these. class LLScriptEdCore : public LLPanel, public LLEventTimer @@ -189,6 +190,7 @@ protected: // virtual BOOL canSaveAs() const; virtual void saveAs(); + void saveAs_continued(AIFilePicker* filepicker); // static void onSearchReplace(void* userdata); @@ -261,6 +263,7 @@ protected: // virtual BOOL canSaveAs() const; virtual void saveAs(); + void saveAs_continued(AIFilePicker* filepicker); // static void onSearchReplace(void* userdata); diff --git a/indra/newview/llpreviewsound.cpp b/indra/newview/llpreviewsound.cpp index e40dddbd2..890979578 100644 --- a/indra/newview/llpreviewsound.cpp +++ b/indra/newview/llpreviewsound.cpp @@ -48,7 +48,7 @@ #include "llchat.h" #include "llfloaterchat.h" #include "llviewerwindow.h" // for alert -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" // for ambient play: #include "llviewerregion.h" // @@ -330,18 +330,22 @@ void LLPreviewSound::gotAssetForSave(LLVFS *vfs, // Write it back out... - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_OGG, LLDir::getScrubbedFileName(self->getItem()->getName())) ) - { - // User canceled or we failed to acquire save file. - return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(LLDir::getScrubbedFileName(self->getItem()->getName()) + ".ogg", FFSAVE_OGG); + filepicker->run(boost::bind(&LLPreviewSound::gotAssetForSave_continued, buffer, size, filepicker)); +} - std::ofstream export_file(filename.c_str(), std::ofstream::binary); - export_file.write(buffer, size); - export_file.close(); +// static +void LLPreviewSound::gotAssetForSave_continued(char* buffer, S32 size, AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) + { + std::string filename = filepicker->getFilename(); + std::ofstream export_file(filename.c_str(), std::ofstream::binary); + export_file.write(buffer, size); + export_file.close(); + } + delete [] buffer; } // virtual diff --git a/indra/newview/llpreviewsound.h b/indra/newview/llpreviewsound.h index 535b233c9..bd8b9c0f0 100644 --- a/indra/newview/llpreviewsound.h +++ b/indra/newview/llpreviewsound.h @@ -35,6 +35,8 @@ #include "llpreview.h" +class AIFilePicker; + class LLPreviewSound : public LLPreview { public: @@ -59,6 +61,7 @@ public: const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); + static void gotAssetForSave_continued(char* buffer, S32 size, AIFilePicker* filepicker); // protected: diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 8eb803401..2e52f3d47 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -37,7 +37,7 @@ #include "llagent.h" #include "llbutton.h" #include "llcombobox.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llimagetga.h" #include "llinventoryview.h" #include "llinventory.h" @@ -380,15 +380,19 @@ void LLPreviewTexture::saveAs() if( mLoadingFullImage ) return; - LLFilePicker& file_picker = LLFilePicker::instance(); const LLViewerInventoryItem* item = getItem() ; - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_TGA, item ? LLDir::getScrubbedFileName(item->getName()) : LLStringUtil::null) ) - { - // User canceled or we failed to acquire save file. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(item ? LLDir::getScrubbedFileName(item->getName()) + ".tga" : LLStringUtil::null, FFSAVE_TGA, "", "image"); + filepicker->run(boost::bind(&LLPreviewTexture::saveAs_continued, this, item, filepicker)); +} + +void LLPreviewTexture::saveAs_continued(LLViewerInventoryItem const* item, AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) return; - } + // remember the user-approved/edited file name. - mSaveFileName = file_picker.getFirstFile(); + mSaveFileName = filepicker->getFilename(); mLoadingFullImage = TRUE; getWindow()->incBusyCount(); mImage->forceToSaveRawImage(0) ;//re-fetch the raw image if the old one is removed. diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index fb75876fc..ce26d4dd4 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -40,6 +40,7 @@ class LLComboBox; class LLImageRaw; +class AIFilePicker; class LLPreviewTexture : public LLPreview { @@ -64,6 +65,7 @@ public: virtual BOOL canSaveAs() const; virtual void saveAs(); + void saveAs_continued(LLViewerInventoryItem const* item, AIFilePicker* filepicker); virtual LLUUID getItemID(); virtual std::string getItemCreatorName(); virtual std::string getItemCreationDate(); diff --git a/indra/newview/lluploaddialog.cpp b/indra/newview/lluploaddialog.cpp index 2ba87f01b..a860e5303 100644 --- a/indra/newview/lluploaddialog.cpp +++ b/indra/newview/lluploaddialog.cpp @@ -161,10 +161,6 @@ void LLUploadDialog::setMessage( const std::string& msg) LLUploadDialog::~LLUploadDialog() { gFocusMgr.releaseFocusIfNeeded( this ); - -// LLFilePicker::instance().reset(); - - LLUploadDialog::sDialog = NULL; } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 873e6d1ae..2c898d300 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -69,6 +69,7 @@ #include "lltimer.h" #include "llvfile.h" #include "llvolumemgr.h" +#include "statemachine/aifilepicker.h" // newview includes #include "llagent.h" @@ -1223,19 +1224,21 @@ void init_debug_world_menu(LLMenuGL* menu) menu->createJumpKeys(); } - +static void handle_export_menus_to_xml_continued(AIFilePicker* filepicker); void handle_export_menus_to_xml(void*) { + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("", FFSAVE_XML); + filepicker->run(boost::bind(&handle_export_menus_to_xml_continued, filepicker)); +} - LLFilePicker& picker = LLFilePicker::instance(); - if(!picker.getSaveFile(LLFilePicker::FFSAVE_XML)) +static void handle_export_menus_to_xml_continued(AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) { - llwarns << "No file" << llendl; return; } - std::string filename = picker.getFirstFile(); - - llofstream out(filename); + llofstream out(filepicker->getFilename()); LLXMLNodePtr node = gMenuBarView->getXML(); node->writeToOstream(out); out.close(); @@ -8645,6 +8648,7 @@ const LLRect LLViewerMenuHolderGL::getMenuRect() const return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT); } +static void handle_save_to_xml_continued(LLFloater* frontmost, AIFilePicker* filepicker); void handle_save_to_xml(void*) { LLFloater* frontmost = gFloaterView->getFrontmost(); @@ -8664,20 +8668,33 @@ void handle_save_to_xml(void*) LLStringUtil::replaceChar(default_name, ':', '_'); LLStringUtil::replaceChar(default_name, '"', '_'); - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getSaveFile(LLFilePicker::FFSAVE_XML, default_name)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(default_name, FFSAVE_XML); + filepicker->run(boost::bind(&handle_save_to_xml_continued, frontmost, filepicker)); +} + +static void handle_save_to_xml_continued(LLFloater* frontmost, AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) { - std::string filename = picker.getFirstFile(); + std::string filename = filepicker->getFilename(); LLUICtrlFactory::getInstance()->saveToXML(frontmost, filename); } } +static void handle_load_from_xml_continued(AIFilePicker* filepicker); void handle_load_from_xml(void*) { - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getOpenFile(LLFilePicker::FFLOAD_XML)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_XML); + filepicker->run(boost::bind(&handle_load_from_xml_continued, filepicker)); +} + +static void handle_load_from_xml_continued(AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) { - std::string filename = picker.getFirstFile(); + std::string filename = filepicker->getFilename(); LLFloater* floater = new LLFloater("sample_floater"); LLUICtrlFactory::getInstance()->buildFloater(floater, filename); } diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 7e276e51f..a8d78cd8d 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -41,7 +41,7 @@ #include "llimagepng.h" #include "llimagebmp.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llfloateranimpreview.h" #include "llfloaterbuycurrency.h" @@ -125,26 +125,26 @@ static std::string SLOBJECT_EXTENSIONS = "slobject"; #endif static std::string ALL_FILE_EXTENSIONS = "*.*"; -std::string build_extensions_string(LLFilePicker::ELoadFilter filter) +std::string build_extensions_string(ELoadFilter filter) { switch(filter) { #if LL_WINDOWS - case LLFilePicker::FFLOAD_IMAGE: + case FFLOAD_IMAGE: return IMAGE_EXTENSIONS; - case LLFilePicker::FFLOAD_WAV: + case FFLOAD_WAV: return SOUND_EXTENSIONS; - case LLFilePicker::FFLOAD_ANIM: + case FFLOAD_ANIM: return ANIM_EXTENSIONS; - case LLFilePicker::FFLOAD_SLOBJECT: + case FFLOAD_SLOBJECT: return SLOBJECT_EXTENSIONS; #ifdef _CORY_TESTING - case LLFilePicker::FFLOAD_GEOMETRY: + case FFLOAD_GEOMETRY: return GEOMETRY_EXTENSIONS; #endif - case LLFilePicker::FFLOAD_XML: + case FFLOAD_XML: return XML_EXTENSIONS; - case LLFilePicker::FFLOAD_ALL: + case FFLOAD_ALL: return ALL_FILE_EXTENSIONS; #endif default: @@ -152,48 +152,51 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter) } } -/** - char* upload_pick(void* data) +class AIFileUpload { + protected: + AIFilePicker* mPicker; - If applicable, brings up a file chooser in which the user selects a file - to upload for a particular task. If the file is valid for the given action, - returns the string to the full path filename, else returns NULL. - Data is the load filter for the type of file as defined in LLFilePicker. + public: + AIFileUpload(void) : mPicker(NULL) { } + virtual ~AIFileUpload() { llassert(!mPicker); if (mPicker) { mPicker->abort(); mPicker = NULL; } } - Eventually I'd really like to have a built-in browser that gave you all - valid filetypes, default permissions, "Temp when available", and a single - upload button. Maybe let it show the contents of multiple folders. The main - purpose of this features is to deal with the problem of SL just up and - disconnecting if you take more than like 30 seconds to look for a file. -HgB -**/ -const std::string upload_pick(void* data) + public: + bool is_valid(std::string const& filename, ELoadFilter type); + void filepicker_callback(ELoadFilter type); + void start_filepicker(ELoadFilter type, char const* context); + + protected: + virtual void handle_event(std::string const& filename) = 0; +}; + +void AIFileUpload::start_filepicker(ELoadFilter filter, char const* context) { - if( gAgent.cameraMouselook() ) + if( gAgent.cameraMouselook() ) { gAgent.changeCameraToDefault(); // This doesn't seem necessary. JC // display(); } - LLFilePicker::ELoadFilter type; - if(data) - { - type = (LLFilePicker::ELoadFilter)((intptr_t)data); - } - else - { - type = LLFilePicker::FFLOAD_ALL; - } + llassert(!mPicker); + mPicker = new AIFilePicker; + mPicker->open(filter, "", context); + mPicker->run(boost::bind(&AIFileUpload::filepicker_callback, this, filter)); +} - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(type)) +void AIFileUpload::filepicker_callback(ELoadFilter type) +{ + if (mPicker->hasFilename()) { - llinfos << "Couldn't import objects from file" << llendl; - return std::string(); + std::string filename = mPicker->getFilename(); + if (is_valid(filename, type)) + handle_event(filename); } + mPicker = NULL; +} - - const std::string& filename = picker.getFirstFile(); +bool AIFileUpload::is_valid(std::string const& filename, ELoadFilter type) +{ std::string ext = gDirUtilp->getExtension(filename); //strincmp doesn't like NULL pointers @@ -205,7 +208,7 @@ const std::string upload_pick(void* data) LLSD args; args["FILE"] = short_name; LLNotifications::instance().add("NoFileExtension", args); - return std::string(); + return false; } else { @@ -248,7 +251,7 @@ const std::string upload_pick(void* data) args["EXTENSION"] = ext; args["VALIDS"] = valid_extensions; LLNotifications::instance().add("InvalidFileExtension", args); - return NULL; + return false; } }//end else (non-null extension) @@ -257,7 +260,7 @@ const std::string upload_pick(void* data) //now we check to see //if the file is actually a valid image/sound/etc. //Consider completely disabling this, see how SL handles it. Maybe we can get full song uploads again! -HgB - if (type == LLFilePicker::FFLOAD_WAV) + if (type == FFLOAD_WAV) { // pre-qualify wavs to make sure the format is acceptable std::string error_msg; @@ -267,103 +270,68 @@ const std::string upload_pick(void* data) LLSD args; args["FILE"] = filename; LLNotifications::instance().add( error_msg, args ); - return std::string(); + return false; } }//end if a wave/sound file - return filename; + return true; } -class LLFileUploadImage : public view_listener_t +class LLFileUploadImage : public view_listener_t, public AIFileUpload { + public: bool handleEvent(LLPointer event, const LLSD& userdata) { - std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE); - if (!filename.empty()) - { - LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml"); - } - return TRUE; + start_filepicker(FFLOAD_IMAGE, "image"); + return true; + } + + protected: + // Inherited from AIFileUpload. + /*virtual*/ void handle_event(std::string const& filename) + { + LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename); + LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml"); } }; -class LLFileUploadSound : public view_listener_t +class LLFileUploadSound : public view_listener_t, public AIFileUpload { bool handleEvent(LLPointer event, const LLSD& userdata) { - std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV); - if (!filename.empty()) - { - LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_sound_preview.xml"); - floaterp->childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() )); - } + start_filepicker(FFLOAD_WAV, "sound"); return true; } + + protected: + // Inherited from AIFileUpload. + /*virtual*/ void handle_event(std::string const& filename) + { + LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename); + LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_sound_preview.xml"); + floaterp->childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() )); + } }; -class LLFileUploadAnim : public view_listener_t +class LLFileUploadAnim : public view_listener_t, public AIFileUpload { bool handleEvent(LLPointer event, const LLSD& userdata) { - const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM); - if (!filename.empty()) - { - LLFloaterAnimPreview* floaterp = new LLFloaterAnimPreview(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_animation_preview.xml"); - } + start_filepicker(FFLOAD_ANIM, "animations"); return true; } + + protected: + // Inherited from AIFileUpload. + /*virtual*/ void handle_event(std::string const& filename) + { + LLFloaterAnimPreview* floaterp = new LLFloaterAnimPreview(filename); + LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_animation_preview.xml"); + } }; class LLFileUploadBulk : public view_listener_t { - static bool onConfirmBulkUploadTemp(const LLSD& notification, const LLSD& response ) - { - S32 option = LLNotification::getSelectedOption(notification, response); - BOOL enabled; - if(option == 0) // yes - enabled = TRUE; - else if(option == 1) //no - enabled = FALSE; - else //cancel - return false; - - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles()) - { - //const std::string& filename = picker.getFirstFile(); - std::string filename; - while(!(filename = picker.getNextFile()).empty()) - { - std::string name = gDirUtilp->getBaseFileName(filename, true); - - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - void *userdata = NULL; - gSavedSettings.setBOOL("TemporaryUpload",enabled); - upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), - display_name, - callback, expected_upload_cost, userdata); - - } - } - else - { - llinfos << "Couldn't import objects from file" << llendl; - gSavedSettings.setBOOL("TemporaryUpload",FALSE); - } - return false; - } bool handleEvent(LLPointer event, const LLSD& userdata) { if( gAgent.cameraMouselook() ) @@ -388,45 +356,59 @@ class LLFileUploadBulk : public view_listener_t msg.append(llformat("\nWARNING: Each upload costs L$%d if it's not temporary.",expected_upload_cost)); args["MESSAGE"] = msg; LLNotifications::instance().add("GenericAlertYesNoCancel", args, LLSD(), onConfirmBulkUploadTemp); - /* moved to the callback for the above - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles()) - { - // - - //const std::string& filename = picker.getFirstFile(); - std::string filename; - while(!(filename = picker.getNextFile()).empty()) - { - // - std::string name = gDirUtilp->getBaseFileName(filename, true); - - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - void *userdata = NULL; - upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), - display_name, - callback, expected_upload_cost, userdata); + return true; + } + + static bool onConfirmBulkUploadTemp(const LLSD& notification, const LLSD& response ) + { + S32 option = LLNotification::getSelectedOption(notification, response); + bool enabled; + if (option == 0) // yes + enabled = true; + else if(option == 1) // no + enabled = false; + else // cancel + return false; + + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_ALL, "", "openfile", true); + filepicker->run(boost::bind(&LLFileUploadBulk::onConfirmBulkUploadTemp_continued, enabled, filepicker)); + return true; + } + + static void onConfirmBulkUploadTemp_continued(bool enabled, AIFilePicker* filepicker) + { + if (filepicker->hasFilename()) + { + std::vector const& file_names(filepicker->getFilenames()); + for (std::vector::const_iterator iter = file_names.begin(); iter != file_names.end(); ++iter) + { + std::string const& filename(*iter); + if (filename.empty()) + continue; + std::string name = gDirUtilp->getBaseFileName(filename, true); + + std::string asset_name = name; + LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); + LLStringUtil::replaceChar(asset_name, '|', '?'); + LLStringUtil::stripNonprintable(asset_name); + LLStringUtil::trim(asset_name); + + std::string display_name = LLStringUtil::null; + LLAssetStorage::LLStoreAssetCallback callback = NULL; + S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + void *userdata = NULL; + gSavedSettings.setBOOL("TemporaryUpload", enabled); + upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), + display_name, callback, expected_upload_cost, userdata); - // *NOTE: Ew, we don't iterate over the file list here, - // we handle the next files in upload_done_callback() - // not anymore! } } else { - llinfos << "Couldn't import objects from file" << llendl; + gSavedSettings.setBOOL("TemporaryUpload", FALSE); } - */ - return true; } }; @@ -601,44 +583,39 @@ class LLFileQuit : public view_listener_t } }; -void handle_upload(void* data) -{ - const std::string filename = upload_pick(data); - if (!filename.empty()) - { - LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_name_description.xml"); - floaterp->childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() )); - } -} - +static void handle_compress_image_continued(AIFilePicker* filepicker); void handle_compress_image(void*) { - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_IMAGE, "", "openfile", true); + filepicker->run(boost::bind(&handle_compress_image_continued, filepicker)); +} + +static void handle_compress_image_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; + + std::vector const& filenames(filepicker->getFilenames()); + for(std::vector::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { - std::string infile = picker.getFirstFile(); - while (!infile.empty()) + std::string const& infile(*filename); + std::string outfile = infile + ".j2c"; + + llinfos << "Input: " << infile << llendl; + llinfos << "Output: " << outfile << llendl; + + BOOL success; + + success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); + + if (success) { - std::string outfile = infile + ".j2c"; - - llinfos << "Input: " << infile << llendl; - llinfos << "Output: " << outfile << llendl; - - BOOL success; - - success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); - - if (success) - { - llinfos << "Compression complete" << llendl; - } - else - { - llinfos << "Compression failed: " << LLImage::getLastError() << llendl; - } - - infile = picker.getNextFile(); + llinfos << "Compression complete" << llendl; + } + else + { + llinfos << "Compression failed: " << LLImage::getLastError() << llendl; } } } @@ -1137,32 +1114,6 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt LLUploadDialog::modalUploadFinished(); delete data; - - // *NOTE: This is a pretty big hack. What this does is check the - // file picker if there are any more pending uploads. If so, - // upload that file. - /* Agreed, let's not use it. -HgB - const std::string& next_file = LLFilePicker::instance().getNextFile(); - if(is_balance_sufficient && !next_file.empty()) - { - std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - void *userdata = NULL; - upload_new_resource(next_file, asset_name, asset_name, // file - 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, - PERM_NONE, PERM_NONE, PERM_NONE, - display_name, - callback, - expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost - userdata); - } - */ } void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_type, diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 0e03429e9..c92e82da3 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -78,6 +78,4 @@ void upload_new_resource(const LLTransactionID &tid, S32 expected_upload_cost, void *userdata); -const std::string upload_pick(void* data); - #endif diff --git a/indra/newview/llviewerobjectbackup.cpp b/indra/newview/llviewerobjectbackup.cpp index c944780af..51d0a4336 100644 --- a/indra/newview/llviewerobjectbackup.cpp +++ b/indra/newview/llviewerobjectbackup.cpp @@ -56,7 +56,7 @@ #include "llagent.h" #include "llappviewer.h" #include "llassetuploadresponders.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llfloateranimpreview.h" #include "llfloaterbuycurrency.h" #include "llfloaterimagepreview.h" @@ -341,14 +341,20 @@ void LLObjectBackup::exportObject() mThisGroup.clear(); // Open the file save dialog - LLFilePicker& file_picker = LLFilePicker::instance(); - if (!file_picker.getSaveFile(LLFilePicker::FFSAVE_XML)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("", FFSAVE_XML); + filepicker->run(boost::bind(&LLObjectBackup::exportObject_continued, this, filepicker)); +} + +void LLObjectBackup::exportObject_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) { // User canceled save. return; } - mFileName = file_picker.getCurFile(); + mFileName = filepicker->getFilename(); mFolder = gDirUtilp->getDirName(mFileName); mNonExportedTextures = TEXTURE_OK; @@ -733,14 +739,19 @@ void LLObjectBackup::importObject(bool upload) mRetexture = upload; // Open the file open dialog - LLFilePicker& file_picker = LLFilePicker::instance(); - if (!file_picker.getOpenFile(LLFilePicker::FFLOAD_XML)) - { - // User canceled save. - return; - } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_XML, "", "import"); + filepicker->run(boost::bind(&LLObjectBackup::importObject_continued, this, filepicker)); - std::string file_name = file_picker.getFirstFile().c_str(); + return; +} + +void LLObjectBackup::importObject_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; + + std::string file_name = filepicker->getFilename(); mFolder = gDirUtilp->getDirName(file_name); llifstream import_file(file_name); LLSDSerialize::fromXML(mLLSD, import_file); @@ -762,7 +773,7 @@ void LLObjectBackup::importObject(bool upload) if (mObjects <= 0) { LLSD args; - args["MESSAGE"] = std::string("Object import failed.\nThe XML file has an incompatble format or does not contain any objects."); + args["MESSAGE"] = std::string("Object import failed.\nThe XML file has an incompatible format or does not contain any objects."); LLNotifications::instance().add("GenericAlert", args); llwarns << "Trying to import illegal XML object file." << llendl; return; diff --git a/indra/newview/llviewerobjectbackup.h b/indra/newview/llviewerobjectbackup.h index 46ca5f916..5ae33c382 100644 --- a/indra/newview/llviewerobjectbackup.h +++ b/indra/newview/llviewerobjectbackup.h @@ -56,9 +56,11 @@ public: // Import entry point void importObject(bool upload=FALSE); + void importObject_continued(AIFilePicker* filepicker); // Export entry point void exportObject(); + void exportObject_continued(AIFilePicker* filepicker); // Update map from texture worker void updateMap(LLUUID uploaded_asset); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 2e684633c..2e256db6b 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4015,23 +4015,22 @@ void LLViewerWindow::saveImageNumbered(LLPointer image) { std::string proposed_name( sSnapshotBaseName ); - // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. + // AIFilePicker will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. // pick a directory in which to save - AIFilePicker* filepicker = new AIFilePicker; // Deleted in LLViewerWindow::saveImageNumbered_filepicker_callback + AIFilePicker* filepicker = new AIFilePicker; // Deleted in LLViewerWindow::saveImageNumbered_continued1 filepicker->open(proposed_name, pick_type, "", "snapshot"); - filepicker->run(boost::bind(&LLViewerWindow::saveImageNumbered_filepicker_callback, this, image, extension, filepicker, _1)); + filepicker->run(boost::bind(&LLViewerWindow::saveImageNumbered_continued1, this, image, extension, filepicker)); return; } - // LLViewerWindow::sSnapshotBaseName and LLViewerWindow::sSnapshotDir already known. Go straight to saveImageNumbered_continued. - saveImageNumbered_continued(image, extension); + // LLViewerWindow::sSnapshotBaseName and LLViewerWindow::sSnapshotDir already known. Go straight to saveImageNumbered_continued2. + saveImageNumbered_continued2(image, extension); } -void LLViewerWindow::saveImageNumbered_filepicker_callback(LLPointer image, std::string const& extension, AIFilePicker* filepicker, bool success) +void LLViewerWindow::saveImageNumbered_continued1(LLPointer image, std::string const& extension, AIFilePicker* filepicker) { - llassert((bool)*filepicker == success); - if (success && !filepicker->isCanceled()) + if (filepicker->hasFilename()) { // Copy the directory + file name std::string filepath = filepicker->getFilename(); @@ -4039,12 +4038,11 @@ void LLViewerWindow::saveImageNumbered_filepicker_callback(LLPointergetBaseFileName(filepath, true); LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath); - saveImageNumbered_continued(image, extension); + saveImageNumbered_continued2(image, extension); } - filepicker->deleteMe(); } -void LLViewerWindow::saveImageNumbered_continued(LLPointer image, std::string const& extension) +void LLViewerWindow::saveImageNumbered_continued2(LLPointer image, std::string const& extension) { // Look for an unused file name std::string filepath; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index cbf3f0187..dec5a177c 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -296,8 +296,8 @@ public: BOOL isSnapshotLocSet() const { return ! sSnapshotDir.empty(); } void resetSnapshotLoc() const { sSnapshotDir.clear(); } void saveImageNumbered(LLPointer image); - void saveImageNumbered_filepicker_callback(LLPointer image, std::string const& extension, AIFilePicker* filepicker, bool success); - void saveImageNumbered_continued(LLPointer image, std::string const& extension); + void saveImageNumbered_continued1(LLPointer image, std::string const& extension, AIFilePicker* filepicker); + void saveImageNumbered_continued2(LLPointer image, std::string const& extension); // Reset the directory where snapshots are saved. // Client will open directory picker on next snapshot save. diff --git a/indra/newview/statemachine/aifilepicker.cpp b/indra/newview/statemachine/aifilepicker.cpp index 33ef0c16c..e0588a990 100644 --- a/indra/newview/statemachine/aifilepicker.cpp +++ b/indra/newview/statemachine/aifilepicker.cpp @@ -133,8 +133,14 @@ void AIFilePicker::open(ELoadFilter filter, std::string const& default_path, std case FFLOAD_RAW: mFilter = "raw"; break; - case FFLOAD_TEXT: - mFilter = "text"; + case FFLOAD_INVGZ: + mFilter = "invgz"; + break; + case FFLOAD_AO: + mFilter = "ao"; + break; + case FFLOAD_BLACKLIST: + mFilter = "blacklist"; break; } } @@ -188,15 +194,75 @@ void AIFilePicker::open(std::string const& filename, ESaveFilter filter, std::st case FFSAVE_JPEG: mFilter = "jpeg"; break; - case FFSAVE_HPA: - mFilter = "hpa"; + case FFSAVE_ANIMATN: + mFilter = "animatn"; break; - case FFSAVE_TEXT: - mFilter = "text"; + case FFSAVE_OGG: + mFilter = "ogg"; + break; + case FFSAVE_NOTECARD: + mFilter = "notecard"; + break; + case FFSAVE_GESTURE: + mFilter = "gesture"; break; case FFSAVE_LSL: mFilter = "lsl"; break; + case FFSAVE_SHAPE: + mFilter = "shape"; + break; + case FFSAVE_SKIN: + mFilter = "skin"; + break; + case FFSAVE_HAIR: + mFilter = "hair"; + break; + case FFSAVE_EYES: + mFilter = "eyes"; + break; + case FFSAVE_SHIRT: + mFilter = "shirt"; + break; + case FFSAVE_PANTS: + mFilter = "pants"; + break; + case FFSAVE_SHOES: + mFilter = "shoes"; + break; + case FFSAVE_SOCKS: + mFilter = "socks"; + break; + case FFSAVE_JACKET: + mFilter = "jacket"; + break; + case FFSAVE_GLOVES: + mFilter = "gloves"; + break; + case FFSAVE_UNDERSHIRT: + mFilter = "undershirt"; + break; + case FFSAVE_UNDERPANTS: + mFilter = "underpants"; + break; + case FFSAVE_SKIRT: + mFilter = "skirt"; + break; + case FFSAVE_INVGZ: + mFilter = "invgz"; + break; + case FFSAVE_LANDMARK: + mFilter = "landmark"; + break; + case FFSAVE_AO: + mFilter = "ao"; + break; + case FFSAVE_BLACKLIST: + mFilter = "blacklist"; + break; + case FFSAVE_PHYSICS: + mFilter = "physics"; + break; } } @@ -320,6 +386,9 @@ void AIFilePicker::finish_impl(void) mPluginManager = NULL; } mFilter.clear(); // Check that open is called before calling run (again). + // The default behavior is to delete the plugin. This can be overridden in + // the callback by calling run() again. + deleteMe(); } // This function is called when a new message is received from the plugin. diff --git a/indra/newview/statemachine/aifilepicker.h b/indra/newview/statemachine/aifilepicker.h index b1caf4701..d916055fe 100644 --- a/indra/newview/statemachine/aifilepicker.h +++ b/indra/newview/statemachine/aifilepicker.h @@ -45,7 +45,9 @@ enum ELoadFilter FFLOAD_XML, FFLOAD_SLOBJECT, FFLOAD_RAW, - FFLOAD_TEXT + FFLOAD_INVGZ, + FFLOAD_AO, + FFLOAD_BLACKLIST }; enum ESaveFilter @@ -62,9 +64,29 @@ enum ESaveFilter FFSAVE_J2C, FFSAVE_PNG, FFSAVE_JPEG, - FFSAVE_HPA, - FFSAVE_TEXT, - FFSAVE_LSL + FFSAVE_ANIMATN, + FFSAVE_OGG, + FFSAVE_NOTECARD, + FFSAVE_GESTURE, + FFSAVE_LSL, + FFSAVE_SHAPE, + FFSAVE_SKIN, + FFSAVE_HAIR, + FFSAVE_EYES, + FFSAVE_SHIRT, + FFSAVE_PANTS, + FFSAVE_SHOES, + FFSAVE_SOCKS, + FFSAVE_JACKET, + FFSAVE_GLOVES, + FFSAVE_UNDERSHIRT, + FFSAVE_UNDERPANTS, + FFSAVE_SKIRT, + FFSAVE_INVGZ, + FFSAVE_LANDMARK, + FFSAVE_AO, + FFSAVE_BLACKLIST, + FFSAVE_PHYSICS }; /* @@ -108,12 +130,9 @@ new AIFilePicker Termination happens by receiving the "canceled" or "done" message, which sets the state to AIFilePicker_canceled or AIFilePicker_done respectively, causing a call to AIStateMachine::finish(), which calls - AIFilePicker::finish_impl which destroys the plugin (mPluginBase) - and the plugin manager (mPluginManager). - - AIStateMachine::finish() also calls the registered callback function, - which should call AIStateMachine::deleteMe(), causing the AIFilePicker - to be deleted. + AIFilePicker::finish_impl which destroys the plugin (mPluginBase), + the plugin manager (mPluginManager) and calls AIStateMachine::deleteMe() + causing the AIFilePicker to be deleted. */ @@ -140,6 +159,7 @@ public: void open(ELoadFilter filter = FFLOAD_ALL, std::string const& default_path = "", std::string const& context = "openfile", bool multiple = false); bool isCanceled(void) const { return mCanceled; } + bool hasFilename(void) const { return *this && !mCanceled; } std::string const& getFilename(void) const; std::string getFolder(void) const; std::vector const& getFilenames(void) const { return mFilenames; } @@ -175,7 +195,7 @@ private: std::string get_folder(std::string const& default_path, std::string const& context); protected: - // Call deleteMe(), not delete. + // Call finish() (or abort()), not delete. /*virtual*/ ~AIFilePicker() { LL_DEBUGS("Plugin") << "Calling AIFilePicker::~AIFilePicker()" << LL_ENDL; } // Handle initializing the object. diff --git a/indra/newview/statemachine/aistatemachine.cpp b/indra/newview/statemachine/aistatemachine.cpp index ca1b5c61e..ce1a4149e 100644 --- a/indra/newview/statemachine/aistatemachine.cpp +++ b/indra/newview/statemachine/aistatemachine.cpp @@ -168,8 +168,16 @@ void AIStateMachine::finish(void) { DoutEntering(dc::statemachine, "AIStateMachine::finish() [" << (void*)this << "]"); llassert(mState == bs_run || mState == bs_abort); + // It is possible that mIdle is false when abort or finish was called from + // outside multiplex_impl. However, that only may be done by the main thread. + llassert(!mIdle || is_main_thread()); + if (!mIdle) + idle(); mState = bs_finish; finish_impl(); + // Did finish_impl call deleteMe? Then that is only the default. Remember it. + bool default_delete = (mState == bs_deleted); + mState = bs_finish; if (mParent) { // It is possible that the parent is not running when the parent is in fact aborting and called @@ -190,22 +198,21 @@ void AIStateMachine::finish(void) } // Set this already to bs_initialize now, so that (bool)*this evaluates to true. mState = bs_initialize; - // It is possible that mIdle is false when abort or finish was called from - // outside multiplex_impl. However, that only may be done by the main thread. - llassert(!mIdle || is_main_thread()); - if (!mIdle) - idle(); if (mCallback) { mCallback->callback(!mAborted); // This can/may call deleteMe(), in which case the whole AIStateMachine will be deleted from the mainloop. delete mCallback; mCallback = NULL; } + // Restore the request for deletion if we weren't started again from the callback. + if (default_delete && mState == bs_initialize) + mState = bs_deleted; } void AIStateMachine::deleteMe(void) { - llassert(mIdle && mState == bs_initialize); + // Should only be called from finish(). + llassert(mIdle && (mState == bs_initialize || mState == bs_finish)); mState = bs_deleted; } diff --git a/indra/plugins/filepicker/basic_plugin_filepicker.cpp b/indra/plugins/filepicker/basic_plugin_filepicker.cpp index b30131479..b954e27b4 100644 --- a/indra/plugins/filepicker/basic_plugin_filepicker.cpp +++ b/indra/plugins/filepicker/basic_plugin_filepicker.cpp @@ -87,12 +87,52 @@ static LLFilePicker::ESaveFilter str2savefilter(std::string const& filter) return LLFilePicker::FFSAVE_PNG; else if (filter == "jpeg") return LLFilePicker::FFSAVE_JPEG; - else if (filter == "hpa") - return LLFilePicker::FFSAVE_HPA; - else if (filter == "text") - return LLFilePicker::FFSAVE_TEXT; + else if (filter == "animatn") + return LLFilePicker::FFSAVE_ANIMATN; + else if (filter == "ogg") + return LLFilePicker::FFSAVE_OGG; + else if (filter == "notecard") + return LLFilePicker::FFSAVE_NOTECARD; + else if (filter == "gesture") + return LLFilePicker::FFSAVE_GESTURE; else if (filter == "lsl") return LLFilePicker::FFSAVE_LSL; + else if (filter == "shape") + return LLFilePicker::FFSAVE_SHAPE; + else if (filter == "skin") + return LLFilePicker::FFSAVE_SKIN; + else if (filter == "hair") + return LLFilePicker::FFSAVE_HAIR; + else if (filter == "eyes") + return LLFilePicker::FFSAVE_EYES; + else if (filter == "shirt") + return LLFilePicker::FFSAVE_SHIRT; + else if (filter == "pants") + return LLFilePicker::FFSAVE_PANTS; + else if (filter == "shoes") + return LLFilePicker::FFSAVE_SHOES; + else if (filter == "socks") + return LLFilePicker::FFSAVE_SOCKS; + else if (filter == "jacket") + return LLFilePicker::FFSAVE_JACKET; + else if (filter == "gloves") + return LLFilePicker::FFSAVE_GLOVES; + else if (filter == "undershirt") + return LLFilePicker::FFSAVE_UNDERSHIRT; + else if (filter == "underpants") + return LLFilePicker::FFSAVE_UNDERPANTS; + else if (filter == "skirt") + return LLFilePicker::FFSAVE_SKIRT; + else if (filter == "invgz") + return LLFilePicker::FFSAVE_INVGZ; + else if (filter == "landmark") + return LLFilePicker::FFSAVE_LANDMARK; + else if (filter == "ao") + return LLFilePicker::FFSAVE_AO; + else if (filter == "blacklist") + return LLFilePicker::FFSAVE_BLACKLIST; + else if (filter == "physics") + return LLFilePicker::FFSAVE_PHYSICS; else return LLFilePicker::FFSAVE_ALL; } @@ -116,8 +156,12 @@ static LLFilePicker::ELoadFilter str2loadfilter(std::string const& filter) return LLFilePicker::FFLOAD_SLOBJECT; else if (filter == "raw") return LLFilePicker::FFLOAD_RAW; - else if (filter == "text") - return LLFilePicker::FFLOAD_TEXT; + else if (filter == "invgz") + return LLFilePicker::FFLOAD_INVGZ; + else if (filter == "ao") + return LLFilePicker::FFLOAD_AO; + else if (filter == "blacklist") + return LLFilePicker::FFLOAD_BLACKLIST; else return LLFilePicker::FFLOAD_ALL; } diff --git a/indra/plugins/filepicker/llfilepicker.cpp b/indra/plugins/filepicker/llfilepicker.cpp index b9c616195..8028665e3 100644 --- a/indra/plugins/filepicker/llfilepicker.cpp +++ b/indra/plugins/filepicker/llfilepicker.cpp @@ -129,8 +129,13 @@ namespace LLWindowSDL { LLFilePicker LLFilePicker::sInstance; #if LL_WINDOWS -#define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0" -#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" +// +#define SOUND_FILTER L"Sounds (*.wav; *.ogg)\0*.wav;*.ogg\0" +#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png; *.jp2; *.j2k; *.j2c)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png;*.jp2;*.j2k;*.j2c\0" +#define INVGZ_FILTER L"Inv cache (*.inv; *.inv.gz)\0*.inv;*.inv.gz\0" +#define AO_FILTER L"Animation Override (*.ao)\0*.ao\0" +#define BLACKLIST_FILTER L"Asset Blacklist (*.blacklist)\0*.blacklist\0" +// #define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0" #ifdef _CORY_TESTING #define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" @@ -264,6 +269,20 @@ bool LLFilePickerBase::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = RAW_FILTER \ L"\0"; break; + // + case FFLOAD_INVGZ: + mOFN.lpstrFilter = INVGZ_FILTER \ + L"\0"; + break; + case FFLOAD_AO: + mOFN.lpstrFilter = AO_FILTER \ + L"\0"; + break; + case FFLOAD_BLACKLIST: + mOFN.lpstrFilter = BLACKLIST_FILTER \ + L"\0"; + break; + // default: res = FALSE; break; @@ -401,28 +420,6 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \ L"\0"; break; - case FFSAVE_LSL: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"lsl"; - mOFN.lpstrFilter = - L"LSL Files (*.lsl)\0*.lsl\0" - L"Text files (*.txt)\0*.txt\0" - L"\0"; - break; - case FFSAVE_TEXT: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.txt", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"txt"; - mOFN.lpstrFilter = - L"Text files (*.txt)\0*.txt\0" - L"RTF Files (*.rtf)\0*.rtf\0" - L"\0"; - break; case FFSAVE_WAV: if (filename.empty()) { @@ -466,11 +463,11 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena case FFSAVE_JPEG: if (filename.empty()) { - wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + wcsncpy( mFilesW,L"untitled.jpg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ } - mOFN.lpstrDefExt = L"jpeg"; + mOFN.lpstrDefExt = L"jpg"; mOFN.lpstrFilter = - L"JPEG Images (*.jpeg)\0*.jpeg\0" \ + L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ L"\0"; break; case FFSAVE_AVI: @@ -545,10 +542,241 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena L"Compressed Images (*.j2c)\0*.j2c\0" \ L"\0"; break; + // + case FFSAVE_ANIMATN: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.animatn", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"animatn"; + mOFN.lpstrFilter = + L"SL Animations (*.animatn)\0*.animatn\0" \ + L"\0"; + break; + case FFSAVE_OGG: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.ogg", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"ogg"; + mOFN.lpstrFilter = + L"Ogg (*.ogg)\0*.ogg\0" \ + L"\0"; + break; + case FFSAVE_NOTECARD: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.notecard", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"notecard"; + mOFN.lpstrFilter = + L"Notecards (*.notecard)\0*.notecard\0" \ + L"\0"; + break; + case FFSAVE_GESTURE: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.gesture", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"gesture"; + mOFN.lpstrFilter = + L"Gestures (*.gesture)\0*.gesture\0" \ + L"\0"; + break; + case FFSAVE_LSL: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"lsl"; + mOFN.lpstrFilter = + L"LSL (*.lsl)\0*.lsl\0" \ + L"\0"; + break; + case FFSAVE_SHAPE: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.shape", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"shape"; + mOFN.lpstrFilter = + L"Shapes (*.shape)\0*.shape\0" \ + L"\0"; + break; + case FFSAVE_SKIN: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.skin", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"skin"; + mOFN.lpstrFilter = + L"Skins (*.skin)\0*.skin\0" \ + L"\0"; + break; + case FFSAVE_HAIR: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.hair", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"hair"; + mOFN.lpstrFilter = + L"Hair (*.hair)\0*.hair\0" \ + L"\0"; + break; + case FFSAVE_EYES: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.eyes", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"eyes"; + mOFN.lpstrFilter = + L"Eyes (*.eyes)\0*.eyes\0" \ + L"\0"; + break; + case FFSAVE_SHIRT: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.shirt", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"shirt"; + mOFN.lpstrFilter = + L"Shirts (*.shirt)\0*.shirt\0" \ + L"\0"; + break; + case FFSAVE_PANTS: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.pants", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"pants"; + mOFN.lpstrFilter = + L"Pants (*.pants)\0*.pants\0" \ + L"\0"; + break; + case FFSAVE_SHOES: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.shoes", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"shoes"; + mOFN.lpstrFilter = + L"Shoes (*.shoes)\0*.shoes\0" \ + L"\0"; + break; + case FFSAVE_SOCKS: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.socks", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"socks"; + mOFN.lpstrFilter = + L"Socks (*.socks)\0*.socks\0" \ + L"\0"; + break; + case FFSAVE_JACKET: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.jacket", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"jacket"; + mOFN.lpstrFilter = + L"Jackets (*.jacket)\0*.jacket\0" \ + L"\0"; + break; + case FFSAVE_GLOVES: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.gloves", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"gloves"; + mOFN.lpstrFilter = + L"Gloves (*.gloves)\0*.gloves\0" \ + L"\0"; + break; + case FFSAVE_UNDERSHIRT: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.undershirt", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"undershirt"; + mOFN.lpstrFilter = + L"Undershirts (*.undershirt)\0*.undershirt\0" \ + L"\0"; + break; + case FFSAVE_UNDERPANTS: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.underpants", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"underpants"; + mOFN.lpstrFilter = + L"Underpants (*.underpants)\0*.underpants\0" \ + L"\0"; + break; + case FFSAVE_SKIRT: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.skirt", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"skirt"; + mOFN.lpstrFilter = + L"Skirts (*.skirt)\0*.skirt\0" \ + L"\0"; + break; + case FFSAVE_LANDMARK: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.landmark", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"landmark"; + mOFN.lpstrFilter = + L"Landmarks (*.landmark)\0*.landmark\0" \ + L"\0"; + break; + case FFSAVE_AO: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.ao", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"ao"; + mOFN.lpstrFilter = + L"Animation overrides (*.ao)\0*.ao\0" \ + L"\0"; + break; + case FFSAVE_INVGZ: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.inv", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L".inv"; + mOFN.lpstrFilter = + L"InvCache (*.inv)\0*.inv\0" \ + L"\0"; + break; + case FFSAVE_BLACKLIST: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.blacklist", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L".blacklist"; + mOFN.lpstrFilter = + L"Asset Blacklists (*.blacklist)\0*.blacklist\0" \ + L"\0"; + break; + case FFSAVE_PHYSICS: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.phy", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"phy"; + mOFN.lpstrFilter = + L"Landmarks (*.phy)\0*.phy\0" \ + L"\0"; + break; + // default: return FALSE; } - mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; @@ -604,16 +832,12 @@ Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *c { if (fileInfo.filetype != 'JPEG' && fileInfo.filetype != 'JPG ' && fileInfo.filetype != 'BMP ' && fileInfo.filetype != 'TGA ' && - fileInfo.filetype != 'TIFF' && fileInfo.filetype != 'PSD ' && fileInfo.filetype != 'BMPf' && fileInfo.filetype != 'TPIC' && fileInfo.filetype != 'PNG ' && (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("jpeg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("jpg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("bmp"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("tga"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && - CFStringCompare(fileInfo.extension, CFSTR("psd"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && - CFStringCompare(fileInfo.extension, CFSTR("tiff"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && - CFStringCompare(fileInfo.extension, CFSTR("tif"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("png"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) ) { @@ -639,6 +863,15 @@ Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *c result = false; } } + else if (filter == FFLOAD_XML) + { + if (fileInfo.filetype != 'XML' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("xml"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + ) + { + result = false; + } + } #ifdef _CORY_TESTING else if (filter == FFLOAD_GEOMETRY) { @@ -1158,13 +1391,8 @@ static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) { - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.wav"); - gtk_file_filter_add_mime_type(gfilter,"audio/x-wav");//not working - - std::string filtername = LLTrans::getString("sound_files") + " (*.wav)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; + return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", + LLTrans::getString("sound_files") + " (*.wav)"); } static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker) @@ -1173,6 +1401,12 @@ static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker) LLTrans::getString("animation_files") + " (*.bvh)"); } +static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) +{ + return add_simple_mime_filter_to_gtkchooser(picker, "text/xml", + LLTrans::getString("xml_file") + " (*.xml)"); +} + static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { GtkFileFilter *gfilter = gtk_file_filter_new(); @@ -1300,6 +1534,9 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder case FFLOAD_IMAGE: filtername = add_imageload_filter_to_gtkchooser(picker); break; + case FFLOAD_XML: + filtername = add_xml_filter_to_gtkchooser(picker); + break; default:; break; } @@ -1376,6 +1613,7 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder case FFLOAD_WAV: filename += ".wav"; break; case FFLOAD_IMAGE: filename += ".tga"; break; case FFLOAD_ANIM: filename += ".bvh"; break; + case FFLOAD_XML: filename += ".xml"; break; default: break; } mFiles.push_back(filename); diff --git a/indra/plugins/filepicker/llfilepicker.h b/indra/plugins/filepicker/llfilepicker.h index d14612112..4e1a52a7e 100644 --- a/indra/plugins/filepicker/llfilepicker.h +++ b/indra/plugins/filepicker/llfilepicker.h @@ -88,7 +88,11 @@ public: FFLOAD_XML = 6, FFLOAD_SLOBJECT = 7, FFLOAD_RAW = 8, - FFLOAD_TEXT = 9, + // + FFLOAD_INVGZ = 9, + FFLOAD_AO = 10, + FFLOAD_BLACKLIST = 11 + // }; enum ESaveFilter @@ -108,9 +112,32 @@ public: FFSAVE_J2C = 12, FFSAVE_PNG = 13, FFSAVE_JPEG = 14, - FFSAVE_HPA = 15, - FFSAVE_TEXT = 16, - FFSAVE_LSL = 17 + // + FFSAVE_ANIMATN = 15, + FFSAVE_OGG = 16, + FFSAVE_NOTECARD = 17, + FFSAVE_GESTURE = 18, + FFSAVE_LSL = 19, + // good grief + FFSAVE_SHAPE = 20, + FFSAVE_SKIN = 21, + FFSAVE_HAIR = 22, + FFSAVE_EYES = 23, + FFSAVE_SHIRT = 24, + FFSAVE_PANTS = 25, + FFSAVE_SHOES = 26, + FFSAVE_SOCKS = 27, + FFSAVE_JACKET = 28, + FFSAVE_GLOVES = 29, + FFSAVE_UNDERSHIRT = 30, + FFSAVE_UNDERPANTS = 31, + FFSAVE_SKIRT = 32, + FFSAVE_INVGZ = 33, + FFSAVE_LANDMARK = 34, + FFSAVE_AO = 35, + FFSAVE_BLACKLIST = 36, + FFSAVE_PHYSICS = 37, + // }; // open the dialog. This is a modal operation @@ -164,13 +191,9 @@ private: #if LL_DARWIN NavDialogCreationOptions mNavOptions; - std::vector mFileVector; - UInt32 mFileIndex; OSStatus doNavChooseDialog(ELoadFilter filter); OSStatus doNavSaveDialog(ESaveFilter filter, const std::string& filename); - void getFilePath(SInt32 index); - void getFileName(SInt32 index); static Boolean navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode); #endif // LL_DARWIN From a6cb676d4a07bfdd449ddf2d13c81bf2cc7aa73c Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 11 May 2011 03:01:34 +0200 Subject: [PATCH 13/87] Add AIDirPicker and use it. Remove indra/newview/ll{dir,file}picker.{h,cpp}. Also removed some code from the Mac/windows code in indra/plugins/filepicker/llfilepicker.cpp that shouldn't be in there anymore (send_agent_pause/resume and updating the LLFrameTimer stuff). --- indra/newview/CMakeLists.txt | 5 +- indra/newview/llassetuploadresponders.cpp | 7 +- indra/newview/llfilepicker.cpp | 1587 ----------------- indra/newview/llfilepicker.h | 230 --- indra/newview/llfloaterreporter.cpp | 1 - indra/newview/llfloatervfsexplorer.cpp | 1 - indra/newview/llinventorybackup.cpp | 27 +- indra/newview/llinventorybackup.h | 3 + indra/newview/llpanelnetwork.cpp | 18 +- indra/newview/llpanelnetwork.h | 3 + indra/newview/llprefsim.cpp | 18 +- indra/newview/lltexturectrl.cpp | 1 - indra/newview/llviewermenu.h | 3 - indra/newview/llviewermenufile.cpp | 4 +- indra/newview/llviewermessage.cpp | 1 - indra/newview/statemachine/aidirpicker.h | 77 + indra/newview/statemachine/aifilepicker.cpp | 6 +- indra/newview/statemachine/aifilepicker.h | 3 +- indra/plugins/filepicker/CMakeLists.txt | 6 +- .../filepicker/basic_plugin_filepicker.cpp | 19 +- indra/plugins/filepicker/legacy.cpp | 112 ++ indra/plugins/filepicker/legacy.h | 79 + .../filepicker}/lldirpicker.cpp | 26 +- .../filepicker}/lldirpicker.h | 0 indra/plugins/filepicker/llfilepicker.cpp | 132 +- indra/plugins/filepicker/llfilepicker.h | 36 +- 26 files changed, 364 insertions(+), 2041 deletions(-) delete mode 100644 indra/newview/llfilepicker.cpp delete mode 100644 indra/newview/llfilepicker.h create mode 100644 indra/newview/statemachine/aidirpicker.h create mode 100644 indra/plugins/filepicker/legacy.cpp create mode 100644 indra/plugins/filepicker/legacy.h rename indra/{newview => plugins/filepicker}/lldirpicker.cpp (92%) rename indra/{newview => plugins/filepicker}/lldirpicker.h (100%) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3599a1d3d..340989a05 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -132,7 +132,6 @@ set(viewer_SOURCE_FILES lldebugmessagebox.cpp lldebugview.cpp lldelayedgestureerror.cpp - lldirpicker.cpp lldrawable.cpp lldrawpoolalpha.cpp lldrawpoolavatar.cpp @@ -154,7 +153,6 @@ set(viewer_SOURCE_FILES llface.cpp llfasttimerview.cpp llfeaturemanager.cpp - llfilepicker.cpp llfirstuse.cpp llflexibleobject.cpp llfloaterabout.cpp @@ -609,7 +607,6 @@ set(viewer_HEADER_FILES lldebugmessagebox.h lldebugview.h lldelayedgestureerror.h - lldirpicker.h lldrawable.h lldrawpool.h lldrawpoolalpha.h @@ -632,7 +629,6 @@ set(viewer_HEADER_FILES llface.h llfasttimerview.h llfeaturemanager.h - llfilepicker.h llfirstuse.h llflexibleobject.h llfloaterabout.h @@ -1017,6 +1013,7 @@ set(statemachine_SOURCE_FILES set(statemachine_HEADER_FILES statemachine/aistatemachine.h statemachine/aifilepicker.h + statemachine/aidirpicker.h ) list(APPEND viewer_SOURCE_FILES ${statemachine_SOURCE_FILES}) list(APPEND viewer_HEADER_FILES ${statemachine_HEADER_FILES}) diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 2992e60bd..d910ab4b2 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -38,7 +38,6 @@ #include "llagent.h" #include "llcompilequeue.h" #include "llfloaterbuycurrency.h" -#include "llfilepicker.h" #include "llnotify.h" #include "llinventorymodel.h" #include "llinventoryview.h" @@ -129,7 +128,7 @@ void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason) break; } LLUploadDialog::modalUploadFinished(); - LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails + //AIFIXME? LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails } //virtual @@ -293,7 +292,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) view->getPanel()->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO); if((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type) - /* FIXME: && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD */) + /* AIFIXME: && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD */) { view->getPanel()->openSelected(); } @@ -310,7 +309,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) // remove the "Uploading..." message LLUploadDialog::modalUploadFinished(); -#if 0 // FIXME: This needs to be done in some other way. +#if 0 // AIFIXME: This needs to be done in some other way. // *FIX: This is a pretty big hack. What this does is check the // file picker if there are any more pending uploads. If so, // upload that file. diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp deleted file mode 100644 index 2a325c0bb..000000000 --- a/indra/newview/llfilepicker.cpp +++ /dev/null @@ -1,1587 +0,0 @@ -/** - * @file llfilepicker.cpp - * @brief OS-specific file picker - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-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 "llviewerprecompiledheaders.h" - -#include "llfilepicker.h" -#include "llworld.h" -#include "llviewerwindow.h" -#include "llkeyboard.h" -#include "lldir.h" -#include "llframetimer.h" -#include "lltrans.h" - -#if LL_SDL -#include "llwindowsdl.h" // for some X/GTK utils to help with filepickers -#endif // LL_SDL - -// -// Globals -// - -LLFilePicker LLFilePicker::sInstance; - -#if LL_WINDOWS -// -#define SOUND_FILTER L"Sounds (*.wav; *.ogg)\0*.wav;*.ogg\0" -#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png; *.jp2; *.j2k; *.j2c)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png;*.jp2;*.j2k;*.j2c\0" -#define INVGZ_FILTER L"Inv cache (*.inv; *.inv.gz)\0*.inv;*.inv.gz\0" -#define AO_FILTER L"Animation Override (*.ao)\0*.ao\0" -#define BLACKLIST_FILTER L"Asset Blacklist (*.blacklist)\0*.blacklist\0" -// -#define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0" -#ifdef _CORY_TESTING -#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" -#endif -#define XML_FILTER L"XML files (*.xml)\0*.xml\0" -#define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0" -#define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" -#endif - -// -// Implementation -// -LLFilePickerBase::LLFilePickerBase() - : mCurrentFile(0), - mLocked(FALSE) - -{ - reset(); - -#if LL_WINDOWS - mOFN.lStructSize = sizeof(OPENFILENAMEW); - mOFN.hwndOwner = NULL; // Set later - mOFN.hInstance = NULL; - mOFN.lpstrCustomFilter = NULL; - mOFN.nMaxCustFilter = 0; - mOFN.lpstrFile = NULL; // set in open and close - mOFN.nMaxFile = LL_MAX_PATH; - mOFN.lpstrFileTitle = NULL; - mOFN.nMaxFileTitle = 0; - mOFN.lpstrInitialDir = NULL; - mOFN.lpstrTitle = NULL; - mOFN.Flags = 0; // set in open and close - mOFN.nFileOffset = 0; - mOFN.nFileExtension = 0; - mOFN.lpstrDefExt = NULL; - mOFN.lCustData = 0L; - mOFN.lpfnHook = NULL; - mOFN.lpTemplateName = NULL; -#endif - -#if LL_DARWIN - memset(&mNavOptions, 0, sizeof(mNavOptions)); - OSStatus error = NavGetDefaultDialogCreationOptions(&mNavOptions); - if (error == noErr) - { - mNavOptions.modality = kWindowModalityAppModal; - } -#endif -} - -const std::string LLFilePickerBase::getFirstFile() -{ - mCurrentFile = 0; - return getNextFile(); -} - -const std::string LLFilePickerBase::getNextFile() -{ - if (mCurrentFile >= getFileCount()) - { - mLocked = FALSE; - return std::string(); - } - else - { - return mFiles[mCurrentFile++]; - } -} - -const std::string LLFilePickerBase::getCurFile() -{ - if (mCurrentFile >= getFileCount()) - { - mLocked = FALSE; - return std::string(); - } - else - { - return mFiles[mCurrentFile]; - } -} - -void LLFilePickerBase::reset() -{ - mLocked = FALSE; - mFiles.clear(); - mCurrentFile = 0; -} - -#if LL_WINDOWS - -BOOL LLFilePickerBase::setupFilter(ELoadFilter filter) -{ - BOOL res = TRUE; - switch (filter) - { - case FFLOAD_ALL: - mOFN.lpstrFilter = L"All Files (*.*)\0*.*\0" \ - SOUND_FILTER \ - IMAGE_FILTER \ - ANIM_FILTER \ - L"\0"; - break; - case FFLOAD_WAV: - mOFN.lpstrFilter = SOUND_FILTER \ - L"\0"; - break; - case FFLOAD_IMAGE: - mOFN.lpstrFilter = IMAGE_FILTER \ - L"\0"; - break; - case FFLOAD_ANIM: - mOFN.lpstrFilter = ANIM_FILTER \ - L"\0"; - break; -#ifdef _CORY_TESTING - case FFLOAD_GEOMETRY: - mOFN.lpstrFilter = GEOMETRY_FILTER \ - L"\0"; - break; -#endif - case FFLOAD_XML: - mOFN.lpstrFilter = XML_FILTER \ - L"\0"; - break; - case FFLOAD_SLOBJECT: - mOFN.lpstrFilter = SLOBJECT_FILTER \ - L"\0"; - break; - case FFLOAD_RAW: - mOFN.lpstrFilter = RAW_FILTER \ - L"\0"; - break; - // - case FFLOAD_INVGZ: - mOFN.lpstrFilter = INVGZ_FILTER \ - L"\0"; - break; - - case FFLOAD_AO: - mOFN.lpstrFilter = AO_FILTER \ - L"\0"; - break; - - case FFLOAD_BLACKLIST: - mOFN.lpstrFilter = BLACKLIST_FILTER \ - L"\0"; - break; - // - default: - res = FALSE; - break; - } - return res; -} - -BOOL LLFilePickerBase::getOpenFile(ELoadFilter filter) -{ - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // don't provide default file selection - mFilesW[0] = '\0'; - - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - mOFN.lpstrFile = mFilesW; - mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; - mOFN.nFilterIndex = 1; - - setupFilter(filter); - - // Modal, so pause agent - send_agent_pause(); - - reset(); - - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetOpenFileName(&mOFN); - if (success) - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - send_agent_resume(); - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; -} - -BOOL LLFilePickerBase::getMultipleOpenFiles(ELoadFilter filter) -{ - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - // don't provide default file selection - mFilesW[0] = '\0'; - - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - mOFN.lpstrFile = mFilesW; - mOFN.nFilterIndex = 1; - mOFN.nMaxFile = FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | - OFN_EXPLORER | OFN_ALLOWMULTISELECT; - - setupFilter(filter); - - reset(); - - // Modal, so pause agent - send_agent_pause(); - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetOpenFileName(&mOFN); // pauses until ok or cancel. - if( success ) - { - // The getopenfilename api doesn't tell us if we got more than - // one file, so we have to test manually by checking string - // lengths. - if( wcslen(mOFN.lpstrFile) > mOFN.nFileOffset ) /*Flawfinder: ignore*/ - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - else - { - mLocked = TRUE; - WCHAR* tptrw = mFilesW; - std::string dirname; - while(1) - { - if (*tptrw == 0 && *(tptrw+1) == 0) // double '\0' - break; - if (*tptrw == 0) - tptrw++; // shouldn't happen? - std::string filename = utf16str_to_utf8str(llutf16string(tptrw)); - if (dirname.empty()) - dirname = filename + "\\"; - else - mFiles.push_back(dirname + filename); - tptrw += filename.size(); - } - } - } - send_agent_resume(); - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; -} - -BOOL LLFilePickerBase::getSaveFile(ESaveFilter filter, const std::string& filename) -{ - if( mLocked ) - { - return FALSE; - } - BOOL success = FALSE; - - mOFN.lpstrFile = mFilesW; - if (!filename.empty()) - { - llutf16string tstring = utf8str_to_utf16str(filename); - wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ - else - { - mFilesW[0] = '\0'; - } - mOFN.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - - switch( filter ) - { - case FFSAVE_ALL: - mOFN.lpstrDefExt = NULL; - mOFN.lpstrFilter = - L"All Files (*.*)\0*.*\0" \ - L"WAV Sounds (*.wav)\0*.wav\0" \ - L"Targa, Bitmap Images (*.tga; *.bmp)\0*.tga;*.bmp\0" \ - L"\0"; - break; - case FFSAVE_WAV: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.wav", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"wav"; - mOFN.lpstrFilter = - L"WAV Sounds (*.wav)\0*.wav\0" \ - L"\0"; - break; - case FFSAVE_TGA: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.tga", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"tga"; - mOFN.lpstrFilter = - L"Targa Images (*.tga)\0*.tga\0" \ - L"\0"; - break; - case FFSAVE_BMP: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.bmp", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"bmp"; - mOFN.lpstrFilter = - L"Bitmap Images (*.bmp)\0*.bmp\0" \ - L"\0"; - break; - case FFSAVE_PNG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"png"; - mOFN.lpstrFilter = - L"PNG Images (*.png)\0*.png\0" \ - L"\0"; - break; - case FFSAVE_JPEG: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"jpg"; - mOFN.lpstrFilter = - L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \ - L"\0"; - break; - case FFSAVE_AVI: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.avi", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"avi"; - mOFN.lpstrFilter = - L"AVI Movie File (*.avi)\0*.avi\0" \ - L"\0"; - break; - case FFSAVE_ANIM: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.xaf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"xaf"; - mOFN.lpstrFilter = - L"XAF Anim File (*.xaf)\0*.xaf\0" \ - L"\0"; - break; -#ifdef _CORY_TESTING - case FFSAVE_GEOMETRY: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"slg"; - mOFN.lpstrFilter = - L"SLG SL Geometry File (*.slg)\0*.slg\0" \ - L"\0"; - break; -#endif - case FFSAVE_XML: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.xml", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - - mOFN.lpstrDefExt = L"xml"; - mOFN.lpstrFilter = - L"XML File (*.xml)\0*.xml\0" \ - L"\0"; - break; - case FFSAVE_COLLADA: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.collada", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"collada"; - mOFN.lpstrFilter = - L"COLLADA File (*.collada)\0*.collada\0" \ - L"\0"; - break; - case FFSAVE_RAW: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.raw", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ - } - mOFN.lpstrDefExt = L"raw"; - mOFN.lpstrFilter = RAW_FILTER \ - L"\0"; - break; - case FFSAVE_J2C: - if (filename.empty()) - { - wcsncpy( mFilesW,L"untitled.j2c", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"j2c"; - mOFN.lpstrFilter = - L"Compressed Images (*.j2c)\0*.j2c\0" \ - L"\0"; - break; - // - case FFSAVE_ANIMATN: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.animatn", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"animatn"; - mOFN.lpstrFilter = - L"SL Animations (*.animatn)\0*.animatn\0" \ - L"\0"; - break; - case FFSAVE_OGG: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.ogg", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"ogg"; - mOFN.lpstrFilter = - L"Ogg (*.ogg)\0*.ogg\0" \ - L"\0"; - break; - case FFSAVE_NOTECARD: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.notecard", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"notecard"; - mOFN.lpstrFilter = - L"Notecards (*.notecard)\0*.notecard\0" \ - L"\0"; - break; - case FFSAVE_GESTURE: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.gesture", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"gesture"; - mOFN.lpstrFilter = - L"Gestures (*.gesture)\0*.gesture\0" \ - L"\0"; - break; - case FFSAVE_LSL: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.lsl", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"lsl"; - mOFN.lpstrFilter = - L"LSL (*.lsl)\0*.lsl\0" \ - L"\0"; - break; - case FFSAVE_SHAPE: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.shape", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"shape"; - mOFN.lpstrFilter = - L"Shapes (*.shape)\0*.shape\0" \ - L"\0"; - break; - case FFSAVE_SKIN: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.skin", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"skin"; - mOFN.lpstrFilter = - L"Skins (*.skin)\0*.skin\0" \ - L"\0"; - break; - case FFSAVE_HAIR: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.hair", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"hair"; - mOFN.lpstrFilter = - L"Hair (*.hair)\0*.hair\0" \ - L"\0"; - break; - case FFSAVE_EYES: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.eyes", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"eyes"; - mOFN.lpstrFilter = - L"Eyes (*.eyes)\0*.eyes\0" \ - L"\0"; - break; - case FFSAVE_SHIRT: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.shirt", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"shirt"; - mOFN.lpstrFilter = - L"Shirts (*.shirt)\0*.shirt\0" \ - L"\0"; - break; - case FFSAVE_PANTS: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.pants", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"pants"; - mOFN.lpstrFilter = - L"Pants (*.pants)\0*.pants\0" \ - L"\0"; - break; - case FFSAVE_SHOES: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.shoes", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"shoes"; - mOFN.lpstrFilter = - L"Shoes (*.shoes)\0*.shoes\0" \ - L"\0"; - break; - case FFSAVE_SOCKS: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.socks", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"socks"; - mOFN.lpstrFilter = - L"Socks (*.socks)\0*.socks\0" \ - L"\0"; - break; - case FFSAVE_JACKET: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.jacket", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"jacket"; - mOFN.lpstrFilter = - L"Jackets (*.jacket)\0*.jacket\0" \ - L"\0"; - break; - case FFSAVE_GLOVES: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.gloves", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"gloves"; - mOFN.lpstrFilter = - L"Gloves (*.gloves)\0*.gloves\0" \ - L"\0"; - break; - case FFSAVE_UNDERSHIRT: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.undershirt", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"undershirt"; - mOFN.lpstrFilter = - L"Undershirts (*.undershirt)\0*.undershirt\0" \ - L"\0"; - break; - case FFSAVE_UNDERPANTS: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.underpants", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"underpants"; - mOFN.lpstrFilter = - L"Underpants (*.underpants)\0*.underpants\0" \ - L"\0"; - break; - case FFSAVE_SKIRT: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.skirt", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"skirt"; - mOFN.lpstrFilter = - L"Skirts (*.skirt)\0*.skirt\0" \ - L"\0"; - break; - case FFSAVE_LANDMARK: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.landmark", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"landmark"; - mOFN.lpstrFilter = - L"Landmarks (*.landmark)\0*.landmark\0" \ - L"\0"; - break; - case FFSAVE_AO: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.ao", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"ao"; - mOFN.lpstrFilter = - L"Animation overrides (*.ao)\0*.ao\0" \ - L"\0"; - break; - case FFSAVE_INVGZ: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.inv", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L".inv"; - mOFN.lpstrFilter = - L"InvCache (*.inv)\0*.inv\0" \ - L"\0"; - break; - case FFSAVE_BLACKLIST: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.blacklist", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L".blacklist"; - mOFN.lpstrFilter = - L"Asset Blacklists (*.blacklist)\0*.blacklist\0" \ - L"\0"; - break; - case FFSAVE_PHYSICS: - if(filename.empty()) - { - wcsncpy( mFilesW,L"untitled.phy", FILENAME_BUFFER_SIZE); - } - mOFN.lpstrDefExt = L"phy"; - mOFN.lpstrFilter = - L"Landmarks (*.phy)\0*.phy\0" \ - L"\0"; - break; - // - default: - return FALSE; - } - - - mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; - mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; - - reset(); - - // Modal, so pause agent - send_agent_pause(); - { - // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetSaveFileName(&mOFN); - if (success) - { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); - } - gKeyboard->resetKeys(); - } - send_agent_resume(); - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; -} - -#elif LL_DARWIN - -Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode) -{ - Boolean result = true; - ELoadFilter filter = *((ELoadFilter*) callBackUD); - OSStatus error = noErr; - - if (filterMode == kNavFilteringBrowserList && filter != FFLOAD_ALL && (theItem->descriptorType == typeFSRef || theItem->descriptorType == typeFSS)) - { - // navInfo is only valid for typeFSRef and typeFSS - NavFileOrFolderInfo *navInfo = (NavFileOrFolderInfo*) info; - if (!navInfo->isFolder) - { - AEDesc desc; - error = AECoerceDesc(theItem, typeFSRef, &desc); - if (error == noErr) - { - FSRef fileRef; - error = AEGetDescData(&desc, &fileRef, sizeof(fileRef)); - if (error == noErr) - { - LSItemInfoRecord fileInfo; - error = LSCopyItemInfoForRef(&fileRef, kLSRequestExtension | kLSRequestTypeCreator, &fileInfo); - if (error == noErr) - { - if (filter == FFLOAD_IMAGE) - { - if (fileInfo.filetype != 'JPEG' && fileInfo.filetype != 'JPG ' && - fileInfo.filetype != 'BMP ' && fileInfo.filetype != 'TGA ' && - fileInfo.filetype != 'BMPf' && fileInfo.filetype != 'TPIC' && - fileInfo.filetype != 'PNG ' && - (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("jpeg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && - CFStringCompare(fileInfo.extension, CFSTR("jpg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && - CFStringCompare(fileInfo.extension, CFSTR("bmp"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && - CFStringCompare(fileInfo.extension, CFSTR("tga"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && - CFStringCompare(fileInfo.extension, CFSTR("png"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) - ) - { - result = false; - } - } - else if (filter == FFLOAD_WAV) - { - if (fileInfo.filetype != 'WAVE' && fileInfo.filetype != 'WAV ' && - (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("wave"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && - CFStringCompare(fileInfo.extension, CFSTR("wav"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) - ) - { - result = false; - } - } - else if (filter == FFLOAD_ANIM) - { - if (fileInfo.filetype != 'BVH ' && - (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("bvh"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) - ) - { - result = false; - } - } - else if (filter == FFLOAD_XML) - { - if (fileInfo.filetype != 'XML ' && - (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("xml"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) - ) - { - result = false; - } - } -#ifdef _CORY_TESTING - else if (filter == FFLOAD_GEOMETRY) - { - if (fileInfo.filetype != 'SLG ' && - (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("slg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) - ) - { - result = false; - } - } -#endif - else if (filter == FFLOAD_SLOBJECT) - { - llwarns << "*** navOpenFilterProc: FFLOAD_SLOBJECT NOT IMPLEMENTED ***" << llendl; - } - else if (filter == FFLOAD_RAW) - { - if (fileInfo.filetype != '\?\?\?\?' && - (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("raw"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) - ) - { - result = false; - } - } - - if (fileInfo.extension) - { - CFRelease(fileInfo.extension); - } - } - } - AEDisposeDesc(&desc); - } - } - } - return result; -} - -OSStatus LLFilePickerBase::doNavChooseDialog(ELoadFilter filter) -{ - OSStatus error = noErr; - NavDialogRef navRef = NULL; - NavReplyRecord navReply; - - memset(&navReply, 0, sizeof(navReply)); - - // NOTE: we are passing the address of a local variable here. - // This is fine, because the object this call creates will exist for less than the lifetime of this function. - // (It is destroyed by NavDialogDispose() below.) - error = NavCreateChooseFileDialog(&mNavOptions, NULL, NULL, NULL, navOpenFilterProc, (void*)(&filter), &navRef); - - gViewerWindow->mWindow->beforeDialog(); - - if (error == noErr) - error = NavDialogRun(navRef); - - gViewerWindow->mWindow->afterDialog(); - - if (error == noErr) - error = NavDialogGetReply(navRef, &navReply); - - if (navRef) - NavDialogDispose(navRef); - - if (error == noErr && navReply.validRecord) - { - SInt32 count = 0; - SInt32 index; - - // AE indexes are 1 based... - error = AECountItems(&navReply.selection, &count); - for (index = 1; index <= count; index++) - { - FSRef fsRef; - AEKeyword theAEKeyword; - DescType typeCode; - Size actualSize = 0; - char path[MAX_PATH]; /*Flawfinder: ignore*/ - - memset(&fsRef, 0, sizeof(fsRef)); - error = AEGetNthPtr(&navReply.selection, index, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize); - - if (error == noErr) - error = FSRefMakePath(&fsRef, (UInt8*) path, sizeof(path)); - - if (error == noErr) - mFiles.push_back(std::string(path)); - } - } - - return error; -} - -OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, const std::string& filename) -{ - OSStatus error = noErr; - NavDialogRef navRef = NULL; - NavReplyRecord navReply; - - memset(&navReply, 0, sizeof(navReply)); - - // Setup the type, creator, and extension - OSType type, creator; - CFStringRef extension = NULL; - switch (filter) - { - case FFSAVE_WAV: - type = 'WAVE'; - creator = 'TVOD'; - extension = CFSTR(".wav"); - break; - - case FFSAVE_TGA: - type = 'TPIC'; - creator = 'prvw'; - extension = CFSTR(".tga"); - break; - - case FFSAVE_BMP: - type = 'BMPf'; - creator = 'prvw'; - extension = CFSTR(".bmp"); - break; - case FFSAVE_JPEG: - type = 'JPEG'; - creator = 'prvw'; - extension = CFSTR(".jpeg"); - break; - case FFSAVE_PNG: - type = 'PNG '; - creator = 'prvw'; - extension = CFSTR(".png"); - break; - case FFSAVE_AVI: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; - extension = CFSTR(".mov"); - break; - - case FFSAVE_ANIM: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; - extension = CFSTR(".xaf"); - break; - -#ifdef _CORY_TESTING - case FFSAVE_GEOMETRY: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; - extension = CFSTR(".slg"); - break; -#endif - case FFSAVE_RAW: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; - extension = CFSTR(".raw"); - break; - - case FFSAVE_J2C: - type = '\?\?\?\?'; - creator = 'prvw'; - extension = CFSTR(".j2c"); - break; - - case FFSAVE_ALL: - default: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; - extension = CFSTR(""); - break; - } - - // Create the dialog - error = NavCreatePutFileDialog(&mNavOptions, type, creator, NULL, NULL, &navRef); - if (error == noErr) - { - CFStringRef nameString = NULL; - bool hasExtension = true; - - // Create a CFString of the initial file name - if (!filename.empty()) - nameString = CFStringCreateWithCString(NULL, filename.c_str(), kCFStringEncodingUTF8); - else - nameString = CFSTR("Untitled"); - - // Add the extension if one was not provided - if (nameString && !CFStringHasSuffix(nameString, extension)) - { - CFStringRef tempString = nameString; - hasExtension = false; - nameString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), tempString, extension); - CFRelease(tempString); - } - - // Set the name in the dialog - if (nameString) - { - error = NavDialogSetSaveFileName(navRef, nameString); - CFRelease(nameString); - } - else - { - error = paramErr; - } - } - - gViewerWindow->mWindow->beforeDialog(); - - // Run the dialog - if (error == noErr) - error = NavDialogRun(navRef); - - gViewerWindow->mWindow->afterDialog(); - - if (error == noErr) - error = NavDialogGetReply(navRef, &navReply); - - if (navRef) - NavDialogDispose(navRef); - - if (error == noErr && navReply.validRecord) - { - SInt32 count = 0; - - // AE indexes are 1 based... - error = AECountItems(&navReply.selection, &count); - if (count > 0) - { - // Get the FSRef to the containing folder - FSRef fsRef; - AEKeyword theAEKeyword; - DescType typeCode; - Size actualSize = 0; - - memset(&fsRef, 0, sizeof(fsRef)); - error = AEGetNthPtr(&navReply.selection, 1, typeFSRef, &theAEKeyword, &typeCode, &fsRef, sizeof(fsRef), &actualSize); - - if (error == noErr) - { - char path[PATH_MAX]; /*Flawfinder: ignore*/ - char newFileName[SINGLE_FILENAME_BUFFER_SIZE]; /*Flawfinder: ignore*/ - - error = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX); - if (error == noErr) - { - if (CFStringGetCString(navReply.saveFileName, newFileName, sizeof(newFileName), kCFStringEncodingUTF8)) - { - mFiles.push_back(std::string(path) + "/" + std::string(newFileName)); - } - else - { - error = paramErr; - } - } - else - { - error = paramErr; - } - } - } - } - - return error; -} - -BOOL LLFilePickerBase::getOpenFile(ELoadFilter filter) -{ - if( mLocked ) - return FALSE; - - BOOL success = FALSE; - - OSStatus error = noErr; - - reset(); - - mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; - // Modal, so pause agent - send_agent_pause(); - { - error = doNavChooseDialog(filter); - } - send_agent_resume(); - if (error == noErr) - { - if (getFileCount()) - success = true; - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; -} - -BOOL LLFilePickerBase::getMultipleOpenFiles(ELoadFilter filter) -{ - if( mLocked ) - return FALSE; - - BOOL success = FALSE; - - OSStatus error = noErr; - - reset(); - - mNavOptions.optionFlags |= kNavAllowMultipleFiles; - // Modal, so pause agent - send_agent_pause(); - { - error = doNavChooseDialog(filter); - } - send_agent_resume(); - if (error == noErr) - { - if (getFileCount()) - success = true; - if (getFileCount() > 1) - mLocked = TRUE; - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; -} - -BOOL LLFilePickerBase::getSaveFile(ESaveFilter filter, const std::string& filename) -{ - if( mLocked ) - return FALSE; - BOOL success = FALSE; - OSStatus error = noErr; - - reset(); - - mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; - - // Modal, so pause agent - send_agent_pause(); - { - error = doNavSaveDialog(filter, filename); - } - send_agent_resume(); - if (error == noErr) - { - if (getFileCount()) - success = true; - } - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); - return success; -} - -#elif LL_LINUX || LL_SOLARIS - -# if LL_GTK - -// static -void LLFilePickerBase::add_to_selectedfiles(gpointer data, gpointer user_data) -{ - // We need to run g_filename_to_utf8 in the user's locale - std::string saved_locale(setlocale(LC_ALL, NULL)); - setlocale(LC_ALL, ""); - - LLFilePickerBase* picker = (LLFilePickerBase*) user_data; - GError *error = NULL; - gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, - -1, NULL, NULL, &error); - if (error) - { - // *FIXME. - // This condition should really be notified to the user, e.g. - // through a message box. Just logging it is inappropriate. - - // g_filename_display_name is ideal, but >= glib 2.6, so: - // a hand-rolled hacky makeASCII which disallows control chars - std::string display_name; - for (const gchar *str = (const gchar *)data; *str; str++) - { - display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); - } - llwarns << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << llendl; - } - - if (filename_utf8) - { - picker->mFiles.push_back(std::string(filename_utf8)); - lldebugs << "ADDED FILE " << filename_utf8 << llendl; - g_free(filename_utf8); - } - - setlocale(LC_ALL, saved_locale.c_str()); -} - -// static -void LLFilePickerBase::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) -{ - LLFilePicker* picker = (LLFilePicker*)user_data; - - lldebugs << "GTK DIALOG RESPONSE " << response << llendl; - - if (response == GTK_RESPONSE_ACCEPT) - { - GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); - g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); - g_slist_foreach(file_list, (GFunc)g_free, NULL); - g_slist_free (file_list); - } - - // set the default path for this usage context. - picker->mContextToPathMap[picker->mCurContextName] = - gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); - - gtk_widget_destroy(widget); - gtk_main_quit(); -} - - -GtkWindow* LLFilePickerBase::buildFilePicker(bool is_save, bool is_folder, std::string context) -{ - if (LLWindowSDL::ll_try_gtk_init()) - { - GtkWidget *win = NULL; - GtkFileChooserAction pickertype = - is_save? - (is_folder? - GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : - GTK_FILE_CHOOSER_ACTION_SAVE) : - (is_folder? - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : - GTK_FILE_CHOOSER_ACTION_OPEN); - - win = gtk_file_chooser_dialog_new(NULL, NULL, - pickertype, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - is_folder ? - GTK_STOCK_APPLY : - (is_save ? - GTK_STOCK_SAVE : - GTK_STOCK_OPEN), - GTK_RESPONSE_ACCEPT, - (gchar *)NULL); - mCurContextName = context; - - // get the default path for this usage context if it's been - // seen before. - std::map::iterator - this_path = mContextToPathMap.find(context); - if (this_path != mContextToPathMap.end()) - { - gtk_file_chooser_set_current_folder - (GTK_FILE_CHOOSER(win), - this_path->second.c_str()); - } - -# if LL_X11 - // Make GTK tell the window manager to associate this - // dialog with our non-GTK raw X11 window, which should try - // to keep it on top etc. - Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); - if (None != XWindowID) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } - else - { - llwarns << "Hmm, couldn't get xwid to use for transient." << llendl; - } -# endif //LL_X11 - - g_signal_connect (GTK_FILE_CHOOSER(win), - "response", - G_CALLBACK(LLFilePickerBase::chooser_responder), - this); - - gtk_window_set_modal(GTK_WINDOW(win), TRUE); - - /* GTK 2.6: if (is_folder) - gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), - TRUE); */ - - return GTK_WINDOW(win); - } - else - { - return NULL; - } -} - -static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter, - GtkWindow *picker, - std::string filtername) -{ - gtk_file_filter_set_name(gfilter, filtername.c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), - gfilter); - GtkFileFilter *allfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(allfilter, "*"); - gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); -} - -static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker, - std::string pattern, - std::string filtername) -{ - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, pattern.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; -} - -static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, - std::string mime, - std::string filtername) -{ - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_mime_type(gfilter, mime.c_str()); - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; -} - -static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav", - LLTrans::getString("sound_files") + " (*.wav)"); -} - -static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_pattern_filter_to_gtkchooser(picker, "*.bvh", - LLTrans::getString("animation_files") + " (*.bvh)"); -} - -static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) -{ - return add_simple_mime_filter_to_gtkchooser(picker, "text/xml", - LLTrans::getString("xml_file") + " (*.xml)"); -} - -static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) -{ - GtkFileFilter *gfilter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(gfilter, "*.tga"); - gtk_file_filter_add_mime_type(gfilter, "image/jpeg"); - gtk_file_filter_add_mime_type(gfilter, "image/png"); - gtk_file_filter_add_mime_type(gfilter, "image/bmp"); - std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; - add_common_filters_to_gtkchooser(gfilter, picker, filtername); - return filtername; -} - - -BOOL LLFilePickerBase::getSaveFile( ESaveFilter filter, const std::string& filename ) -{ - BOOL rtn = FALSE; - - gViewerWindow->mWindow->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(true, false, "savefile"); - - if (picker) - { - std::string suggest_name = "untitled"; - std::string suggest_ext = ""; - std::string caption = LLTrans::getString("save_file_verb") + " "; - switch (filter) - { - case FFSAVE_WAV: - caption += add_wav_filter_to_gtkchooser(picker); - suggest_ext = ".wav"; - break; - case FFSAVE_TGA: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); - suggest_ext = ".tga"; - break; - case FFSAVE_BMP: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "image/bmp", LLTrans::getString("bitmap_image_files") + " (*.bmp)"); - suggest_ext = ".bmp"; - break; - case FFSAVE_AVI: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "video/x-msvideo", - LLTrans::getString("avi_movie_file") + " (*.avi)"); - suggest_ext = ".avi"; - break; - case FFSAVE_ANIM: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); - suggest_ext = ".xaf"; - break; - case FFSAVE_XML: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); - suggest_ext = ".xml"; - break; - case FFSAVE_RAW: - caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); - suggest_ext = ".raw"; - break; - case FFSAVE_J2C: - caption += add_simple_mime_filter_to_gtkchooser - (picker, "images/jp2", - LLTrans::getString("compressed_image_files") + " (*.j2c)"); - suggest_ext = ".j2c"; - break; - default:; - break; - } - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - if (filename.empty()) - { - suggest_name += suggest_ext; - - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), - suggest_name.c_str()); - } - else - { - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(picker), filename.c_str()); - } - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - - rtn = (getFileCount() == 1); - } - - gViewerWindow->mWindow->afterDialog(); - - return rtn; -} - -BOOL LLFilePickerBase::getOpenFile( ELoadFilter filter ) -{ - BOOL rtn = FALSE; - - gViewerWindow->mWindow->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) - { - std::string caption = LLTrans::getString("load_file_verb") + " "; - std::string filtername = ""; - switch (filter) - { - case FFLOAD_WAV: - filtername = add_wav_filter_to_gtkchooser(picker); - break; - case FFLOAD_ANIM: - filtername = add_bvh_filter_to_gtkchooser(picker); - break; - case FFLOAD_IMAGE: - filtername = add_imageload_filter_to_gtkchooser(picker); - break; - case FFLOAD_XML: - filtername = add_xml_filter_to_gtkchooser(picker); - break; - default:; - break; - } - - caption += filtername; - - gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - - rtn = (getFileCount() == 1); - } - - gViewerWindow->mWindow->afterDialog(); - - return rtn; -} - -BOOL LLFilePickerBase::getMultipleOpenFiles( ELoadFilter filter ) -{ - BOOL rtn = FALSE; - - gViewerWindow->mWindow->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) - { - gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), - TRUE); - - gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); - - gtk_widget_show_all(GTK_WIDGET(picker)); - gtk_main(); - rtn = !mFiles.empty(); - } - - gViewerWindow->mWindow->afterDialog(); - - return rtn; -} - -# else // LL_GTK - -// Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with -// static results, when we don't have a real filepicker. - -BOOL LLFilePickerBase::getSaveFile( ESaveFilter filter, const std::string& filename ) -{ - reset(); - - llinfos << "getSaveFile suggested filename is [" << filename - << "]" << llendl; - if (!filename.empty()) - { - mFiles.push_back(gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + filename); - return TRUE; - } - return FALSE; -} - -BOOL LLFilePickerBase::getOpenFile( ELoadFilter filter ) -{ - reset(); - - // HACK: Static filenames for 'open' until we implement filepicker - std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; - switch (filter) - { - case FFLOAD_WAV: filename += ".wav"; break; - case FFLOAD_IMAGE: filename += ".tga"; break; - case FFLOAD_ANIM: filename += ".bvh"; break; - case FFLOAD_XML: filename += ".xml"; break; - default: break; - } - mFiles.push_back(filename); - llinfos << "getOpenFile: Will try to open file: " << hackyfilename << llendl; - return TRUE; -} - -BOOL LLFilePickerBase::getMultipleOpenFiles( ELoadFilter filter ) -{ - reset(); - return FALSE; -} - -#endif // LL_GTK - -#else // not implemented - -BOOL LLFilePickerBase::getSaveFile( ESaveFilter filter, const std::string& filename ) -{ - reset(); - return FALSE; -} - -BOOL LLFilePickerBase::getOpenFile( ELoadFilter filter ) -{ - reset(); - return FALSE; -} - -BOOL LLFilePickerBase::getMultipleOpenFiles( ELoadFilter filter ) -{ - reset(); - return FALSE; -} - -#endif diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h deleted file mode 100644 index 3be94f8e0..000000000 --- a/indra/newview/llfilepicker.h +++ /dev/null @@ -1,230 +0,0 @@ -/** - * @file llfilepicker.h - * @brief OS-specific file picker - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-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$ - */ - -// OS specific file selection dialog. This is implemented as a -// singleton class, so call the instance() method to get the working -// instance. When you call getMultipleOpenFile(), it locks the picker -// until you iterate to the end of the list of selected files with -// getNextFile() or call reset(). - -#ifndef LL_LLFILEPICKER_H -#define LL_LLFILEPICKER_H - -#include "stdtypes.h" - -#if LL_DARWIN -#include - -// AssertMacros.h does bad things. -#undef verify -#undef check -#undef require - -#include -#include "llstring.h" - -#endif - -// Need commdlg.h for OPENFILENAMEA -#ifdef LL_WINDOWS -#include -#endif - -// mostly for Linux, possible on others -#if LL_GTK -# include "gtk/gtk.h" -#endif // LL_GTK - -// also mostly for Linux, for some X11-specific filepicker usability tweaks -#if LL_X11 -#include "SDL/SDL_syswm.h" -#endif - -// This class is used as base class of a singleton and is therefore not -// allowed to have any static members or static local variables! -class LLFilePickerBase -{ -public: - enum ELoadFilter - { - FFLOAD_ALL = 1, - FFLOAD_WAV = 2, - FFLOAD_IMAGE = 3, - FFLOAD_ANIM = 4, -#ifdef _CORY_TESTING - FFLOAD_GEOMETRY = 5, -#endif - FFLOAD_XML = 6, - FFLOAD_SLOBJECT = 7, - FFLOAD_RAW = 8, - // - FFLOAD_INVGZ = 9, - FFLOAD_AO = 10, - FFLOAD_BLACKLIST = 11 - // - }; - - enum ESaveFilter - { - FFSAVE_ALL = 1, - FFSAVE_WAV = 3, - FFSAVE_TGA = 4, - FFSAVE_BMP = 5, - FFSAVE_AVI = 6, - FFSAVE_ANIM = 7, -#ifdef _CORY_TESTING - FFSAVE_GEOMETRY = 8, -#endif - FFSAVE_XML = 9, - FFSAVE_COLLADA = 10, - FFSAVE_RAW = 11, - FFSAVE_J2C = 12, - FFSAVE_PNG = 13, - FFSAVE_JPEG = 14, - // - FFSAVE_ANIMATN = 15, - FFSAVE_OGG = 16, - FFSAVE_NOTECARD = 17, - FFSAVE_GESTURE = 18, - FFSAVE_LSL = 19, - // good grief - FFSAVE_SHAPE = 20, - FFSAVE_SKIN = 21, - FFSAVE_HAIR = 22, - FFSAVE_EYES = 23, - FFSAVE_SHIRT = 24, - FFSAVE_PANTS = 25, - FFSAVE_SHOES = 26, - FFSAVE_SOCKS = 27, - FFSAVE_JACKET = 28, - FFSAVE_GLOVES = 29, - FFSAVE_UNDERSHIRT = 30, - FFSAVE_UNDERPANTS = 31, - FFSAVE_SKIRT = 32, - FFSAVE_INVGZ = 33, - FFSAVE_LANDMARK = 34, - FFSAVE_AO = 35, - FFSAVE_BLACKLIST = 36, - FFSAVE_PHYSICS = 37, - // - }; - - // open the dialog. This is a modal operation - BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null ); - BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL ); - BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL ); - - // Get the filename(s) found. getFirstFile() sets the pointer to - // the start of the structure and allows the start of iteration. - const std::string getFirstFile(); - - // getNextFile() increments the internal representation and - // returns the next file specified by the user. Returns NULL when - // no more files are left. Further calls to getNextFile() are - // undefined. - const std::string getNextFile(); - - // This utility function extracts the current file name without - // doing any incrementing. - const std::string getCurFile(); - - // Returns the index of the current file. - S32 getCurFileNum() const { return mCurrentFile; } - - S32 getFileCount() const { return (S32)mFiles.size(); } - - // See llvfs/lldir.h : getBaseFileName and getDirName to extract base or directory names - - // clear any lists of buffers or whatever, and make sure the file - // picker isn't locked. - void reset(); - -private: - enum - { - SINGLE_FILENAME_BUFFER_SIZE = 1024, - //FILENAME_BUFFER_SIZE = 65536 - FILENAME_BUFFER_SIZE = 65000 - }; - -#if LL_WINDOWS - OPENFILENAMEW mOFN; // for open and save dialogs - WCHAR mFilesW[FILENAME_BUFFER_SIZE]; - - BOOL setupFilter(ELoadFilter filter); -#endif - -#if LL_DARWIN - NavDialogCreationOptions mNavOptions; - - OSStatus doNavChooseDialog(ELoadFilter filter); - OSStatus doNavSaveDialog(ESaveFilter filter, const std::string& filename); - static Boolean navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode); -#endif - -#if LL_GTK - static void add_to_selectedfiles(gpointer data, gpointer user_data); - static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); - // we remember the last path that was accessed for a particular usage - std::map mContextToPathMap; - std::string mCurContextName; -#endif - - std::vector mFiles; - S32 mCurrentFile; - BOOL mLocked; - BOOL mMultiFile; - -protected: -#if LL_GTK - GtkWindow* buildFilePicker(bool is_save, bool is_folder, - std::string context = "generic"); -#endif - -protected: - LLFilePickerBase(); -}; - -// True singleton, private constructors (and no friends). -class LLFilePicker : public LLFilePickerBase -{ -public: - // calling this before main() is undefined - static LLFilePicker& instance( void ) { return sInstance; } - -private: - static LLFilePicker sInstance; - - LLFilePicker() { } -}; - -#endif diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 6e524a05f..72720692f 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -76,7 +76,6 @@ #include "llviewerwindow.h" #include "llviewertexturelist.h" #include "llworldmap.h" -#include "llfilepicker.h" #include "llfloateravatarpicker.h" #include "lldir.h" #include "llselectmgr.h" diff --git a/indra/newview/llfloatervfsexplorer.cpp b/indra/newview/llfloatervfsexplorer.cpp index 6f6384a37..99662b9d9 100644 --- a/indra/newview/llfloatervfsexplorer.cpp +++ b/indra/newview/llfloatervfsexplorer.cpp @@ -5,7 +5,6 @@ #include "lluictrlfactory.h" #include "llscrolllistctrl.h" #include "llcheckboxctrl.h" -#include "llfilepicker.h" #include "llvfs.h" #include "lllocalinventory.h" #include "llviewerwindow.h" diff --git a/indra/newview/llinventorybackup.cpp b/indra/newview/llinventorybackup.cpp index c6f687272..416c82065 100644 --- a/indra/newview/llinventorybackup.cpp +++ b/indra/newview/llinventorybackup.cpp @@ -5,7 +5,7 @@ #include "llinventorymodel.h" #include "llviewerinventory.h" #include "statemachine/aifilepicker.h" -#include "lldirpicker.h" +#include "statemachine/aidirpicker.h" #include "llviewertexturelist.h" // gTextureList #include "llagent.h" // gAgent #include "llviewerwindow.h" // gViewerWindow @@ -120,36 +120,41 @@ void LLFloaterInventoryBackupSettings::onClickNext(void* userdata) } // Get dir name - LLDirPicker& picker = LLDirPicker::instance(); - std::string filename = "New Folder"; - if (!picker.getDir(&filename)) + AIDirPicker* dirpicker = new AIDirPicker("New Folder"); + dirpicker->run(boost::bind(&LLFloaterInventoryBackupSettings::onClickNext_continued, userdata, dirpicker)); +} + +// static +void LLFloaterInventoryBackupSettings::onClickNext_continued(void* userdata, AIDirPicker* dirpicker) +{ + LLFloaterInventoryBackupSettings* floater = (LLFloaterInventoryBackupSettings*)userdata; + LLInventoryBackupOrder* order = floater->mOrder; + + if (!dirpicker->hasDirname()) { floater->close(); return; } - filename = picker.getDirName(); + std::string dirname = dirpicker->getDirname(); // Make local directory tree - LLFile::mkdir(filename); + LLFile::mkdir(dirname); std::vector::iterator _cat_iter = order->mCats.begin(); std::vector::iterator _cat_end = order->mCats.end(); for( ; _cat_iter != _cat_end; ++_cat_iter) { - std::string path = filename + OS_SEP + LLInventoryBackup::getPath(*_cat_iter, order->mCats); + std::string path = dirname + OS_SEP + LLInventoryBackup::getPath(*_cat_iter, order->mCats); LLFile::mkdir(path); } // Go go backup floater - LLFloaterInventoryBackup* backup_floater = new LLFloaterInventoryBackup(filename, order->mCats, order->mItems); + LLFloaterInventoryBackup* backup_floater = new LLFloaterInventoryBackup(dirname, order->mCats, order->mItems); backup_floater->center(); // Close myself floater->close(); } - - - // static bool LLInventoryBackup::itemIsFolder(LLInventoryItem* item) { diff --git a/indra/newview/llinventorybackup.h b/indra/newview/llinventorybackup.h index 16d9a3ad1..2ee0c197c 100644 --- a/indra/newview/llinventorybackup.h +++ b/indra/newview/llinventorybackup.h @@ -15,6 +15,8 @@ #include "llviewertexture.h" #include "llfloater.h" +class AIDirPicker; + class LLInventoryBackupOrder { public: @@ -44,6 +46,7 @@ public: LLFloaterInventoryBackupSettings(LLInventoryBackupOrder* order); BOOL postBuild(void); static void onClickNext(void* userdata); + static void onClickNext_continued(void* userdata, AIDirPicker* dirpicker); LLInventoryBackupOrder* mOrder; virtual ~LLFloaterInventoryBackupSettings(); diff --git a/indra/newview/llpanelnetwork.cpp b/indra/newview/llpanelnetwork.cpp index 6e66628eb..6bc34989a 100644 --- a/indra/newview/llpanelnetwork.cpp +++ b/indra/newview/llpanelnetwork.cpp @@ -39,7 +39,7 @@ // project includes #include "llcheckboxctrl.h" #include "llradiogroup.h" -#include "lldirpicker.h" +#include "statemachine/aidirpicker.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" #include "llviewerwindow.h" @@ -151,18 +151,24 @@ void LLPanelNetwork::onClickClearCache(void*) // static void LLPanelNetwork::onClickSetCache(void* user_data) { - LLPanelNetwork* self = (LLPanelNetwork*)user_data; - std::string cur_name(gSavedSettings.getString("CacheLocation")); std::string proposed_name(cur_name); - LLDirPicker& picker = LLDirPicker::instance(); - if (! picker.getDir(&proposed_name ) ) + AIDirPicker* dirpicker = new AIDirPicker(proposed_name, "cachelocation"); + dirpicker->run(boost::bind(&LLPanelNetwork::onClickSetCache_continued, user_data, dirpicker)); +} + +// static +void LLPanelNetwork::onClickSetCache_continued(void* user_data, AIDirPicker* dirpicker) +{ + if (!dirpicker->hasDirname()) { return; //Canceled! } - std::string dir_name = picker.getDirName(); + LLPanelNetwork* self = (LLPanelNetwork*)user_data; + std::string cur_name(gSavedSettings.getString("CacheLocation")); + std::string dir_name = dirpicker->getDirname(); if (!dir_name.empty() && dir_name != cur_name) { self->childSetText("cache_location", dir_name); diff --git a/indra/newview/llpanelnetwork.h b/indra/newview/llpanelnetwork.h index a5e2269a4..30dc471e6 100644 --- a/indra/newview/llpanelnetwork.h +++ b/indra/newview/llpanelnetwork.h @@ -35,6 +35,8 @@ #include "llpanel.h" +class AIDirPicker; + class LLPanelNetwork : public LLPanel { public: @@ -49,6 +51,7 @@ public: private: static void onClickClearCache(void*); static void onClickSetCache(void*); + static void onClickSetCache_continued(void* user_data, AIDirPicker* dirpicker); static void onClickResetCache(void*); static void onCommitPort(LLUICtrl* ctrl, void*); static void onCommitSocks5ProxyEnabled(LLUICtrl* ctrl, void* data); diff --git a/indra/newview/llprefsim.cpp b/indra/newview/llprefsim.cpp index 8c1f71b4b..62dc37726 100644 --- a/indra/newview/llprefsim.cpp +++ b/indra/newview/llprefsim.cpp @@ -45,7 +45,7 @@ #include "llviewernetwork.h" #include "lluictrlfactory.h" -#include "lldirpicker.h" +#include "statemachine/aidirpicker.h" #include "hippogridmanager.h" @@ -53,6 +53,8 @@ #include "rlvhandler.h" // [/RLVa:KB] +class AIDirPicker; + class LLPrefsIMImpl : public LLPanel { public: @@ -67,6 +69,7 @@ public: void enableHistory(); static void onClickLogPath(void* user_data); + static void onClickLogPath_continued(void* user_data, AIDirPicker* dirpicker); static void onCommitLogging(LLUICtrl* ctrl, void* user_data); protected: @@ -301,13 +304,20 @@ void LLPrefsIMImpl::onClickLogPath(void* user_data) std::string proposed_name(self->childGetText("log_path_string")); - LLDirPicker& picker = LLDirPicker::instance(); - if (!picker.getDir(&proposed_name ) ) + AIDirPicker* dirpicker = new AIDirPicker(proposed_name); + dirpicker->run(boost::bind(&LLPrefsIMImpl::onClickLogPath_continued, user_data, dirpicker)); +} + +// static +void LLPrefsIMImpl::onClickLogPath_continued(void* user_data, AIDirPicker* dirpicker) +{ + if (!dirpicker->hasDirname()) { return; //Canceled! } - self->childSetText("log_path_string", picker.getDirName()); + LLPrefsIMImpl* self=(LLPrefsIMImpl*)user_data; + self->childSetText("log_path_string", dirpicker->getDirname()); } diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 319f1cb57..e92a5185c 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -74,7 +74,6 @@ // tag: vaa emerald local_asset_browser [begin] #include "floaterlocalassetbrowse.h" #include "llscrolllistctrl.h" -#include "llfilepicker.h" #define LOCALLIST_COL_ID 1 // tag: vaa emerald local_asset_browser [end] diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index e9fedf37d..a6d96c08c 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -35,9 +35,6 @@ #include "llmenugl.h" -//newview includes -#include "llfilepicker.h" - class LLUICtrl; class LLView; class LLParcelSelection; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index a8d78cd8d..0a3254ea0 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -420,7 +420,7 @@ void upload_error(const std::string& error_message, const std::string& label, co { lldebugs << "unable to remove temp file" << llendl; } - LLFilePicker::instance().reset(); + //AIFIXME? LLFilePicker::instance().reset(); } class LLFileEnableCloseWindow : public view_listener_t @@ -965,7 +965,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, { lldebugs << "unable to remove temp file" << llendl; } - LLFilePicker::instance().reset(); + //AIFIXME? LLFilePicker::instance().reset(); } } // diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 99844508f..60a2be5a3 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -49,7 +49,6 @@ #include "llchat.h" #include "lldbstrings.h" #include "lleconomy.h" -#include "llfilepicker.h" #include "llfocusmgr.h" #include "llfollowcamparams.h" #include "llinstantmessage.h" diff --git a/indra/newview/statemachine/aidirpicker.h b/indra/newview/statemachine/aidirpicker.h new file mode 100644 index 000000000..452f42b3e --- /dev/null +++ b/indra/newview/statemachine/aidirpicker.h @@ -0,0 +1,77 @@ +/** + * @file aidirpicker.h + * @brief Directory picker State machine + * + * Copyright (c) 2011, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * 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. + * + * CHANGELOG + * and additional copyright holders. + * + * 10/05/2011 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AIDIRPICKER_H +#define AIDIRPICKER_H + +#include "aifilepicker.h" + +// A directory picker state machine. +// +// Before calling run(), call open() to pass needed parameters. +// +// When the state machine finishes, call hasDirname to check +// whether or not getDirname will be valid. +// +// Objects of this type can be reused multiple times, see +// also the documentation of AIStateMachine. +class AIDirPicker : protected AIFilePicker { +public: + // Allow to pass the arguments to open upon creation. + // + // The starting directory that the user will be in when the directory picker opens + // will be the same as the directory used the last time the directory picker was + // opened with the same context. If the directory picker was never opened before + // with the given context, the starting directory will be set to default_path + // unless that is the empty string, in which case it will be equal to the + // directory used the last time the file- or dirpicker was opened with context + // "openfile". + AIDirPicker(std::string const& default_path = "", std::string const& context = "openfile") { open(default_path, context); } + + // This should only be called if you want to re-use the AIDirPicker after it finished + // (from the callback function, followed by a call to 'run'). Normally it is not used. + void open(std::string const& default_path = "", std::string const& context = "openfile") { AIFilePicker::open(DF_DIRECTORY, default_path, context); } + + bool hasDirname(void) const { return hasFilename(); } + std::string const& getDirname(void) const { return getFilename(); } + +public: + // Basically all public members of AIStateMachine could made accessible here, + // but I don't think others will ever be needed (not even these, actually). + using AIStateMachine::state_type; + using AIFilePicker::isCanceled; + using AIStateMachine::run; + +protected: + // Call finish() (or abort()), not delete. + /*virtual*/ ~AIDirPicker() { LL_DEBUGS("Plugin") << "Calling AIDirPicker::~AIDirPicker()" << LL_ENDL; } +}; + +#endif diff --git a/indra/newview/statemachine/aifilepicker.cpp b/indra/newview/statemachine/aifilepicker.cpp index e0588a990..e3a09009d 100644 --- a/indra/newview/statemachine/aifilepicker.cpp +++ b/indra/newview/statemachine/aifilepicker.cpp @@ -107,6 +107,9 @@ void AIFilePicker::open(ELoadFilter filter, std::string const& default_path, std mOpenType = multiple ? load_multiple : load; switch(filter) { + case DF_DIRECTORY: + mFilter = "directory"; + break; case FFLOAD_ALL: mFilter = "all"; break; @@ -314,7 +317,8 @@ void AIFilePicker::multiplex_impl(void) static char const* key_str[] = { "all_files", "sound_files", "animation_files", "image_files", "save_file_verb", "targa_image_files", "bitmap_image_files", "avi_movie_file", "xaf_animation_file", - "xml_file", "raw_file", "compressed_image_files", "load_file_verb", "load_files" + "xml_file", "raw_file", "compressed_image_files", "load_file_verb", "load_files", + "choose_the_directory" }; LLSD dictionary; for (int key = 0; key < sizeof(key_str) / sizeof(key_str[0]); ++key) diff --git a/indra/newview/statemachine/aifilepicker.h b/indra/newview/statemachine/aifilepicker.h index d916055fe..a1709eeb8 100644 --- a/indra/newview/statemachine/aifilepicker.h +++ b/indra/newview/statemachine/aifilepicker.h @@ -38,6 +38,7 @@ enum ELoadFilter { + DF_DIRECTORY, FFLOAD_ALL, FFLOAD_WAV, FFLOAD_IMAGE, @@ -175,7 +176,7 @@ public: private: LLPointer mPluginManager; //!< Pointer to the plugin manager. - // FIXME: this should be a separate, thread-safe singleton. + // AIFIXME: this should be a separate, thread-safe singleton. typedef std::map context_map_type; //!< Type of mContextMap. context_map_type mContextMap; //!< Map context (ie, "snapshot" or "image") to last used folder. std::string mContext; //!< Some key to indicate the context (remembers the folder per key). diff --git a/indra/plugins/filepicker/CMakeLists.txt b/indra/plugins/filepicker/CMakeLists.txt index d3b233e01..13714e89f 100644 --- a/indra/plugins/filepicker/CMakeLists.txt +++ b/indra/plugins/filepicker/CMakeLists.txt @@ -28,12 +28,16 @@ if(NOT WORD_SIZE EQUAL 32) endif (NOT WORD_SIZE EQUAL 32) set(basic_plugin_filepicker_SOURCE_FILES - basic_plugin_filepicker.cpp + basic_plugin_filepicker.cpp + legacy.cpp llfilepicker.cpp + lldirpicker.cpp ) set(basic_plugin_filepicker_HEADER_FILES + legacy.h llfilepicker.h + lldirpicker.h ) set_source_files_properties(${basic_plugin_filepicker_HEADER_FILES} diff --git a/indra/plugins/filepicker/basic_plugin_filepicker.cpp b/indra/plugins/filepicker/basic_plugin_filepicker.cpp index b954e27b4..1201c3f71 100644 --- a/indra/plugins/filepicker/basic_plugin_filepicker.cpp +++ b/indra/plugins/filepicker/basic_plugin_filepicker.cpp @@ -36,6 +36,7 @@ #include "linden_common.h" #include "basic_plugin_base.h" #include "llfilepicker.h" +#include "lldirpicker.h" class FilepickerPlugin : public BasicPluginBase { @@ -229,9 +230,14 @@ void FilepickerPlugin::receiveMessage(char const* message_string) std::string type = message_in.getValue("type"); std::string filter = message_in.getValue("filter"); std::string folder = message_in.getValue("folder"); + bool get_directory = (filter == "directory"); bool canceled; - if (type == "save") + if (get_directory) + { + canceled = !LLDirPicker::instance().getDir(&folder); + } + else if (type == "save") { canceled = !LLFilePicker::instance().getSaveFile(str2savefilter(filter), message_in.getValue("default"), folder); } @@ -254,9 +260,16 @@ void FilepickerPlugin::receiveMessage(char const* message_string) LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "done"); message.setValue("perseus", "unblock"); LLSD filenames; - for (std::string filename = LLFilePicker::instance().getFirstFile(); !filename.empty(); filename = LLFilePicker::instance().getNextFile()) + if (get_directory) { - filenames.append(filename); + filenames.append(LLDirPicker::instance().getDirName()); + } + else + { + for (std::string filename = LLFilePicker::instance().getFirstFile(); !filename.empty(); filename = LLFilePicker::instance().getNextFile()) + { + filenames.append(filename); + } } message.setValueLLSD("filenames", filenames); sendMessage(message); diff --git a/indra/plugins/filepicker/legacy.cpp b/indra/plugins/filepicker/legacy.cpp new file mode 100644 index 000000000..f89862061 --- /dev/null +++ b/indra/plugins/filepicker/legacy.cpp @@ -0,0 +1,112 @@ +/** + * @file legacy.cpp + * @brief Helper stubs to keep the picker files as much as possible equal to their original. + * + * Copyright (c) 2011, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * 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. + * + * CHANGELOG + * and additional copyright holders. + * + * 11/05/2011 + * - Initial version, written by Aleric Inglewood @ SL + */ + +#include "legacy.h" +#include "basic_plugin_base.h" // For PLS_INFOS etc. + +// Translation map. +translation_map_type translation_map; + +namespace translation +{ + std::string getString(char const* key) + { + translation_map_type::iterator iter = translation_map.find(key); + return (iter != translation_map.end()) ? iter->second : key; + } + + void add(std::string const& key, std::string const& translation) + { + PLS_DEBUGS << "Adding translation \"" << key << "\" --> \"" << translation << "\"" << PLS_ENDL; + translation_map[key] = translation; + } +} + +#if LL_GTK +namespace LLWindowSDL { + bool ll_try_gtk_init(void) + { + static BOOL done_gtk_diag = FALSE; + static BOOL gtk_is_good = FALSE; + static BOOL done_setlocale = FALSE; + static BOOL tried_gtk_init = FALSE; + + if (!done_setlocale) + { + PLS_INFOS << "Starting GTK Initialization." << PLS_ENDL; + //maybe_lock_display(); + gtk_disable_setlocale(); + //maybe_unlock_display(); + done_setlocale = TRUE; + } + + if (!tried_gtk_init) + { + tried_gtk_init = TRUE; + if (!g_thread_supported ()) g_thread_init (NULL); + //maybe_lock_display(); + gtk_is_good = gtk_init_check(NULL, NULL); + //maybe_unlock_display(); + if (!gtk_is_good) + PLS_WARNS << "GTK Initialization failed." << PLS_ENDL; + } + if (gtk_is_good && !done_gtk_diag) + { + PLS_INFOS << "GTK Initialized." << PLS_ENDL; + PLS_INFOS << "- Compiled against GTK version " + << GTK_MAJOR_VERSION << "." + << GTK_MINOR_VERSION << "." + << GTK_MICRO_VERSION << PLS_ENDL; + PLS_INFOS << "- Running against GTK version " + << gtk_major_version << "." + << gtk_minor_version << "." + << gtk_micro_version << PLS_ENDL; + //maybe_lock_display(); + const gchar* gtk_warning = gtk_check_version( + GTK_MAJOR_VERSION, + GTK_MINOR_VERSION, + GTK_MICRO_VERSION); + //maybe_unlock_display(); + if (gtk_warning) + { + PLS_WARNS << "- GTK COMPATIBILITY WARNING: " << gtk_warning << PLS_ENDL; + gtk_is_good = FALSE; + } + else + { + PLS_INFOS << "- GTK version is good." << PLS_ENDL; + } + done_gtk_diag = TRUE; + } + return gtk_is_good; + } +} +#endif + diff --git a/indra/plugins/filepicker/legacy.h b/indra/plugins/filepicker/legacy.h new file mode 100644 index 000000000..253a99280 --- /dev/null +++ b/indra/plugins/filepicker/legacy.h @@ -0,0 +1,79 @@ +/** + * @file legacy.h + * @brief Declarations of legacy.cpp. + * + * Copyright (c) 2011, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * 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. + * + * CHANGELOG + * and additional copyright holders. + * + * 11/05/2011 + * - Initial version, written by Aleric Inglewood @ SL + */ + +#include +#include +#include "stdtypes.h" // BOOL + +// Translation map. +typedef std::map translation_map_type; +extern translation_map_type translation_map; + +namespace translation +{ + std::string getString(char const* key); + void add(std::string const& key, std::string const& translation); +} + +#if LL_GTK +namespace LLWindowSDL { + bool ll_try_gtk_init(void); +} +#endif + +// A temporary hack to minimize the number of changes from the original llfilepicker.cpp. +#define LLTrans translation + +#if LL_DARWIN +#include + +// AssertMacros.h does bad things. +#undef verify +#undef check +#undef require + +#include "llstring.h" +#endif + +// Need commdlg.h for OPENFILENAMEA +#ifdef LL_WINDOWS +#include +#endif + +// mostly for Linux, possible on others +#if LL_GTK +# include "gtk/gtk.h" +#endif // LL_GTK + +// also mostly for Linux, for some X11-specific filepicker usability tweaks +#if LL_X11 +#include "SDL/SDL_syswm.h" +#endif + diff --git a/indra/newview/lldirpicker.cpp b/indra/plugins/filepicker/lldirpicker.cpp similarity index 92% rename from indra/newview/lldirpicker.cpp rename to indra/plugins/filepicker/lldirpicker.cpp index 3840b52bd..39dff05e9 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/plugins/filepicker/lldirpicker.cpp @@ -30,16 +30,12 @@ * $/LicenseInfo$ */ -#include "llviewerprecompiledheaders.h" - +#include "linden_common.h" #include "lldirpicker.h" -//#include "llviewermessage.h" -#include "llworld.h" -#include "llviewerwindow.h" -#include "llkeyboard.h" -#include "lldir.h" -#include "llframetimer.h" -#include "lltrans.h" +#include "llpreprocessor.h" +#include "llerror.h" +#include "basic_plugin_base.h" // For PLS_INFOS etc. +#include "legacy.h" #if LL_LINUX || LL_SOLARIS # include "llfilepicker.h" @@ -77,9 +73,6 @@ BOOL LLDirPicker::getDir(std::string* filename) } BOOL success = FALSE; - // Modal, so pause agent - send_agent_pause(); - BROWSEINFO bi; memset(&bi, 0, sizeof(bi)); @@ -109,10 +102,6 @@ BOOL LLDirPicker::getDir(std::string* filename) ::OleUninitialize(); - send_agent_resume(); - - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); return success; } @@ -237,20 +226,15 @@ BOOL LLDirPicker::getDir(std::string* filename) // mNavOptions.saveFileName - // Modal, so pause agent - send_agent_pause(); { error = doNavChooseDialog(); } - send_agent_resume(); if (error == noErr) { if (mDir.length() > 0) success = true; } - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); return success; } diff --git a/indra/newview/lldirpicker.h b/indra/plugins/filepicker/lldirpicker.h similarity index 100% rename from indra/newview/lldirpicker.h rename to indra/plugins/filepicker/lldirpicker.h diff --git a/indra/plugins/filepicker/llfilepicker.cpp b/indra/plugins/filepicker/llfilepicker.cpp index 8028665e3..48069e88c 100644 --- a/indra/plugins/filepicker/llfilepicker.cpp +++ b/indra/plugins/filepicker/llfilepicker.cpp @@ -35,92 +35,7 @@ #include "llpreprocessor.h" #include "llerror.h" #include "basic_plugin_base.h" // For PLS_INFOS etc. - -#if LL_SDL -#include "llwindowsdl.h" // for some X/GTK utils to help with filepickers -#endif // LL_SDL - -// Translation map. -typedef std::map translation_map_type; -translation_map_type translation_map; - -// A temporary hack to minimize the number of changes from the original llfilepicker.cpp. -#define LLTrans translation -namespace translation -{ - std::string getString(char const* key) - { - translation_map_type::iterator iter = translation_map.find(key); - return (iter != translation_map.end()) ? iter->second : key; - } - - void add(std::string const& key, std::string const& translation) - { - PLS_DEBUGS << "Adding translation \"" << key << "\" --> \"" << translation << "\"" << PLS_ENDL; - translation_map[key] = translation; - } -} - -#if LL_GTK -namespace LLWindowSDL { - bool ll_try_gtk_init(void) - { - static BOOL done_gtk_diag = FALSE; - static BOOL gtk_is_good = FALSE; - static BOOL done_setlocale = FALSE; - static BOOL tried_gtk_init = FALSE; - - if (!done_setlocale) - { - PLS_INFOS << "Starting GTK Initialization." << PLS_ENDL; - //maybe_lock_display(); - gtk_disable_setlocale(); - //maybe_unlock_display(); - done_setlocale = TRUE; - } - - if (!tried_gtk_init) - { - tried_gtk_init = TRUE; - if (!g_thread_supported ()) g_thread_init (NULL); - //maybe_lock_display(); - gtk_is_good = gtk_init_check(NULL, NULL); - //maybe_unlock_display(); - if (!gtk_is_good) - PLS_WARNS << "GTK Initialization failed." << PLS_ENDL; - } - if (gtk_is_good && !done_gtk_diag) - { - PLS_INFOS << "GTK Initialized." << PLS_ENDL; - PLS_INFOS << "- Compiled against GTK version " - << GTK_MAJOR_VERSION << "." - << GTK_MINOR_VERSION << "." - << GTK_MICRO_VERSION << PLS_ENDL; - PLS_INFOS << "- Running against GTK version " - << gtk_major_version << "." - << gtk_minor_version << "." - << gtk_micro_version << PLS_ENDL; - //maybe_lock_display(); - const gchar* gtk_warning = gtk_check_version( - GTK_MAJOR_VERSION, - GTK_MINOR_VERSION, - GTK_MICRO_VERSION); - //maybe_unlock_display(); - if (gtk_warning) - { - PLS_WARNS << "- GTK COMPATIBILITY WARNING: " << gtk_warning << PLS_ENDL; - gtk_is_good = FALSE; - } - else - { - PLS_INFOS << "- GTK version is good." << PLS_ENDL; - } - done_gtk_diag = TRUE; - } - return gtk_is_good; - } -} -#endif +#include "legacy.h" // // Globals @@ -290,7 +205,7 @@ bool LLFilePickerBase::setupFilter(ELoadFilter filter) return res; } -// FIXME: Use folder +// AIFIXME: Use folder bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { if( mLocked ) @@ -309,9 +224,6 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder setupFilter(filter); - // Modal, so pause agent - send_agent_pause(); - reset(); // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! @@ -321,14 +233,11 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); mFiles.push_back(filename); } - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); return success; } -// FIXME: Use folder +// AIFIXME: Use folder bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) { if( mLocked ) @@ -350,8 +259,6 @@ bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string cons reset(); - // Modal, so pause agent - send_agent_pause(); // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! success = GetOpenFileName(&mOFN); // pauses until ok or cancel. if( success ) @@ -384,14 +291,11 @@ bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string cons } } } - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); return success; } -// FIXME: Use folder +// AIFIXME: Use folder bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) { if( mLocked ) @@ -783,8 +687,6 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena reset(); - // Modal, so pause agent - send_agent_pause(); { // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! success = GetSaveFileName(&mOFN); @@ -795,10 +697,7 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena } gKeyboard->resetKeys(); } - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); return success; } @@ -1137,7 +1036,7 @@ OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, const std::string return error; } -// FIXME: Use folder +// AIFIXME: Use folder bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { if( mLocked ) @@ -1150,24 +1049,19 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder reset(); mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; - // Modal, so pause agent - send_agent_pause(); { error = doNavChooseDialog(filter); } - send_agent_resume(); if (error == noErr) { if (getFileCount()) success = true; } - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); return success; } -// FIXME: Use folder +// AIFIXME: Use folder bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) { if( mLocked ) @@ -1180,12 +1074,9 @@ bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string cons reset(); mNavOptions.optionFlags |= kNavAllowMultipleFiles; - // Modal, so pause agent - send_agent_pause(); { error = doNavChooseDialog(filter); } - send_agent_resume(); if (error == noErr) { if (getFileCount()) @@ -1194,12 +1085,10 @@ bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string cons mLocked = TRUE; } - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); return success; } -// FIXME: Use folder +// AIFIXME: Use folder bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) { if( mLocked ) @@ -1211,20 +1100,15 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; - // Modal, so pause agent - send_agent_pause(); { error = doNavSaveDialog(filter, filename); } - send_agent_resume(); if (error == noErr) { if (getFileCount()) success = true; } - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); return success; } @@ -1601,7 +1485,7 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena return FALSE; } -// FIXME: Use folder +// AIFIXME: Use folder bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { reset(); diff --git a/indra/plugins/filepicker/llfilepicker.h b/indra/plugins/filepicker/llfilepicker.h index 4e1a52a7e..f8e17719e 100644 --- a/indra/plugins/filepicker/llfilepicker.h +++ b/indra/plugins/filepicker/llfilepicker.h @@ -39,37 +39,8 @@ #ifndef LL_LLFILEPICKER_H #define LL_LLFILEPICKER_H -#include "stdtypes.h" -#include +#include "legacy.h" #include -#include - -#if LL_DARWIN -#include - -// AssertMacros.h does bad things. -#undef verify -#undef check -#undef require - -#include "llstring.h" - -#endif - -// Need commdlg.h for OPENFILENAMEA -#ifdef LL_WINDOWS -#include -#endif - -// mostly for Linux, possible on others -#if LL_GTK -# include "gtk/gtk.h" -#endif // LL_GTK - -// also mostly for Linux, for some X11-specific filepicker usability tweaks -#if LL_X11 -#include "SDL/SDL_syswm.h" -#endif // This class is used as base class of a singleton and is therefore not // allowed to have any static members or static local variables! @@ -246,9 +217,4 @@ private: LLFilePicker() { } }; -namespace translation -{ - void add(std::string const& key, std::string const& translation); -} - #endif From 38b33328e604d32a5bf62dda10062bd50a58d07d Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 11 May 2011 03:47:42 +0200 Subject: [PATCH 14/87] Redo the copyconstructor hack for AI*Access objects. The previous hack wasn't thread-safe: read-only access would access the reference counter multiple times at the same time, which therefore would have to be thread-local to ever work. The current solution just disables the calls to lock/unlock for copyconstructed objects, which works if the copyconstructed object isn't used anymore after the original is destructed. This is the case then the copy construction only happens upon passing a temporary to a function, which is the case. --- indra/llcommon/aithreadsafe.h | 43 +++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h index 795c15e0a..810aa8c2f 100644 --- a/indra/llcommon/aithreadsafe.h +++ b/indra/llcommon/aithreadsafe.h @@ -39,6 +39,11 @@ // g++ 4.2.x (and before?) have the bug that when you try to pass a temporary // to a function taking a const reference, it still calls the copy constructor. // Define this to hack around that. +// Note that the chosen solution ONLY works for copying an AI*Access object that +// is passed to a function: the lifetime of the copied object must not be longer +// than the original (or at least, it shouldn't be used anymore after the +// original is destructed). This will be guaranteed if the code also compiles +// on a compiler that doesn't need this hack. #define AI_NEED_ACCESS_CC (defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || (__GNUC__ < 4))) template struct AIReadAccessConst; @@ -71,10 +76,6 @@ protected: // Accessors. T const* ptr() const { return reinterpret_cast(mMemory); } T* ptr() { return reinterpret_cast(mMemory); } - -#if AI_NEED_ACCESS_CC - int mAccessCopyCount; -#endif }; /** @@ -246,11 +247,11 @@ struct AIReadAccessConst AIReadAccessConst(AIThreadSafe const& wrapper) : mWrapper(const_cast&>(wrapper)), mState(readlocked) +#if AI_NEED_ACCESS_CC + , mIsCopyConstructed(false) +#endif { mWrapper.mRWLock.rdlock(); -#if AI_NEED_ACCESS_CC - mWrapper.mAccessCopyCount = 1; -#endif } //! Destruct the AI*Access object. @@ -258,7 +259,7 @@ struct AIReadAccessConst ~AIReadAccessConst() { #if AI_NEED_ACCESS_CC - if (--(this->mWrapper.mAccessCopyCount) > 0) return; + if (mIsCopyConstructed) return; #endif if (mState == readlocked) mWrapper.mRWLock.rdunlock(); @@ -282,13 +283,14 @@ protected: AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to. state_type const mState; //!< The lock state that mWrapper is in. -#if !AI_NEED_ACCESS_CC +#if AI_NEED_ACCESS_CC + bool mIsCopyConstructed; +public: + AIReadAccessConst(AIReadAccessConst const& orig) : mWrapper(orig.mWrapper), mState(orig.mState), mIsCopyConstructed(true) { } +#else private: // Disallow copy constructing directly. AIReadAccessConst(AIReadAccessConst const&); -#else -public: - AIReadAccessConst(AIReadAccessConst const& orig) : mWrapper(orig.mWrapper), mState(orig.mState) { mWrapper.mAccessCopyCount++; } #endif }; @@ -482,11 +484,11 @@ struct AIAccess { //! Construct a AIAccess from a non-constant AIThreadSafeSimple. AIAccess(AIThreadSafeSimple& wrapper) : mWrapper(wrapper) +#if AI_NEED_ACCESS_CC + , mIsCopyConstructed(false) +#endif { this->mWrapper.mMutex.lock(); -#if AI_NEED_ACCESS_CC - this->mWrapper.mAccessCopyCount = 1; -#endif } //! Access the underlaying object for (read and) write access. @@ -498,7 +500,7 @@ struct AIAccess ~AIAccess() { #if AI_NEED_ACCESS_CC - if (--(this->mWrapper.mAccessCopyCount) > 0) return; + if (mIsCopyConstructed) return; #endif this->mWrapper.mMutex.unlock(); } @@ -506,13 +508,14 @@ struct AIAccess protected: AIThreadSafeSimple& mWrapper; //!< Reference to the object that we provide access to. -#if !AI_NEED_ACCESS_CC +#if AI_NEED_ACCESS_CC + bool mIsCopyConstructed; +public: + AIAccess(AIAccess const& orig) : mWrapper(orig.mWrapper), mIsCopyConstructed(true) { } +#else private: // Disallow copy constructing directly. AIAccess(AIAccess const&); -#else -public: - AIAccess(AIAccess const& orig) : mWrapper(orig.mWrapper) { this->mWrapper.mAccessCopyCount++; } #endif }; From d1d69944193770f36e11aed6a8be0af8414c14ca Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 10 May 2011 03:30:59 -0500 Subject: [PATCH 15/87] Full v2.6 renderer. --- indra/llcommon/indra_constants.h | 18 +- indra/llcommon/llapr.cpp | 2 +- indra/llmath/llcamera.cpp | 35 +- indra/llmath/llcamera.h | 14 + indra/llprimitive/llprimitive.cpp | 77 + indra/llprimitive/llprimitive.h | 26 +- indra/llrender/llrender.cpp | 3 +- indra/llrender/llrender.h | 1 + indra/llrender/llrendersphere.cpp | 86 +- indra/llrender/llrendersphere.h | 4 + indra/newview/app_settings/settings.xml | 831 ++++- .../shaders/class1/deferred/alphaF.glsl | 70 +- .../shaders/class1/deferred/alphaV.glsl | 64 +- .../shaders/class1/deferred/avatarAlphaF.glsl | 2 +- .../shaders/class1/deferred/avatarAlphaV.glsl | 25 +- .../shaders/class1/deferred/avatarF.glsl | 5 +- .../class1/deferred/avatarShadowF.glsl | 4 +- .../class1/deferred/avatarShadowV.glsl | 3 +- .../shaders/class1/deferred/avatarV.glsl | 2 - .../shaders/class1/deferred/blurLightF.glsl | 57 +- .../shaders/class1/deferred/bumpF.glsl | 16 +- .../shaders/class1/deferred/bumpV.glsl | 3 - .../shaders/class1/deferred/diffuseF.glsl | 12 +- .../shaders/class1/deferred/diffuseV.glsl | 7 +- .../shaders/class1/deferred/fullbrightF.glsl | 37 +- .../shaders/class1/deferred/fullbrightV.glsl | 2 +- .../shaders/class1/deferred/giF.glsl | 166 + .../shaders/class1/deferred/giV.glsl | 22 + .../shaders/class1/deferred/impostorF.glsl | 5 +- .../shaders/class1/deferred/impostorV.glsl | 4 - .../shaders/class1/deferred/luminanceF.glsl | 15 + .../shaders/class1/deferred/luminanceV.glsl | 20 + .../class1/deferred/multiPointLightF.glsl | 62 +- .../class1/deferred/multiSpotLightF.glsl | 225 ++ .../shaders/class1/deferred/pointLightF.glsl | 66 +- .../shaders/class1/deferred/pointLightV.glsl | 6 +- .../class1/deferred/postDeferredF.glsl | 57 + .../class1/deferred/postDeferredV.glsl | 17 + .../shaders/class1/deferred/postgiF.glsl | 80 + .../shaders/class1/deferred/postgiV.glsl | 17 + .../shaders/class1/deferred/shadowF.glsl | 3 + .../shaders/class1/deferred/shadowV.glsl | 10 +- .../shaders/class1/deferred/softenLightF.glsl | 108 +- .../shaders/class1/deferred/spotLightF.glsl | 167 + .../shaders/class1/deferred/sunLightF.glsl | 130 +- .../class1/deferred/sunLightSSAOF.glsl | 124 + .../shaders/class1/deferred/terrainF.glsl | 7 +- .../shaders/class1/deferred/terrainV.glsl | 2 - .../shaders/class1/deferred/treeF.glsl | 5 +- .../shaders/class1/deferred/treeV.glsl | 3 - .../shaders/class1/deferred/waterF.glsl | 58 +- .../shaders/class1/lighting/lightFuncV.glsl | 7 +- .../shaders/class2/deferred/alphaF.glsl | 127 + .../shaders/class2/deferred/alphaV.glsl | 103 + .../shaders/class2/deferred/avatarAlphaF.glsl | 98 + .../shaders/class2/deferred/avatarAlphaV.glsl | 83 + .../shaders/class2/deferred/blurLightF.glsl | 81 + .../shaders/class2/deferred/blurLightV.glsl | 17 + .../shaders/class2/deferred/edgeF.glsl | 63 + .../shaders/class2/deferred/edgeV.glsl | 17 + .../class2/deferred/multiSpotLightF.glsl | 236 ++ .../class2/deferred/postDeferredF.glsl | 59 + .../class2/deferred/postDeferredV.glsl | 17 + .../shaders/class2/deferred/softenLightF.glsl | 344 ++ .../shaders/class2/deferred/softenLightV.glsl | 24 + .../shaders/class2/deferred/spotLightF.glsl | 185 ++ .../shaders/class2/deferred/sunLightF.glsl | 197 ++ .../class2/deferred/sunLightSSAOF.glsl | 257 ++ .../shaders/class2/deferred/sunLightV.glsl | 25 + .../shaders/class2/effects/blurF.glsl | 1 + .../shaders/class2/lighting/sumLightsV.glsl | 9 +- .../class3/deferred/giDownsampleF.glsl | 86 + .../class3/deferred/giDownsampleV.glsl | 17 + .../shaders/class3/deferred/giF.glsl | 191 ++ .../shaders/class3/deferred/giFinalF.glsl | 25 + .../shaders/class3/deferred/giFinalV.glsl | 17 + .../shaders/class3/deferred/giV.glsl | 22 + .../shaders/class3/deferred/luminanceF.glsl | 19 + .../shaders/class3/deferred/luminanceV.glsl | 20 + .../class3/deferred/postDeferredF.glsl | 80 + .../class3/deferred/postDeferredV.glsl | 17 + .../shaders/class3/deferred/postgiF.glsl | 69 + .../shaders/class3/deferred/postgiV.glsl | 17 + .../shaders/class3/deferred/softenLightF.glsl | 356 ++ .../shaders/class3/deferred/softenLightV.glsl | 24 + .../shaders/class3/deferred/treeF.glsl | 19 + .../shaders/class3/lighting/sumLightsV.glsl | 27 +- indra/newview/lldrawpool.cpp | 7 - indra/newview/lldrawpool.h | 4 +- indra/newview/lldrawpoolalpha.cpp | 8 +- indra/newview/lldrawpoolavatar.cpp | 12 +- indra/newview/lldrawpoolavatar.h | 2 - indra/newview/lldrawpoolclouds.cpp | 3 - indra/newview/lldrawpoolclouds.h | 1 - indra/newview/lldrawpoolground.cpp | 4 - indra/newview/lldrawpoolground.h | 1 - indra/newview/lldrawpoolsky.cpp | 5 +- indra/newview/lldrawpoolsky.h | 1 - indra/newview/lldrawpooltree.cpp | 21 +- indra/newview/lldrawpoolwater.cpp | 114 +- indra/newview/lldrawpoolwater.h | 7 +- indra/newview/llpaneldisplay.cpp | 1 - indra/newview/llviewercontrol.cpp | 45 +- indra/newview/llviewerdisplay.cpp | 7 +- indra/newview/llviewershadermgr.cpp | 151 +- indra/newview/llviewershadermgr.h | 30 + indra/newview/llviewerstats.cpp | 2 +- indra/newview/llvoavatar.cpp | 4 +- indra/newview/llvoavatar.h | 2 +- indra/newview/llvopartgroup.cpp | 4 +- indra/newview/llvosky.cpp | 2 +- indra/newview/llvotree.cpp | 12 +- indra/newview/llvovolume.cpp | 147 + indra/newview/llvovolume.h | 14 + indra/newview/llvowater.cpp | 16 +- indra/newview/pipeline.cpp | 2852 +++++++++++++---- indra/newview/pipeline.h | 45 +- 117 files changed, 8031 insertions(+), 1234 deletions(-) create mode 100644 indra/newview/app_settings/shaders/class1/deferred/giF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/giV.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl create mode 100644 indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giF.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giV.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/treeF.glsl diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 3725b1d84..a95b6499d 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -48,7 +48,7 @@ class LLUUID; #define PHYSICS_TIMESTEP (1.f / 45.f) const F32 COLLISION_TOLERANCE = 0.1f; -const F32 HALF_COLLISION_TOLERANCE = COLLISION_TOLERANCE * 0.5f; +const F32 HALF_COLLISION_TOLERANCE = 0.05f; // Time constants const U32 HOURS_PER_LINDEN_DAY = 4; @@ -99,9 +99,9 @@ const F32 MIN_AGENT_WIDTH = 0.40f; const F32 DEFAULT_AGENT_WIDTH = 0.60f; const F32 MAX_AGENT_WIDTH = 0.80f; -const F32 MIN_AGENT_HEIGHT = 1.3f - 2.0f * COLLISION_TOLERANCE; +const F32 MIN_AGENT_HEIGHT = 1.1f; const F32 DEFAULT_AGENT_HEIGHT = 1.9f; -const F32 MAX_AGENT_HEIGHT = 2.65f - 2.0f * COLLISION_TOLERANCE; +const F32 MAX_AGENT_HEIGHT = 2.45f; // For linked sets const S32 MAX_CHILDREN_PER_TASK = 255; @@ -252,9 +252,6 @@ const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only const U8 SIM_ACCESS_DOWN = 254; const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; -// group constants -const S32 DEFAULT_MAX_AGENT_GROUPS = 25; - // attachment constants const S32 MAX_AGENT_ATTACHMENTS = 38; const U8 ATTACHMENT_ADD = 0x80; @@ -293,6 +290,7 @@ const U8 UPD_UNIFORM = 0x10; // used with UPD_SCALE // Agent Update Flags (U8) const U8 AU_FLAGS_NONE = 0x00; const U8 AU_FLAGS_HIDETITLE = 0x01; +const U8 AU_FLAGS_CLIENT_AUTOPILOT = 0x02; // start location constants const U32 START_LOCATION_ID_LAST = 0; @@ -306,6 +304,14 @@ const U32 START_LOCATION_ID_COUNT = 6; // group constants const U32 GROUP_MIN_SIZE = 2; +// gMaxAgentGroups is now sent by login.cgi, which +// looks it up from globals.xml. +// +// For now we need an old default value however, +// so the viewer can be deployed ahead of login.cgi. +// +const S32 DEFAULT_MAX_AGENT_GROUPS = 25; + // radius within which a chat message is fully audible const F32 CHAT_WHISPER_RADIUS = 10.f; const F32 CHAT_NORMAL_RADIUS = 20.f; diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 9595707cb..d2169d65e 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -81,7 +81,7 @@ bool ll_apr_warn_status(apr_status_t status) { if(APR_SUCCESS == status) return false; char buf[MAX_STRING]; /* Flawfinder: ignore */ - apr_strerror(status, buf, MAX_STRING); + apr_strerror(status, buf, sizeof(buf)); LL_WARNS("APR") << "APR: " << buf << LL_ENDL; return true; } diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp index e6b6797c6..01528e5f1 100644 --- a/indra/llmath/llcamera.cpp +++ b/indra/llmath/llcamera.cpp @@ -45,7 +45,8 @@ LLCamera::LLCamera() : mNearPlane(DEFAULT_NEAR_PLANE), mFarPlane(DEFAULT_FAR_PLANE), mFixedDistance(-1.f), - mPlaneCount(6) + mPlaneCount(6), + mFrustumCornerDist(0.f) { calculateFrustumPlanes(); } @@ -55,7 +56,8 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p LLCoordFrame(), mViewHeightInPixels(view_height_in_pixels), mFixedDistance(-1.f), - mPlaneCount(6) + mPlaneCount(6), + mFrustumCornerDist(0.f) { mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO); mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE); @@ -178,7 +180,7 @@ S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius) U8 mask = 0; S32 result = 2; - if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist) + /*if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist) { //box is larger than frustum, check frustum quads against box planes static const LLVector3 dir[] = @@ -241,11 +243,15 @@ S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius) result = 1; } } - else + else*/ { for (U32 i = 0; i < mPlaneCount; i++) { mask = mAgentPlanes[i].mask; + if (mask == 0xff) + { + continue; + } LLPlane p = mAgentPlanes[i].p; LLVector3 n = LLVector3(p); float d = p.mV[3]; @@ -294,6 +300,10 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& r } mask = mAgentPlanes[i].mask; + if (mask == 0xff) + { + continue; + } LLPlane p = mAgentPlanes[i].p; LLVector3 n = LLVector3(p); float d = p.mV[3]; @@ -437,6 +447,11 @@ int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) int res = 2; for (int i = 0; i < 6; i++) { + if (mAgentPlanes[i].mask == 0xff) + { + continue; + } + float d = mAgentPlanes[i].p.dist(sphere_center); if (d > radius) @@ -622,9 +637,19 @@ U8 LLCamera::calcPlaneMask(const LLPlane& plane) return mask; } +void LLCamera::ignoreAgentFrustumPlane(S32 idx) +{ + if (idx < 0 || idx > (S32) mPlaneCount) + { + return; + } + + mAgentPlanes[idx].mask = 0xff; + mAgentPlanes[idx].p.clearVec(); +} + void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) { - for (int i = 0; i < 8; i++) { mAgentFrustum[i] = frust[i]; diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index 85b93dfc9..69a24e1dd 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -84,6 +84,17 @@ public: PLANE_TOP_MASK = (1<mLightTexture != mLightTexture) ) + { + return false; + } + + if ( (param->mParams != mParams ) ) + { + return false; + } + + return true; +} + +void LLLightImageParams::copy(const LLNetworkData& data) +{ + const LLLightImageParams *param = (LLLightImageParams*)&data; + mLightTexture = param->mLightTexture; + mParams = param->mParams; +} + + + +LLSD LLLightImageParams::asLLSD() const +{ + LLSD sd; + + sd["texture"] = mLightTexture; + sd["params"] = mParams.getValue(); + + return sd; +} + +bool LLLightImageParams::fromLLSD(LLSD& sd) +{ + if (sd.has("texture")) + { + setLightTexture( sd["texture"] ); + setParams( LLVector3( sd["params"] ) ); + return true; + } + + return false; +} diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 03769a87a..fdd765a4a 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -107,7 +107,8 @@ public: { PARAMS_FLEXIBLE = 0x10, PARAMS_LIGHT = 0x20, - PARAMS_SCULPT = 0x30 + PARAMS_SCULPT = 0x30, + PARAMS_LIGHT_IMAGE = 0x40, }; public: @@ -267,6 +268,29 @@ public: U8 getSculptType() const { return mSculptType; } }; +class LLLightImageParams : public LLNetworkData +{ +protected: + LLUUID mLightTexture; + LLVector3 mParams; + +public: + LLLightImageParams(); + /*virtual*/ BOOL pack(LLDataPacker &dp) const; + /*virtual*/ BOOL unpack(LLDataPacker &dp); + /*virtual*/ bool operator==(const LLNetworkData& data) const; + /*virtual*/ void copy(const LLNetworkData& data); + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + void setLightTexture(const LLUUID& id) { mLightTexture = id; } + LLUUID getLightTexture() const { return mLightTexture; } + bool isLightSpotlight() const { return mLightTexture.notNull(); } + void setParams(const LLVector3& params) { mParams = params; } + LLVector3 getParams() const { return mParams; } + +}; class LLPrimitive : public LLXform diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 5bc77f437..909c5d8ad 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -45,6 +45,7 @@ LLRender gGL; // Handy copies of last good GL matrices F64 gGLModelView[16]; F64 gGLLastModelView[16]; +F64 gGLLastProjection[16]; F64 gGLProjection[16]; S32 gGLViewport[4]; @@ -144,7 +145,7 @@ void LLTexUnit::activate(void) { if (mIndex < 0) return; - if (gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty) + if ((S32)gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty) { glActiveTextureARB(GL_TEXTURE0_ARB + mIndex); gGL.mCurrTextureUnitIndex = mIndex; diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index ab0935bbe..d0c99b4f9 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -369,6 +369,7 @@ private: extern F64 gGLModelView[16]; extern F64 gGLLastModelView[16]; +extern F64 gGLLastProjection[16]; extern F64 gGLProjection[16]; extern S32 gGLViewport[4]; diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp index e22b75392..212963f27 100644 --- a/indra/llrender/llrendersphere.cpp +++ b/indra/llrender/llrendersphere.cpp @@ -68,45 +68,6 @@ void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks) } -// lat = 0 is Z-axis -// lon = 0, lat = 90 at X-axis -void lat2xyz(LLVector3 * result, F32 lat, F32 lon) -{ - // Convert a latitude and longitude to x,y,z on a normal sphere and return it in result - F32 r; - result->mV[VX] = (F32) (cos(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD)); - result->mV[VY] = (F32) (sin(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD)); - r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f); - if (r == 1.0f) - { - result->mV[VZ] = 0.0f; - } - else - { - result->mV[VZ] = (F32) pow(1 - r*r, 0.5f); - if (lat > 90.01) - { - result->mV[VZ] *= -1.0; - } - } -} - -void lat2xyz_rad(LLVector3 * result, F32 lat, F32 lon) -{ - // Convert a latitude and longitude to x,y,z on a normal sphere and return it in result - F32 r; - result->mV[VX] = (F32) (cos(lon) * sin(lat)); - result->mV[VY] = (F32) (sin(lon) * sin(lat)); - r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f); - if (r == 1.0f) - result->mV[VZ] = 0.0f; - else - { - result->mV[VZ] = (F32) pow(1 - r*r, 0.5f); - if (lat > F_PI_BY_TWO) result->mV[VZ] *= -1.0; - } -} - // 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 @@ -181,3 +142,50 @@ void LLRenderSphere::render() { glCallList(mDList[0]); } + +inline LLVector3 polar_to_cart(F32 latitude, F32 longitude) +{ + return LLVector3(sin(F_TWO_PI * latitude) * cos(F_TWO_PI * longitude), + sin(F_TWO_PI * latitude) * sin(F_TWO_PI * longitude), + cos(F_TWO_PI * latitude)); +} + + +void LLRenderSphere::renderGGL() +{ + S32 const LATITUDE_SLICES = 20; + S32 const LONGITUDE_SLICES = 30; + + if (mSpherePoints.empty()) + { + mSpherePoints.resize(LATITUDE_SLICES + 1); + for (S32 lat_i = 0; lat_i < LATITUDE_SLICES + 1; lat_i++) + { + mSpherePoints[lat_i].resize(LONGITUDE_SLICES + 1); + for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES + 1; lon_i++) + { + F32 lat = (F32)lat_i / LATITUDE_SLICES; + F32 lon = (F32)lon_i / LONGITUDE_SLICES; + + mSpherePoints[lat_i][lon_i] = polar_to_cart(lat, lon); + } + } + } + + gGL.begin(LLRender::TRIANGLES); + + for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++) + { + for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++) + { + gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV); + gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); + gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); + + gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); + gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); + gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i+1].mV); + } + } + gGL.end(); +} diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h index 617ee3e12..ebc71b614 100644 --- a/indra/llrender/llrendersphere.h +++ b/indra/llrender/llrendersphere.h @@ -52,6 +52,10 @@ public: 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 + +private: + std::vector< std::vector > mSpherePoints; }; extern LLRenderSphere gSphere; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b821681a3..3cf7e5547 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8908,7 +8908,7 @@ Type S32 Value - 35 + 12 RenderAvatarPhysicsLODFactor @@ -8943,21 +8943,6 @@ Value 1 - RenderShadowGaussian - - Comment - Gaussian coefficients for the two shadow/SSAO blurring passes (z component unused). - Persist - 1 - Type - Vector3 - Value - - 2.0 - 2.0 - 0.0 - - RenderShadowNearDist Comment @@ -8983,11 +8968,74 @@ Vector3 Value - 4.0 - 8.0 - 24.0 + 1.0 + 12.0 + 32.0 - + + RenderShadowSplitExponent + + Comment + Near clip plane split distances for shadow map frusta (x=perspective, y=ortho, z=transition rate). + Persist + 1 + Type + Vector3 + Value + + 3.0 + 3.0 + 2.0 + + + RenderShadowOrthoClipPlanes + + Comment + Near clip plane split distances for orthographic shadow map frusta. + Persist + 1 + Type + Vector3 + Value + + 4.0 + 8.0 + 24.0 + + + RenderShadowProjOffset + + Comment + Amount to scale distance to virtual origin of shadow perspective projection. + Persist + 1 + Type + F32 + Value + 2.0 + + RenderShadowSlopeThreshold + + Comment + Cutoff slope value for points to affect perspective shadow generation + Persist + 1 + Type + F32 + Value + 0.0 + + RenderShadowProjExponent + + Comment + Exponent applied to transition between ortho and perspective shadow projections based on viewing angle and light vector. + Persist + 1 + Type + F32 + Value + 0.5 + RenderSSAOScale Comment @@ -9008,7 +9056,7 @@ Type U32 Value - 60 + 200 RenderSSAOFactor @@ -9056,7 +9104,7 @@ Type F32 Value - 128 + 64 RenderCubeMap @@ -9146,7 +9194,175 @@ Value 0 - RenderDeferredAlphaSoften + + RenderGIRange + + Comment + Distance to cut off GI effect. + Persist + 1 + Type + F32 + Value + 96 + + + RenderGILuminance + + Comment + Luminance factor of global illumination contribution. + Persist + 1 + Type + F32 + Value + 0.075 + + + RenderGIBrightness + + Comment + Brightness factor of global illumination contribution. + Persist + 1 + Type + F32 + Value + 0.3 + + + RenderGINoise + + Comment + Noise of position sampling for GI photon mapping. + Persist + 1 + Type + F32 + Value + 0.7 + + + RenderGIAttenuation + + Comment + Distance attenuation factor for indirect lighting. + Persist + 1 + Type + F32 + Value + 0.1 + + + RenderGIBlurBrightness + + Comment + Brightness factor of global illumination blur effect. + Persist + 1 + Type + F32 + Value + 1.025 + + + RenderGIBlurEdgeWeight + + Comment + Edge weight for GI soften filter (sharpness). + Persist + 1 + Type + F32 + Value + 0.8 + + + RenderGIBlurIncrement + + Comment + Increment of scale for each pass of global illumination blur effect. + Persist + 1 + Type + F32 + Value + 0.8 + + + RenderLuminanceScale + + Comment + Luminance value scalar for darkening effect. + Persist + 1 + Type + F32 + Value + 1.0 + + + RenderSunLuminanceScale + + Comment + Sun Luminance value scalar for darkening effect. + Persist + 1 + Type + F32 + Value + 1.0 + + + RenderSunLuminanceOffset + + Comment + Sun Luminance value offset for darkening effect. + Persist + 1 + Type + F32 + Value + 0 + + + RenderLuminanceDetail + + Comment + Mipmap level to use for luminance + Persist + 1 + Type + F32 + Value + 16.0 + + + RenderEdgeDepthCutoff + + Comment + Cutoff for depth difference that amounts to an edge. + Persist + 1 + Type + F32 + Value + 0.01 + + RenderEdgeNormCutoff + + Comment + Cutoff for normal difference that amounts to an edge. + Persist + 1 + Type + F32 + Value + 0.25 + + + RenderDeferredAlphaSoften Comment Scalar for softening alpha surfaces (for soft particles). @@ -9168,9 +9384,249 @@ Value 4 - RenderDeferred - - Comment + RenderDeferredSpotShadowBias + + Comment + Bias value for spot shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + -64.0 + + RenderDeferredSpotShadowOffset + + Comment + Offset value for spot shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + 0.8 + + + RenderShadowBias + + Comment + Bias value for shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + -0.008 + + RenderShadowOffset + + Comment + Offset value for shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + 0.01 + + + RenderShadowBiasError + + Comment + Error scale for shadow bias (based on altitude). + Persist + 1 + Type + F32 + Value + 0 + + RenderShadowOffsetError + + Comment + Error scale for shadow offset (based on altitude). + Persist + 1 + Type + F32 + Value + 0 + + + RenderSpotLightsInNondeferred + + Comment + Whether to support projectors as spotlights when Lighting and Shadows is disabled + Persist + 1 + Type + Boolean + Value + 0 + + + RenderSpotShadowBias + + Comment + Bias value for shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + 0.0 + + RenderSpotShadowOffset + + Comment + Offset value for shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + 0.04 + + + RenderShadowResolutionScale + + Comment + Scale of shadow map resolution vs. screen resolution + Persist + 1 + Type + F32 + Value + 1.0 + + + RenderDeferredTreeShadowBias + + Comment + Bias value for tree shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + 1.0 + + RenderDeferredTreeShadowOffset + + Comment + Offset value for tree shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + 1.0 + + + RenderHoverGlowEnable + + Comment + Show glow effect when hovering on interactive objects. + Persist + 1 + Type + Boolean + Value + 0 + + + RenderHighlightFadeTime + + Comment + Transition time for mouseover highlights. + Persist + 1 + Type + F32 + Value + 0.1 + + + RenderHighlightBrightness + + Comment + Brightness of mouseover highlights. + Persist + 1 + Type + F32 + Value + 4.0 + + + RenderHighlightThickness + + Comment + Thickness of mouseover highlights. + Persist + 1 + Type + F32 + Value + 0.6 + + + RenderHighlightColor + + Comment + Brightness of mouseover highlights. + Persist + 1 + Type + Color4 + Value + + 0.4 + 0.98 + 0.93 + 1.0 + + + + RenderSpecularResX + + Comment + Spec map resolution. + Persist + 1 + Type + U32 + Value + 128 + + + RenderSpecularResY + + Comment + Spec map resolution. + Persist + 1 + Type + U32 + Value + 128 + + + RenderSpecularExponent + + Comment + Specular exponent for generating spec map + Persist + 1 + Type + F32 + Value + 8 + + + RenderDeferred + + Comment Use deferred rendering pipeline. Persist 1 @@ -9179,19 +9635,93 @@ Value 0 - RenderDeferredSunShadow - - Comment - Generate shadows from the sun. - Persist - 1 - Type - Boolean - Value - 1 - - RenderDeferredSunWash - + + RenderDeferredGI + + Comment + Enable GI in deferred renderer. + Persist + 1 + Type + Boolean + Value + 0 + + + RenderDeferredSun + + Comment + Execute sunlight shader in deferred renderer. + Persist + 1 + Type + Boolean + Value + 1 + + + RenderDeferredAtmospheric + + Comment + Execute atmospheric shader in deferred renderer. + Persist + 1 + Type + Boolean + Value + 1 + + + RenderDeferredSSAO + + Comment + Execute screen space ambient occlusion shader in deferred renderer. + Persist + 1 + Type + Boolean + Value + 1 + + + RenderDeferredBlurLight + + Comment + Execute shadow softening shader in deferred renderer. + Persist + 1 + Type + Boolean + Value + 1 + + + RenderDeferredLocalLights + + Comment + Execute local lighting shader in deferred renderer. + Persist + 1 + Type + Boolean + Value + 1 + + + RenderDeferredFullscreenLights + + Comment + Execute local lighting shader in deferred renderer. + Persist + 1 + Type + Boolean + Value + 1 + + + RenderDeferredSunWash + Comment Amount local lights are washed out by sun. Persist @@ -9211,20 +9741,59 @@ F32 Value -0.0001 - - RenderShadowBlurSize - - Comment - Scale of shadow softening kernel. - Persist - 1 - Type - F32 - Value - 0.7 - - RenderShadowBlurSamples - + + RenderShadowErrorCutoff + + Comment + Cutoff error value to use ortho instead of perspective projection. + Persist + 1 + Type + F32 + Value + 5.0 + + RenderShadowFOVCutoff + + Comment + Cutoff FOV to use ortho instead of perspective projection. + Persist + 1 + Type + F32 + Value + 1.1 + + + RenderShadowGaussian + + Comment + Gaussian coefficients for the two shadow/SSAO blurring passes (z component unused). + Persist + 1 + Type + Vector3 + Value + + 3.0 + 2.0 + 0.0 + + + + RenderShadowBlurSize + + Comment + Scale of shadow softening kernel. + Persist + 1 + Type + F32 + Value + 1.4 + + RenderShadowBlurSamples + Comment Number of samples to take for each pass of shadow blur (value range 1-16). Actual number of samples is value * 2 - 1. Persist @@ -9234,6 +9803,104 @@ Value 5 + RenderShadowBlurDistFactor + + Comment + Distance scaler for shadow blur. + Persist + 1 + Type + F32 + Value + 0.1 + + + RenderGIAmbiance + + Comment + Ambiance factor of global illumination contribution. + Persist + 1 + Type + F32 + Value + 0.5 + + + RenderGIMinRenderSize + + Comment + Minimum size of objects to put into GI source map. + Persist + 1 + Type + F32 + Value + 0.5 + + + RenderGIBlurColorCurve + + Comment + Color curve for GI softening kernel + Persist + 1 + Type + Vector3 + Value + + 1.0 + 0.6 + 0.02 + + + + RenderGIBlurPasses + + Comment + Scale of GI softening kernel. + Persist + 1 + Type + U32 + Value + 4 + + + RenderGIBlurSize + + Comment + Scale of GI softening kernel. + Persist + 1 + Type + F32 + Value + 4.0 + + RenderGIBlurSamples + + Comment + Number of samples to take for each pass of GI blur (value range 1-16). Actual number of samples is value * 2 - 1. + Persist + 1 + Type + U32 + Value + 16 + + RenderGIBlurDistFactor + + Comment + Distance scaler for GI blur. + Persist + 1 + Type + F32 + Value + 0.0 + + RenderDynamicLOD Comment @@ -9303,7 +9970,7 @@ RenderFastAlpha Comment - Use lossy alpha rendering optimization (opaque/nonexistent small alpha faces). + Use alpha masks where appropriate. Persist 1 Type @@ -9583,17 +10250,6 @@ Value 0 - RenderLightingDetail - - Comment - Amount of detail for lighting objects/avatars/terrain (0=sun/moon only, 1=enable local lights) - Persist - 1 - Type - S32 - Value - 1 - RenderMaxPartCount Comment @@ -9770,6 +10426,18 @@ Value 2 + RenderShadowDetail + + Comment + Detail of shadows. + Persist + 1 + Type + S32 + Value + 2 + + RenderReflectionRes Comment @@ -9880,6 +10548,17 @@ Value 1.0 + RenderTransparentWater + + Comment + Render water as transparent. Setting to false renders water as opaque with a simple texture applied. + Persist + 1 + Type + Boolean + Value + 1 + RenderTreeLODFactor Comment @@ -10034,28 +10713,6 @@ Value 512 - RenderWaterReflections - - Comment - Reflect the environment in the water. - Persist - 1 - Type - Boolean - Value - 0 - - RenderWaterVoidCulling - - Comment - Cull void water objects when off-screen. - Persist - 1 - Type - Boolean - Value - 1 - RotateRight Comment diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl index 7c8d238d2..9f98f9266 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl @@ -8,14 +8,10 @@ #extension GL_ARB_texture_rectangle : enable uniform sampler2D diffuseMap; -uniform sampler2DShadow shadowMap0; -uniform sampler2DShadow shadowMap1; -uniform sampler2DShadow shadowMap2; -uniform sampler2DShadow shadowMap3; uniform sampler2D noiseMap; -uniform sampler2DRect positionMap; +uniform sampler2DRect depthMap; -uniform mat4 shadow_matrix[4]; +uniform mat4 shadow_matrix[6]; uniform vec4 shadow_clip; uniform vec2 screen_res; @@ -26,63 +22,49 @@ varying vec3 vary_ambient; varying vec3 vary_directional; varying vec3 vary_fragcoord; varying vec3 vary_position; +varying vec3 vary_light; +varying vec3 vary_pointlight_col; -uniform float alpha_soften; +uniform mat4 inv_proj; + + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} void main() { vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; frag *= screen_res; - vec3 samp_pos = texture2DRect(positionMap, frag).xyz; + vec3 samp_pos = getPosition(frag).xyz; - float shadow = 1.0; vec4 pos = vec4(vary_position, 1.0); - if (pos.z > -shadow_clip.w) - { - if (pos.z < -shadow_clip.z) - { - vec4 lpos = shadow_matrix[3]*pos; - shadow = shadow2DProj(shadowMap3, lpos).x; - shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); - } - else if (pos.z < -shadow_clip.y) - { - vec4 lpos = shadow_matrix[2]*pos; - shadow = shadow2DProj(shadowMap2, lpos).x; - } - else if (pos.z < -shadow_clip.x) - { - vec4 lpos = shadow_matrix[1]*pos; - shadow = shadow2DProj(shadowMap1, lpos).x; - } - else - { - vec4 lpos = shadow_matrix[0]*pos; - shadow = shadow2DProj(shadowMap0, lpos).x; - } - } + vec4 diff= texture2D(diffuseMap, gl_TexCoord[0].xy); - vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, gl_Color.a); - vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col; + vec4 col = vec4(vary_ambient + vary_directional.rgb, gl_Color.a); + vec4 color = diff * col; color.rgb = atmosLighting(color.rgb); color.rgb = scaleSoftClip(color.rgb); - /*if (samp_pos.z != 0.0) - { - float dist_factor = alpha_soften; - float a = gl_Color.a; - a *= a; - dist_factor *= 1.0/(1.0-a); - color.a *= min((pos.z-samp_pos.z)*dist_factor, 1.0); - }*/ - + color.rgb += diff.rgb * vary_pointlight_col.rgb; + //gl_FragColor = gl_Color; gl_FragColor = color; //gl_FragColor = vec4(1,0,1,1); + //gl_FragColor = vec4(1,0,1,1)*shadow; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl index 9f130ee42..5200f4d64 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl @@ -9,7 +9,7 @@ vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); void calcAtmospherics(vec3 inPositionEye); float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLight(vec3 v, vec3 n, vec4 lp, float la); +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); @@ -20,8 +20,37 @@ varying vec3 vary_ambient; varying vec3 vary_directional; varying vec3 vary_fragcoord; varying vec3 vary_position; +varying vec3 vary_light; +varying vec3 vary_pointlight_col; uniform float near_clip; +uniform float shadow_offset; +uniform float shadow_bias; + +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight) +{ + //get light vector + vec3 lv = lp.xyz-v; + + //get distance + float d = length(lv); + + //normalize light vector + lv *= 1.0/d; + + //distance attenuation + float dist2 = d*d/(la*la); + float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 + + //angular attenuation + da *= calcDirectionalLight(n, lv); + + return da; +} void main() { @@ -32,32 +61,37 @@ void main() vec4 pos = (gl_ModelViewMatrix * gl_Vertex); vec3 norm = normalize(gl_NormalMatrix * gl_Normal); - vary_position = pos.xyz; + + float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz)); + vary_position = pos.xyz + gl_LightSource[0].position.xyz * (1.0-dp_directional_light)*shadow_offset; calcAtmospherics(pos.xyz); //vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.)); - + vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a); + + // Collect normal lights + col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation, gl_LightSource[2].specular.a); + col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation, gl_LightSource[3].specular.a); + col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation, gl_LightSource[4].specular.a); + col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation, gl_LightSource[5].specular.a); + col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation, gl_LightSource[6].specular.a); + col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation, gl_LightSource[7].specular.a); + + vary_pointlight_col = col.rgb*gl_Color.rgb; + + col.rgb = vec3(0,0,0); // Add windlight lights col.rgb = atmosAmbient(vec3(0.)); - col.rgb = scaleUpLight(col.rgb); - - // Collect normal lights (need to be divided by two, as we later multiply by 2) - col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation); - col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation); - col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation); - col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation); - col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation); - col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation); - col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz); - col.rgb = scaleDownLight(col.rgb); + + vary_light = gl_LightSource[0].position.xyz; vary_ambient = col.rgb*gl_Color.rgb; vary_directional.rgb = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a))); - col.rgb = min(col.rgb*gl_Color.rgb, 1.0); + col.rgb = col.rgb*gl_Color.rgb; gl_FrontColor = col; diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl index 6c94f5c5a..ff64a6b0c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl @@ -12,7 +12,7 @@ uniform sampler2DShadow shadowMap2; uniform sampler2DShadow shadowMap3; uniform sampler2D noiseMap; -uniform mat4 shadow_matrix[4]; +uniform mat4 shadow_matrix[6]; uniform vec4 shadow_clip; vec3 atmosLighting(vec3 light); diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl index c1988d3c7..650fbcc3f 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl @@ -10,7 +10,7 @@ mat4 getSkinnedTransform(); void calcAtmospherics(vec3 inPositionEye); float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLight(vec3 v, vec3 n, vec4 lp, float la); +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); @@ -47,23 +47,22 @@ void main() calcAtmospherics(pos.xyz); //vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.)); - vec4 col; - col.a = gl_Color.a; - - // Add windlight lights - col.rgb = atmosAmbient(vec3(0.)); - col.rgb = scaleUpLight(col.rgb); + + vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a); // Collect normal lights (need to be divided by two, as we later multiply by 2) - col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation); - col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation); - col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation); - col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation); - col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation); - col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation); + col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a); + col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a); + col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a); + col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a); + col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a); + col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a); col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz); col.rgb = scaleDownLight(col.rgb); + // Add windlight lights + col.rgb += atmosAmbient(vec3(0.)); + vary_ambient = col.rgb*gl_Color.rgb; vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a))); diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl index b5daef03e..afbe08a57 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl @@ -8,7 +8,6 @@ uniform sampler2D diffuseMap; varying vec3 vary_normal; -varying vec4 vary_position; void main() { @@ -21,7 +20,7 @@ void main() gl_FragData[0] = vec4(diff.rgb, 0.0); gl_FragData[1] = vec4(0,0,0,0); - gl_FragData[2] = vec4(normalize(vary_normal), 0.0); - gl_FragData[3] = vary_position; + vec3 nvn = normalize(vary_normal); + gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl index 3f60d4a71..085ffddee 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl @@ -10,7 +10,7 @@ uniform sampler2D diffuseMap; void main() { - //gl_FragColor = vec4(1,1,1,gl_Color.a * texture2D(diffuseMap, gl_TexCoord[0].xy)); //This should not compile! - gl_FragColor = vec4(1,1,1,texture2D(diffuseMap, gl_TexCoord[0].xy).a * gl_Color.a); + //gl_FragColor = vec4(1,1,1,gl_Color.a * texture2D(diffuseMap, gl_TexCoord[0].xy).a); + gl_FragColor = vec4(1,1,1,1); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl index 14da6b1ad..8c8489d08 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl @@ -28,8 +28,7 @@ void main() norm = normalize(norm); pos = gl_ProjectionMatrix * pos; - //smash geometry against near clip plane - pos.z = max(pos.z, -1.0); + pos.z = max(pos.z, -pos.w+0.01); gl_Position = pos; gl_FrontColor = gl_Color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl index 12a7ff7f2..471a1f040 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl @@ -10,7 +10,6 @@ mat4 getSkinnedTransform(); attribute vec4 weight; varying vec3 vary_normal; -varying vec4 vary_position; void main() { @@ -30,7 +29,6 @@ void main() norm.z = dot(trans[2].xyz, gl_Normal); norm = normalize(norm); - vary_position = pos; vary_normal = norm; gl_Position = gl_ProjectionMatrix * pos; diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 3c6700a87..d1c5d7cb1 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -7,42 +7,75 @@ #extension GL_ARB_texture_rectangle : enable -uniform sampler2DRect positionMap; +uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; uniform sampler2DRect lightMap; +uniform float dist_factor; uniform float blur_size; uniform vec2 delta; -uniform vec3 kern[32]; -uniform int kern_length; +uniform vec3 kern[4]; uniform float kern_scale; varying vec2 vary_fragcoord; +uniform mat4 inv_proj; +uniform vec2 screen_res; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + void main() { vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz; - vec3 pos = texture2DRect(positionMap, vary_fragcoord.xy).xyz; - vec2 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rg; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + vec3 pos = getPosition(vary_fragcoord.xy).xyz; + vec4 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rgba; vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy); - vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free' - vec2 col = defined_weight * ccol; + dlt /= max(-pos.z*dist_factor, 1.0); - for (int i = 1; i < kern_length; i++) + vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free' + vec4 col = defined_weight.xyxx * ccol; + + for (int i = 1; i < 4; i++) { vec2 tc = vary_fragcoord.xy + kern[i].z*dlt; - vec3 samppos = texture2DRect(positionMap, tc).xyz; + vec3 samppos = getPosition(tc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane if (d*d <= 0.003) { - col += texture2DRect(lightMap, tc).rg*kern[i].xy; + col += texture2DRect(lightMap, tc)*kern[i].xyxx; + defined_weight += kern[i].xy; + } + } + for (int i = 1; i < 4; i++) + { + vec2 tc = vary_fragcoord.xy - kern[i].z*dlt; + vec3 samppos = getPosition(tc).xyz; + float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane + if (d*d <= 0.003) + { + col += texture2DRect(lightMap, tc)*kern[i].xyxx; defined_weight += kern[i].xy; } } - col /= defined_weight; - gl_FragColor = vec4(col.r, col.g, 0.0, 1.0); + + col /= defined_weight.xyxx; + + gl_FragColor = col; } + diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl index a8712bc8c..2197744a3 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl @@ -11,19 +11,19 @@ uniform sampler2D bumpMap; varying vec3 vary_mat0; varying vec3 vary_mat1; varying vec3 vary_mat2; -varying vec4 vary_position; void main() { - vec3 col = texture2D(diffuseMap, gl_TexCoord[0].xy).rgb; + vec3 col = gl_Color.rgb * texture2D(diffuseMap, gl_TexCoord[0].xy).rgb; vec3 norm = texture2D(bumpMap, gl_TexCoord[0].xy).rgb * 2.0 - 1.0; vec3 tnorm = vec3(dot(norm,vary_mat0), - dot(norm,vary_mat1), - dot(norm,vary_mat2)); + dot(norm,vary_mat1), + dot(norm,vary_mat2)); - gl_FragData[0].rgb = gl_Color.rgb*col; - gl_FragData[1] = vec4(col*(gl_Color.a*1.5), gl_Color.a); - gl_FragData[2] = vec4(normalize(tnorm), 0.0); - gl_FragData[3] = vary_position; + gl_FragData[0] = vec4(col, 0.0); + gl_FragData[1] = gl_Color.aaaa; // spec + //gl_FragData[1] = vec4(vec3(gl_Color.a), gl_Color.a+(1.0-gl_Color.a)*gl_Color.a); // spec - from former class3 - maybe better, but not so well tested + vec3 nvn = normalize(tnorm); + gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl index ba180922c..9589912c6 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl @@ -8,7 +8,6 @@ varying vec3 vary_mat0; varying vec3 vary_mat1; varying vec3 vary_mat2; -varying vec4 vary_position; void main() { @@ -16,8 +15,6 @@ void main() gl_Position = ftransform(); gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; - vary_position = gl_ModelViewMatrix * gl_Vertex; - vec3 n = normalize(gl_NormalMatrix * gl_Normal); vec3 b = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz); vec3 t = cross(b, n); diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl index f2ba2df69..3803119cd 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl @@ -8,13 +8,13 @@ uniform sampler2D diffuseMap; varying vec3 vary_normal; -varying vec4 vary_position; void main() { - vec3 col = texture2D(diffuseMap, gl_TexCoord[0].xy).rgb; - gl_FragData[0] = vec4(gl_Color.rgb*col, 1.0); - gl_FragData[1] = vec4(col*(gl_Color.a*1.5), gl_Color.a); - gl_FragData[2] = vec4(normalize(vary_normal), 0.0); - gl_FragData[3] = vary_position; + vec3 col = gl_Color.rgb * texture2D(diffuseMap, gl_TexCoord[0].xy).rgb; + gl_FragData[0] = vec4(col, 0.0); + gl_FragData[1] = gl_Color.aaaa; // spec + //gl_FragData[1] = vec4(vec3(gl_Color.a), gl_Color.a+(1.0-gl_Color.a)*gl_Color.a); // spec - from former class3 - maybe better, but not so well tested + vec3 nvn = normalize(vary_normal); + gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl index 3413a7f9d..e375bb2a9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl @@ -2,20 +2,17 @@ * @file diffuseV.glsl * * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. - * $License$ + * $/LicenseInfo$ */ varying vec3 vary_normal; -varying vec4 vary_position; void main() { //transform vertex - gl_Position = ftransform(); + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; - vary_position = gl_ModelViewMatrix * gl_Vertex; - vary_normal = normalize(gl_NormalMatrix * gl_Normal); gl_FrontColor = gl_Color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl index 2a811c589..f53e15c6c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl @@ -1,21 +1,16 @@ /** * @file fullbrightF.glsl * - * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. - * $License$ + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ */ #extension GL_ARB_texture_rectangle : enable uniform sampler2D diffuseMap; -uniform sampler2DShadow shadowMap0; -uniform sampler2DShadow shadowMap1; -uniform sampler2DShadow shadowMap2; -uniform sampler2DShadow shadowMap3; +uniform sampler2DRect depthMap; uniform sampler2D noiseMap; -uniform sampler2DRect positionMap; -uniform mat4 shadow_matrix[4]; uniform vec4 shadow_clip; uniform vec2 screen_res; @@ -28,14 +23,27 @@ varying vec4 vary_position; varying vec3 vary_normal; varying vec3 vary_fragcoord; -uniform float alpha_soften; +uniform mat4 inv_proj; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} void main() { vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; frag *= screen_res; - vec3 samp_pos = texture2DRect(positionMap, frag).xyz; + vec3 samp_pos = getPosition(frag).xyz; float shadow = 1.0; vec4 pos = vary_position; @@ -46,15 +54,6 @@ void main() color.rgb = fullbrightScaleSoftClip(color.rgb); - if (samp_pos.z != 0.0) - { - float dist_factor = alpha_soften; - float a = gl_Color.a; - a *= a; - dist_factor *= 1.0/(1.0-a); - color.a *= min((pos.z-samp_pos.z)*dist_factor, 1.0); - } - //gl_FragColor = gl_Color; gl_FragColor = color; //gl_FragColor = vec4(1,0,1,1); diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl index 6381a1ced..aff51178b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl @@ -12,12 +12,12 @@ vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 scaleDownLight(vec3 light); vec3 scaleUpLight(vec3 light); -varying vec4 vary_position; varying vec3 vary_ambient; varying vec3 vary_directional; varying vec3 vary_normal; varying vec3 vary_fragcoord; uniform float near_clip; +varying vec4 vary_position; void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/giF.glsl b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl new file mode 100644 index 000000000..e64e29a0d --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl @@ -0,0 +1,166 @@ +/** + * @file giF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform sampler2D noiseMap; + +uniform sampler2D diffuseGIMap; +uniform sampler2D normalGIMap; +uniform sampler2D depthGIMap; + +uniform sampler2D lightFunc; + +// Inputs +varying vec2 vary_fragcoord; + +uniform vec2 screen_res; + +uniform mat4 inv_proj; +uniform mat4 gi_mat; //gPipeline.mGIMatrix - eye space to sun space +uniform mat4 gi_mat_proj; //gPipeline.mGIMatrixProj - eye space to projected sun space +uniform mat4 gi_norm_mat; //gPipeline.mGINormalMatrix - eye space normal to sun space normal matrix +uniform mat4 gi_inv_proj; //gPipeline.mGIInvProj - projected sun space to sun space +uniform float gi_radius; +uniform float gi_intensity; +uniform int gi_samples; +uniform vec2 gi_kern[25]; +uniform vec2 gi_scale; +uniform vec3 gi_quad; +uniform vec3 gi_spec; +uniform float gi_direction_weight; +uniform float gi_light_offset; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec4 getGIPosition(vec2 gi_tc) +{ + float depth = texture2D(depthGIMap, gi_tc).a; + vec2 sc = gi_tc*2.0; + sc -= vec2(1.0, 1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = gi_inv_proj*ndc; + pos.xyz /= pos.w; + pos.w = 1.0; + return pos; +} + +vec3 giAmbient(vec3 pos, vec3 norm) +{ + vec4 gi_c = gi_mat_proj * vec4(pos, 1.0); + gi_c.xyz /= gi_c.w; + + vec4 gi_pos = gi_mat*vec4(pos,1.0); + vec3 gi_norm = (gi_norm_mat*vec4(norm,1.0)).xyz; + gi_norm = normalize(gi_norm); + + vec2 tcx = gi_norm.xy; + vec2 tcy = gi_norm.yx; + + vec4 eye_pos = gi_mat*vec4(0,0,0,1.0); + + vec3 eye_dir = normalize(gi_pos.xyz-eye_pos.xyz/eye_pos.w); + + //vec3 eye_dir = vec3(0,0,-1); + //eye_dir = (gi_norm_mat*vec4(eye_dir, 1.0)).xyz; + //eye_dir = normalize(eye_dir); + + //float round_x = gi_scale.x; + //float round_y = gi_scale.y; + + vec3 debug = texture2D(normalGIMap, gi_c.xy).rgb*0.5+0.5; + debug.xz = vec2(0.0,0.0); + //debug = fract(debug); + + float round_x = 1.0/64.0; + float round_y = 1.0/64.0; + + //gi_c.x = floor(gi_c.x/round_x+0.5)*round_x; + //gi_c.y = floor(gi_c.y/round_y+0.5)*round_y; + + float fda = 0.0; + vec3 fdiff = vec3(0,0,0); + + vec3 rcol = vec3(0,0,0); + + float fsa = 0.0; + + for (int i = -1; i < 2; i+=2 ) + { + for (int j = -1; j < 2; j+=2) + { + vec2 tc = vec2(i, j)*0.75; + vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0+tc*0.5).xyz; + //tc += gi_norm.xy*nz.z; + tc += nz.xy*2.0; + tc /= gi_samples; + tc += gi_c.xy; + + vec3 lnorm = -normalize(texture2D(normalGIMap, tc.xy).xyz*2.0-1.0); + vec3 lpos = getGIPosition(tc.xy).xyz; + + vec3 at = lpos-gi_pos.xyz; + float dist = dot(at,at); + float da = clamp(1.0/(gi_spec.x*dist), 0.0, 1.0); + + if (da > 0.0) + { + //add angular attenuation + vec3 ldir = at; + float ang_atten = clamp(dot(ldir, gi_norm), 0.0, 1.0); + + float ld = -dot(ldir, lnorm); + + if (ang_atten > 0.0 && ld < 0.0) + { + vec3 diff = texture2D(diffuseGIMap, tc.xy).xyz; + da = da*ang_atten; + fda += da; + fdiff += diff*da; + } + } + } + } + + fdiff /= max(gi_spec.y*fda, gi_quad.z); + fdiff = clamp(fdiff, vec3(0), vec3(1)); + + vec3 ret = fda*fdiff; + //ret = ret*ret*gi_quad.x+ret*gi_quad.y+gi_quad.z; + + //fda *= nz.z; + + //rcol.rgb *= gi_intensity; + //return rcol.rgb+vary_AmblitColor.rgb*0.25; + //return vec4(debug, 0.0); + //return vec4(fda*fdiff, 0.0); + return clamp(ret,vec3(0.0), vec3(1.0)); + //return debug.xyz; +} + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + vec4 pos = getPosition(pos_screen); + vec3 norm = texture2DRect(normalMap, pos_screen).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + + gl_FragData[0].xyz = giAmbient(pos, norm); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/giV.glsl b/indra/newview/app_settings/shaders/class1/deferred/giV.glsl new file mode 100644 index 000000000..543527612 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/giV.glsl @@ -0,0 +1,22 @@ +/** + * @file giV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; + +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res; + vec4 tex = gl_MultiTexCoord0; + tex.w = 1.0; + + gl_FrontColor = gl_Color; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index 4e3e635f1..508bbf415 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -9,13 +9,10 @@ uniform sampler2D diffuseMap; uniform sampler2D normalMap; uniform sampler2D specularMap; -varying vec4 vary_position; - void main() { vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy); gl_FragData[0] = vec4(col.rgb, col.a <= 0.5 ? 0.0 : 0.005); gl_FragData[1] = texture2D(specularMap, gl_TexCoord[0].xy); - gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, vary_position.z); - gl_FragData[3] = vary_position; + gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl index 9c5ae3154..57532a30b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl @@ -5,15 +5,11 @@ * $License$ */ -varying vec4 vary_position; - void main() { //transform vertex gl_Position = ftransform(); gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; - vary_position = gl_ModelViewMatrix * gl_Vertex; - gl_FrontColor = gl_Color; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl new file mode 100644 index 000000000..acb3014d1 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl @@ -0,0 +1,15 @@ +/** + * @file luminanceF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +uniform sampler2DRect diffuseMap; + +varying vec2 vary_fragcoord; + +void main() +{ + gl_FragColor = texture2DRect(diffuseMap, vary_fragcoord.xy); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl new file mode 100644 index 000000000..6368def83 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl @@ -0,0 +1,20 @@ +/** + * @file giV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; + +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res; + + gl_FrontColor = gl_Color; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl index c8248b294..68cb0636d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl @@ -7,13 +7,14 @@ #extension GL_ARB_texture_rectangle : enable +uniform sampler2DRect depthMap; uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; -uniform sampler2DRect positionMap; uniform sampler2DRect normalMap; uniform samplerCube environmentMap; -uniform sampler2DRect lightMap; uniform sampler2D noiseMap; +uniform sampler2D lightFunc; + uniform vec3 env_mat[3]; uniform float sun_wash; @@ -23,24 +24,50 @@ uniform int light_count; uniform vec4 light[16]; uniform vec4 light_col[16]; -varying vec3 vary_fragcoord; +varying vec4 vary_fragcoord; uniform vec2 screen_res; +uniform float far_z; + +uniform mat4 inv_proj; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + void main() { vec2 frag = (vary_fragcoord.xy*0.5+0.5)*screen_res; - vec3 pos = texture2DRect(positionMap, frag.xy).xyz; - vec3 norm = normalize(texture2DRect(normalMap, frag.xy).xyz); + vec3 pos = getPosition(frag.xy).xyz; + if (pos.z < far_z) + { + discard; + } + + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + norm = normalize(norm); vec4 spec = texture2DRect(specularRect, frag.xy); vec3 diff = texture2DRect(diffuseRect, frag.xy).rgb; float noise = texture2D(noiseMap, frag.xy/128.0).b; vec3 out_col = vec3(0,0,0); + vec3 npos = normalize(-pos); for (int i = 0; i < light_count; ++i) { vec3 lv = light[i].xyz-pos; float dist2 = dot(lv,lv); - if (dist2 > light[i].w) + dist2 /= light[i].w; + if (dist2 > 1.0) { continue; } @@ -55,30 +82,31 @@ void main() da = dot(norm, lv); float fa = light_col[i].a+1.0; - float dist_atten = clamp(1.0-(dist2-light[i].w*(1.0-fa))/(light[i].w*fa), 0.0, 1.0); + float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); dist_atten *= noise; float lit = da * dist_atten; vec3 col = light_col[i].rgb*lit*diff; + //vec3 col = vec3(dist2, light_col[i].a, lit); if (spec.a > 0.0) { - vec3 ref = reflect(normalize(pos), norm); - float sa = dot(ref,lv); - sa = max(sa, 0.0); - sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0); - sa *= noise; - col += da*sa*light_col[i].rgb*spec.rgb; + //vec3 ref = dot(pos+lv, norm); + + float sa = dot(normalize(lv+npos),norm); + + if (sa > 0.0) + { + sa = texture2D(lightFunc,vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0); + sa *= noise; + col += da*sa*light_col[i].rgb*spec.rgb; + } } out_col += col; } - //attenuate point light contribution by SSAO component - out_col *= texture2DRect(lightMap, frag.xy).g; - - if (dot(out_col, out_col) <= 0.0) { discard; diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl new file mode 100644 index 000000000..a9f03f761 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl @@ -0,0 +1,225 @@ +/** + * @file multiSpotLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#version 120 + +//class 1 -- no shadows + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform samplerCube environmentMap; +uniform sampler2D noiseMap; +uniform sampler2D lightFunc; +uniform sampler2D projectionMap; + +uniform mat4 proj_mat; //screen space to light space +uniform float proj_near; //near clip for projection +uniform vec3 proj_p; //plane projection is emitting from (in screen space) +uniform vec3 proj_n; +uniform float proj_focus; //distance from plane to begin blurring +uniform float proj_lod; //(number of mips in proj map) +uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambient_lod; +uniform float proj_ambiance; +uniform float near_clip; +uniform float far_clip; + +uniform vec3 proj_origin; //origin of projection to be used for angular attenuation +uniform float sun_wash; +uniform int proj_shadow_idx; +uniform float shadow_fade; + +varying vec4 vary_light; + +varying vec4 vary_fragcoord; +uniform vec2 screen_res; + +uniform mat4 inv_proj; + +vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float det = max(1.0-lod/(proj_lod*0.5), 0.0); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); + + return ret; +} + +vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + + float det = min(lod/(proj_lod*0.5), 1.0); + + float d = min(dist.x, dist.y); + + float edge = 0.25*det; + + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; +} + + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +void main() +{ + vec4 frag = vary_fragcoord; + frag.xyz /= frag.w; + frag.xyz = frag.xyz*0.5+0.5; + frag.xy *= screen_res; + + vec3 pos = getPosition(frag.xy).xyz; + vec3 lv = vary_light.xyz-pos.xyz; + float dist2 = dot(lv,lv); + dist2 /= vary_light.w; + if (dist2 > 1.0) + { + discard; + } + + vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0; + + norm = normalize(norm); + float l_dist = -dot(lv, proj_n); + + vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); + if (proj_tc.z < 0.0) + { + discard; + } + + proj_tc.xyz /= proj_tc.w; + + float fa = gl_Color.a+1.0; + float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + if (dist_atten <= 0.0) + { + discard; + } + + lv = proj_origin-pos.xyz; + lv = normalize(lv); + float da = dot(norm, lv); + + vec3 col = vec3(0,0,0); + + vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; + + float noise = texture2D(noiseMap, frag.xy/128.0).b; + if (proj_tc.z > 0.0 && + proj_tc.x < 1.0 && + proj_tc.y < 1.0 && + proj_tc.x > 0.0 && + proj_tc.y > 0.0) + { + float lit = 0.0; + float amb_da = proj_ambiance; + + if (da > 0.0) + { + float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); + float lod = diff * proj_lod; + + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); + + vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a; + + lit = da * dist_atten * noise; + + col = lcol*lit*diff_tex; + amb_da += (da*0.5)*proj_ambiance; + } + + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); + vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); + + amb_da += (da*da*0.5+0.5)*proj_ambiance; + + amb_da *= dist_atten * noise; + + amb_da = min(amb_da, 1.0-lit); + + col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + } + + + vec4 spec = texture2DRect(specularRect, frag.xy); + if (spec.a > 0.0) + { + vec3 ref = reflect(normalize(pos), norm); + + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); + + if (ds < 0.0) + { + vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; + + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); + + if (stc.z > 0.0) + { + stc.xy /= stc.w; + + float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); + + stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); + + if (stc.x < 1.0 && + stc.y < 1.0 && + stc.x > 0.0 && + stc.y > 0.0) + { + vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); + col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb; + } + } + } + } + + gl_FragColor.rgb = col; + gl_FragColor.a = 0.0; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl index 68f376d69..43da16436 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl @@ -1,41 +1,62 @@ /** * @file pointLightF.glsl * - * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. - * $License$ + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ */ #extension GL_ARB_texture_rectangle : enable uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; -uniform sampler2DRect positionMap; uniform sampler2DRect normalMap; uniform samplerCube environmentMap; -uniform sampler2DRect lightMap; uniform sampler2D noiseMap; +uniform sampler2D lightFunc; +uniform sampler2DRect depthMap; uniform vec3 env_mat[3]; uniform float sun_wash; varying vec4 vary_light; -varying vec3 vary_fragcoord; +varying vec4 vary_fragcoord; uniform vec2 screen_res; +uniform mat4 inv_proj; +uniform vec4 viewport; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = (pos_screen.xy-viewport.xy)*2.0; + sc /= viewport.zw; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + void main() { - vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; - frag *= screen_res; - vec3 pos = texture2DRect(positionMap, frag).xyz; + vec4 frag = vary_fragcoord; + frag.xyz /= frag.w; + frag.xyz = frag.xyz*0.5+0.5; + frag.xy *= screen_res; + + vec3 pos = getPosition(frag.xy).xyz; vec3 lv = vary_light.xyz-pos; float dist2 = dot(lv,lv); - if (dist2 > vary_light.w) + dist2 /= vary_light.w; + if (dist2 > 1.0) { discard; } - vec3 norm = texture2DRect(normalMap, frag).xyz; + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm float da = dot(norm, lv); if (da < 0.0) { @@ -46,35 +67,32 @@ void main() lv = normalize(lv); da = dot(norm, lv); - float noise = texture2D(noiseMap, frag/128.0).b; + float noise = texture2D(noiseMap, frag.xy/128.0).b; - vec3 col = texture2DRect(diffuseRect, frag).rgb; + vec3 col = texture2DRect(diffuseRect, frag.xy).rgb; float fa = gl_Color.a+1.0; - float dist_atten = clamp(1.0-(dist2-vary_light.w*(1.0-fa))/(vary_light.w*fa), 0.0, 1.0); + float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); float lit = da * dist_atten * noise; col = gl_Color.rgb*lit*col; - vec4 spec = texture2DRect(specularRect, frag); + vec4 spec = texture2DRect(specularRect, frag.xy); if (spec.a > 0.0) { - vec3 ref = reflect(normalize(pos), norm); - float sa = dot(ref,lv); - sa = max(sa, 0.0); - sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0); - sa *= noise; - col += da*sa*gl_Color.rgb*spec.rgb; + float sa = dot(normalize(lv-normalize(pos)),norm); + if (sa > 0.0) + { + sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0); + sa *= noise; + col += da*sa*gl_Color.rgb*spec.rgb; + } } - //attenuate point light contribution by SSAO component - col *= texture2DRect(lightMap, frag.xy).g; - if (dot(col, col) <= 0.0) { discard; } - gl_FragColor.rgb = col; gl_FragColor.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl index a4edb8825..e815ca260 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl @@ -6,7 +6,7 @@ */ varying vec4 vary_light; -varying vec3 vary_fragcoord; +varying vec4 vary_fragcoord; uniform vec2 screen_res; uniform float near_clip; @@ -14,10 +14,10 @@ uniform float near_clip; void main() { //transform vertex - gl_Position = ftransform(); + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; - vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip); + vary_fragcoord = pos; vec4 tex = gl_MultiTexCoord0; tex.w = 1.0; diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl new file mode 100644 index 000000000..650e1a91a --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl @@ -0,0 +1,57 @@ +/** + * @file postDeferredF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect localLightMap; +uniform sampler2DRect sunLightMap; +uniform sampler2DRect giLightMap; +uniform sampler2D luminanceMap; +uniform sampler2DRect lightMap; + +uniform vec3 lum_quad; +uniform float lum_lod; +uniform vec4 ambient; + +uniform vec3 gi_quad; + +uniform vec2 screen_res; +varying vec2 vary_fragcoord; + +void main() +{ + vec2 tc = vary_fragcoord.xy; + vec3 lum = texture2DLod(luminanceMap, tc/screen_res, lum_lod).rgb; + float luminance = lum.r; + luminance = luminance*lum_quad.y+lum_quad.z; + + vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy); + + float ambocc = texture2DRect(lightMap, vary_fragcoord.xy).g; + + vec3 gi_col = texture2DRect(giLightMap, vary_fragcoord.xy).rgb; + gi_col = gi_col*gi_col*gi_quad.x + gi_col*gi_quad.y+gi_quad.z*ambocc*ambient.rgb; + gi_col *= diff; + + vec4 sun_col = texture2DRect(sunLightMap, vary_fragcoord.xy); + + vec3 local_col = texture2DRect(localLightMap, vary_fragcoord.xy).rgb; + + + sun_col *= 1.0/min(luminance, 1.0); + gi_col *= 1.0/luminance; + + vec3 col = sun_col.rgb+gi_col+local_col; + + gl_FragColor.rgb = col.rgb; + col.rgb = max(col.rgb-vec3(1.0,1.0,1.0), vec3(0.0, 0.0, 0.0)); + + gl_FragColor.a = 0.0; // max(dot(col.rgb,col.rgb)*lum_quad.x, sun_col.a); + + //gl_FragColor.rgb = vec3(lum_lod); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl new file mode 100644 index 000000000..0ec81dcb0 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl @@ -0,0 +1,17 @@ +/** + * @file postDeferredV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl new file mode 100644 index 000000000..e8e58f50e --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl @@ -0,0 +1,80 @@ +/** + * @file postgiF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform sampler2DRect giLightMap; +uniform sampler2D noiseMap; + +uniform vec2 kern[32]; +uniform float dist_factor; +uniform float blur_size; +uniform vec2 delta; +uniform int kern_length; +uniform float kern_scale; +uniform vec3 blur_quad; + +varying vec2 vary_fragcoord; + +uniform mat4 inv_proj; +uniform vec2 screen_res; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +void main() +{ + vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + vec3 pos = getPosition(vary_fragcoord.xy).xyz; + + vec3 ccol = texture2DRect(giLightMap, vary_fragcoord.xy).rgb; + vec2 dlt = kern_scale * delta/(1.0+norm.xy*norm.xy); + dlt /= max(-pos.z*dist_factor, 1.0); + float defined_weight = kern[0].x; + vec3 col = vec3(0.0); + + for (int i = 0; i < kern_length; i++) + { + vec2 tc = vary_fragcoord.xy + kern[i].y*dlt; + vec3 sampNorm = texture2DRect(normalMap, tc.xy).xyz; + sampNorm = vec3((sampNorm.xy-0.5)*2.0,sampNorm.z); // unpack norm + + float d = dot(norm.xyz, sampNorm); + + if (d > 0.8) + { + vec3 samppos = getPosition(tc.xy).xyz; + samppos -= pos; + if (dot(samppos,samppos) < -0.05*pos.z) + { + col += texture2DRect(giLightMap, tc).rgb*kern[i].x; + defined_weight += kern[i].x; + } + } + } + + col /= defined_weight; + + //col = ccol; + + col = col*col*blur_quad.x + col*blur_quad.y + blur_quad.z; + + gl_FragData[0].xyz = col; + + //gl_FragColor = ccol; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl b/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl new file mode 100644 index 000000000..e5f621764 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl @@ -0,0 +1,17 @@ +/** + * @file postgiV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl index b3758c363..b0b31fd4b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl @@ -7,8 +7,11 @@ uniform sampler2D diffuseMap; +varying vec4 post_pos; void main() { gl_FragColor = vec4(1,1,1,texture2D(diffuseMap, gl_TexCoord[0].xy).a * gl_Color.a); + + gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl index aae1beeae..7214d246a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl @@ -5,13 +5,17 @@ * $License$ */ +varying vec4 post_pos; + void main() { //transform vertex vec4 pos = gl_ModelViewProjectionMatrix*gl_Vertex; - //smash geometry against the near clip plane (great for ortho projections) - pos.z = max(pos.z, -1.0); - gl_Position = pos; + + post_pos = pos; + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; gl_FrontColor = gl_Color; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl index d5671a6ce..bef91e735 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl @@ -11,10 +11,11 @@ uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect positionMap; uniform sampler2DRect normalMap; -uniform sampler2DRect depthMap; uniform sampler2DRect lightMap; +uniform sampler2DRect depthMap; uniform sampler2D noiseMap; uniform samplerCube environmentMap; +uniform sampler2D lightFunc; uniform float blur_size; uniform float blur_fidelity; @@ -38,8 +39,8 @@ uniform vec4 max_y; uniform vec4 glow; uniform float scene_light_strength; uniform vec3 env_mat[3]; -uniform mat4 shadow_matrix[3]; -uniform vec4 shadow_clip; +//uniform mat4 shadow_matrix[3]; +//uniform vec4 shadow_clip; uniform mat3 ssao_effect_mat; varying vec4 vary_light; @@ -52,6 +53,27 @@ vec3 vary_AmblitColor; vec3 vary_AdditiveColor; vec3 vary_AtmosAttenuation; +uniform mat4 inv_proj; +uniform vec2 screen_res; + +vec4 getPosition_d(vec2 pos_screen, float depth) +{ + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec4 getPosition(vec2 pos_screen) +{ //get position in screen space (world units) given window coordinate and depth map + float depth = texture2DRect(depthMap, pos_screen.xy).a; + return getPosition_d(pos_screen, depth); +} + vec3 getPositionEye() { return vary_PositionEye; @@ -235,45 +257,87 @@ vec3 scaleSoftClip(vec3 light) void main() { vec2 tc = vary_fragcoord.xy; - vec3 pos = texture2DRect(positionMap, tc).xyz; + float depth = texture2DRect(depthMap, tc.xy).a; + vec3 pos = getPosition_d(tc, depth).xyz; vec3 norm = texture2DRect(normalMap, tc).xyz; - vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + //vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz; float da = max(dot(norm.xyz, vary_light.xyz), 0.0); - vec4 diffuse = vec4(texture2DRect(diffuseRect, tc).rgb, 1.0); + vec4 diffuse = texture2DRect(diffuseRect, tc); vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg; - float scol = scol_ambocc.r; + float scol = max(scol_ambocc.r, diffuse.a); float ambocc = scol_ambocc.g; calcAtmospherics(pos.xyz, ambocc); vec3 col = atmosAmbient(vec3(0)); - col += atmosAffectDirectionalLight(min(da, scol)); + col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a)); col *= diffuse.rgb; - if (spec.a > 0.2) + if (spec.a > 0.0) // specular reflection { - vec3 ref = reflect(pos.xyz, norm.xyz); - vec3 rc; - rc.x = dot(ref, env_mat[0]); - rc.y = dot(ref, env_mat[1]); - rc.z = dot(ref, env_mat[2]); - - vec3 refcol = textureCube(environmentMap, rc).rgb; - col.rgb += refcol * spec.rgb; + // the old infinite-sky shiny reflection + // + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + float sa = dot(refnormpersp, vary_light.xyz); + vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a; + + /* + // screen-space cheap fakey reflection map + // + vec3 refnorm = normalize(reflect(vec3(0,0,-1), norm.xyz)); + depth -= 0.5; // unbias depth + // first figure out where we'll make our 2D guess from + vec2 ref2d = (0.25 * screen_res.y) * (refnorm.xy) * abs(refnorm.z) / depth; + // Offset the guess source a little according to a trivial + // checkerboard dither function and spec.a. + // This is meant to be similar to sampling a blurred version + // of the diffuse map. LOD would be better in that regard. + // The goal of the blur is to soften reflections in surfaces + // with low shinyness, and also to disguise our lameness. + float checkerboard = floor(mod(tc.x+tc.y, 2.0)); // 0.0, 1.0 + float checkoffset = (3.0 + (7.0*(1.0-spec.a)))*(checkerboard-0.5); + ref2d += vec2(checkoffset, checkoffset); + ref2d += tc.xy; // use as offset from destination + // Get attributes from the 2D guess point. + // We average two samples of diffuse (not of anything else) per + // pixel to try to reduce aliasing some more. + vec3 refcol = 0.5 * (texture2DRect(diffuseRect, ref2d + vec2(0.0, -checkoffset)).rgb + + texture2DRect(diffuseRect, ref2d + vec2(-checkoffset, 0.0)).rgb); + float refdepth = texture2DRect(depthMap, ref2d).a; + vec3 refpos = getPosition_d(ref2d, refdepth).xyz; + vec3 refn = texture2DRect(normalMap, ref2d).rgb; + refn = normalize(vec3((refn.xy-0.5)*2.0,refn.z)); // unpack norm + // figure out how appropriate our guess actually was + float refapprop = max(0.0, dot(-refnorm, normalize(pos - refpos))); + // darken reflections from points which face away from the reflected ray - our guess was a back-face + //refapprop *= step(dot(refnorm, refn), 0.0); + refapprop = min(refapprop, max(0.0, -dot(refnorm, refn))); // more conservative variant + // get appropriate light strength for guess-point. + // reflect light direction to increase the illusion that + // these are reflections. + vec3 reflight = reflect(lightnorm.xyz, norm.xyz); + float reflit = max(dot(refn, reflight.xyz), 0.0); + // apply sun color to guess-point, dampen according to inappropriateness of guess + float refmod = min(refapprop, reflit); + vec3 refprod = vary_SunlitColor * refcol.rgb * refmod; + vec3 ssshiny = (refprod * spec.a); + ssshiny *= 0.3; // dampen it even more + */ + vec3 ssshiny = vec3(0,0,0); + + // add the two types of shiny together + col += (ssshiny + dumbshiny) * spec.rgb; } col = atmosLighting(col); col = scaleSoftClip(col); - + gl_FragColor.rgb = col; gl_FragColor.a = 0.0; - //gl_FragColor.rg = scol_ambocc.rg; - //gl_FragColor.rgb = norm.rgb*0.5+0.5; - //gl_FragColor.rgb = vec3(ambocc); - //gl_FragColor.rgb = vec3(scol); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl new file mode 100644 index 000000000..29fac46bf --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl @@ -0,0 +1,167 @@ +/** + * @file spotLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#version 120 + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform samplerCube environmentMap; +uniform sampler2D noiseMap; +uniform sampler2D lightFunc; +uniform sampler2D projectionMap; + +uniform mat4 proj_mat; //screen space to light space +uniform float proj_near; //near clip for projection +uniform vec3 proj_p; //plane projection is emitting from (in screen space) +uniform vec3 proj_n; +uniform float proj_focus; //distance from plane to begin blurring +uniform float proj_lod; //(number of mips in proj map) +uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambiance; +uniform float near_clip; +uniform float far_clip; + +uniform vec3 proj_origin; //origin of projection to be used for angular attenuation +uniform float sun_wash; + +varying vec4 vary_light; + +varying vec4 vary_fragcoord; +uniform vec2 screen_res; + +uniform mat4 inv_proj; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +void main() +{ + vec4 frag = vary_fragcoord; + frag.xyz /= frag.w; + frag.xyz = frag.xyz*0.5+0.5; + frag.xy *= screen_res; + + vec3 pos = getPosition(frag.xy).xyz; + vec3 lv = vary_light.xyz-pos.xyz; + float dist2 = dot(lv,lv); + dist2 /= vary_light.w; + if (dist2 > 1.0) + { + discard; + } + + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + + norm = normalize(norm); + float l_dist = -dot(lv, proj_n); + + vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); + if (proj_tc.z < 0.0) + { + discard; + } + + proj_tc.xyz /= proj_tc.w; + + float fa = gl_Color.a+1.0; + float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + + lv = proj_origin-pos.xyz; + lv = normalize(lv); + float da = dot(norm, lv); + + vec3 col = vec3(0,0,0); + + vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; + + float noise = texture2D(noiseMap, frag.xy/128.0).b; + if (proj_tc.z > 0.0 && + proj_tc.x < 1.0 && + proj_tc.y < 1.0 && + proj_tc.x > 0.0 && + proj_tc.y > 0.0) + { + float lit = 0.0; + if (da > 0.0) + { + float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); + float lod = diff * proj_lod; + + vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod); + + vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a; + + lit = da * dist_atten * noise; + + col = lcol*lit*diff_tex; + } + + float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); + float lod = diff * proj_lod; + vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod); + //float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0)); + float amb_da = proj_ambiance; + + amb_da += (da*da*0.5+0.5)*proj_ambiance; + + amb_da *= dist_atten * noise; + + amb_da = min(amb_da, 1.0-lit); + + col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + } + + + vec4 spec = texture2DRect(specularRect, frag.xy); + if (spec.a > 0.0) + { + vec3 ref = reflect(normalize(pos), norm); + + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); + + if (ds < 0.0) + { + vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; + + vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz; + + if (stc.z > 0.0) + { + stc.xy /= stc.z+proj_near; + + if (stc.x < 1.0 && + stc.y < 1.0 && + stc.x > 0.0 && + stc.y > 0.0) + { + vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); + col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb; + } + } + } + } + + gl_FragColor.rgb = col; + gl_FragColor.a = 0.0; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl index d43fe6ca9..56e4055c0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl @@ -5,135 +5,11 @@ * $License$ */ +//class 1, no shadow, no SSAO, should never be called + #extension GL_ARB_texture_rectangle : enable -uniform sampler2DRect positionMap; -uniform sampler2DRect normalMap; -uniform sampler2DRect depthMap; -uniform sampler2DShadow shadowMap0; -uniform sampler2DShadow shadowMap1; -uniform sampler2DShadow shadowMap2; -uniform sampler2DShadow shadowMap3; -uniform sampler2D noiseMap; - -// Inputs -uniform mat4 shadow_matrix[4]; -uniform vec4 shadow_clip; -uniform float ssao_radius; -uniform float ssao_max_radius; -uniform float ssao_factor; -uniform float ssao_factor_inv; - -varying vec2 vary_fragcoord; -varying vec4 vary_light; - -//calculate decreases in ambient lighting when crowded out (SSAO) -float calcAmbientOcclusion(vec4 pos, vec3 norm) -{ - vec2 kern[8]; - // exponentially (^2) distant occlusion samples spread around origin - kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; - kern[1] = vec2(1.0, 0.0) * 0.250*0.250; - kern[2] = vec2(0.0, 1.0) * 0.375*0.375; - kern[3] = vec2(0.0, -1.0) * 0.500*0.500; - kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; - kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; - kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; - kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; - - vec2 pos_screen = vary_fragcoord.xy; - vec3 pos_world = pos.xyz; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - - float angle_hidden = 0.0; - int points = 0; - - float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); - - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) - for (int i = 0; i < 8; i++) - { - vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); - vec3 samppos_world = texture2DRect(positionMap, samppos_screen).xyz; - - vec3 diff = pos_world - samppos_world; - float dist2 = dot(diff, diff); - - // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area - // --> solid angle shrinking by the square of distance - //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 - //(k should vary inversely with # of samples, but this is taken care of later) - - //if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) // -0.05*norm to shift sample point back slightly for flat surfaces - // angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional. max of 1.0 (= ssao_factor_inv * ssao_factor) - angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv); - - // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" - points = points + int(diff.z > -1.0); - } - - angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0); - - return 1.0 - (float(points != 0) * angle_hidden); -} - void main() { - vec2 pos_screen = vary_fragcoord.xy; - vec4 pos = vec4(texture2DRect(positionMap, pos_screen).xyz, 1.0); - vec3 norm = texture2DRect(normalMap, pos_screen).xyz; - - /*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL - { - gl_FragColor = vec4(0.0); // doesn't matter - return; - }*/ - - float shadow = 1.0; - float dp_directional_light = max(0.0, dot(norm, vary_light.xyz)); - - if (dp_directional_light == 0.0) - { - // if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup - shadow = 0.0; - } - else if (pos.z > -shadow_clip.w) - { - if (pos.z < -shadow_clip.z) - { - vec4 lpos = shadow_matrix[3]*pos; - shadow = shadow2DProj(shadowMap3, lpos).x; - shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); - } - else if (pos.z < -shadow_clip.y) - { - vec4 lpos = shadow_matrix[2]*pos; - shadow = shadow2DProj(shadowMap2, lpos).x; - } - else if (pos.z < -shadow_clip.x) - { - vec4 lpos = shadow_matrix[1]*pos; - shadow = shadow2DProj(shadowMap1, lpos).x; - } - else - { - vec4 lpos = shadow_matrix[0]*pos; - shadow = shadow2DProj(shadowMap0, lpos).x; - } - - // take the most-shadowed value out of these two: - // * the blurred sun shadow in the light (shadow) map - // * an unblurred dot product between the sun and this norm - // the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting - shadow = min(shadow, dp_directional_light); - } - else - { - // more distant than the shadow map covers - just use directional shading as shadow - shadow = dp_directional_light; - } - - gl_FragColor[0] = shadow; - gl_FragColor[1] = calcAmbientOcclusion(pos, norm); - //gl_FragColor[2] is unused as of August 2008, may be used for debugging + gl_FragColor = vec4(0,0,0,0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl new file mode 100644 index 000000000..cdbed4b79 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl @@ -0,0 +1,124 @@ +/** + * @file sunLightSSAOF.glsl + * + * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#extension GL_ARB_texture_rectangle : enable + +//class 1 -- no shadow, SSAO only + +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform sampler2D noiseMap; + +uniform sampler2D lightFunc; + + +// Inputs +uniform mat4 shadow_matrix[6]; +uniform vec4 shadow_clip; +uniform float ssao_radius; +uniform float ssao_max_radius; +uniform float ssao_factor; +uniform float ssao_factor_inv; + +varying vec2 vary_fragcoord; +varying vec4 vary_light; + +uniform mat4 inv_proj; +uniform vec2 screen_res; + +uniform float shadow_bias; +uniform float shadow_offset; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +//calculate decreases in ambient lighting when crowded out (SSAO) +float calcAmbientOcclusion(vec4 pos, vec3 norm) +{ + float ret = 1.0; + + float dist = dot(pos.xyz,pos.xyz); + + if (dist < 64.0*64.0) + { + vec2 kern[8]; + // exponentially (^2) distant occlusion samples spread around origin + kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; + kern[1] = vec2(1.0, 0.0) * 0.250*0.250; + kern[2] = vec2(0.0, 1.0) * 0.375*0.375; + kern[3] = vec2(0.0, -1.0) * 0.500*0.500; + kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; + kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; + kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; + kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; + + vec2 pos_screen = vary_fragcoord.xy; + vec3 pos_world = pos.xyz; + vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; + + float angle_hidden = 0.0; + int points = 0; + + float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); + + // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) + for (int i = 0; i < 8; i++) + { + vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); + vec3 samppos_world = getPosition(samppos_screen).xyz; + + vec3 diff = pos_world - samppos_world; + float dist2 = dot(diff, diff); + + // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area + // --> solid angle shrinking by the square of distance + //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 + //(k should vary inversely with # of samples, but this is taken care of later) + + //if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) // -0.05*norm to shift sample point back slightly for flat surfaces + // angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional. max of 1.0 (= ssao_factor_inv * ssao_factor) + angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv); + + // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" + points = points + int(diff.z > -1.0); + } + + angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0); + + ret = (1.0 - (float(points != 0) * angle_hidden)); + ret += max((dist-32.0*32.0)/(32.0*32.0), 0.0); + } + + return min(ret, 1.0); +} + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + + //try doing an unproject here + + vec4 pos = getPosition(pos_screen); + + vec3 norm = texture2DRect(normalMap, pos_screen).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + + gl_FragColor[0] = 1.0; + gl_FragColor[1] = calcAmbientOcclusion(pos, norm); + gl_FragColor[2] = 1.0; + gl_FragColor[3] = 1.0; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl index 211b2e039..fa0a60c98 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl @@ -12,7 +12,6 @@ uniform sampler2D detail_3; uniform sampler2D alpha_ramp; varying vec3 vary_normal; -varying vec4 vary_position; void main() { @@ -28,9 +27,9 @@ void main() float alphaFinal = texture2D(alpha_ramp, gl_TexCoord[1].zw).a; vec4 outColor = mix( mix(color3, color2, alpha2), mix(color1, color0, alpha1), alphaFinal ); - gl_FragData[0] = vec4(outColor.rgb, 1.0); + gl_FragData[0] = vec4(outColor.rgb, 0.0); gl_FragData[1] = vec4(outColor.rgb*0.2, 0.2); - gl_FragData[2] = vec4(normalize(vary_normal), 0.0); - gl_FragData[3] = vary_position; + vec3 nvn = normalize(vary_normal); + gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl index e9d6dcabf..3038b1477 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl @@ -6,7 +6,6 @@ */ varying vec3 vary_normal; -varying vec4 vary_position; vec4 texgen_object(vec4 vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1) { @@ -27,7 +26,6 @@ void main() //transform vertex gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; - vary_position = gl_ModelViewMatrix * gl_Vertex; vary_normal = normalize(gl_NormalMatrix * gl_Normal); // Transform and pass tex coords diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl index ea70eabf5..5b33ea5bf 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl @@ -8,13 +8,12 @@ uniform sampler2D diffuseMap; varying vec3 vary_normal; -varying vec4 vary_position; void main() { vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy); gl_FragData[0] = vec4(gl_Color.rgb*col.rgb, col.a <= 0.5 ? 0.0 : 0.005); gl_FragData[1] = vec4(0,0,0,0); - gl_FragData[2] = vec4(normalize(vary_normal), 0.0); - gl_FragData[3] = vary_position; + vec3 nvn = normalize(vary_normal); + gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl index 9131d7c2b..6b9dc2def 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl @@ -6,7 +6,6 @@ */ varying vec3 vary_normal; -varying vec4 vary_position; void main() { @@ -14,8 +13,6 @@ void main() gl_Position = ftransform(); gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; - vary_position = gl_ModelViewMatrix * gl_Vertex; - vary_normal = normalize(gl_NormalMatrix * gl_Normal); gl_FrontColor = gl_Color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl index 83959101e..a8c7e3fc3 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl @@ -12,13 +12,13 @@ vec3 atmosTransport(vec3 inColor); uniform sampler2D bumpMap; uniform sampler2D screenTex; uniform sampler2D refTex; -uniform sampler2DShadow shadowMap0; -uniform sampler2DShadow shadowMap1; -uniform sampler2DShadow shadowMap2; -uniform sampler2DShadow shadowMap3; +uniform sampler2DRectShadow shadowMap0; +uniform sampler2DRectShadow shadowMap1; +uniform sampler2DRectShadow shadowMap2; +uniform sampler2DRectShadow shadowMap3; uniform sampler2D noiseMap; -uniform mat4 shadow_matrix[4]; +uniform mat4 shadow_matrix[6]; uniform vec4 shadow_clip; uniform float sunAngle; @@ -33,9 +33,9 @@ uniform vec3 normScale; uniform float fresnelScale; uniform float fresnelOffset; uniform float blurMultiplier; +uniform vec2 screen_res; uniform mat4 norm_mat; //region space to screen space - //bigWave is (refCoord.w, view.w); varying vec4 refCoord; varying vec4 littleWave; @@ -114,51 +114,27 @@ void main() vec4 fb = texture2D(screenTex, distort2); //mix with reflection - // Note we actually want to use just df1, but multiplying by 0.999999 gets around and nvidia compiler bug + // Note we actually want to use just df1, but multiplying by 0.999999 gets around an nvidia compiler bug color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999); float shadow = 1.0; vec4 pos = vary_position; //vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz; - -// if (pos.z > -shadow_clip.w) -// { - vec4 spos = pos; - -/* if (pos.z < -shadow_clip.z) - { - vec4 lpos = (shadow_matrix[3]*spos); - shadow = shadow2DProj(shadowMap3, lpos).x; - } - else if (pos.z < -shadow_clip.y) - { - vec4 lpos = (shadow_matrix[2]*spos); - shadow = shadow2DProj(shadowMap2, lpos).x; - } - else if (pos.z < -shadow_clip.x) - { - vec4 lpos = (shadow_matrix[1]*spos); - shadow = shadow2DProj(shadowMap1, lpos).x; - } - else - { - vec4 lpos = (shadow_matrix[0]*spos); - shadow = shadow2DProj(shadowMap0, lpos).x; - } - }*/ + vec4 spos = pos; + + //spec *= shadow; + //color.rgb += spec * specular; -// spec *= shadow; -// color.rgb += spec * specular; - -// color.rgb = atmosTransport(color.rgb); -// color.rgb = scaleSoftClip(color.rgb); -// color.a = spec * sunAngle2; + //color.rgb = atmosTransport(color.rgb); + //color.rgb = scaleSoftClip(color.rgb); + //color.a = spec * sunAngle2; -// gl_FragColor = color; + //wavef.z *= 0.1f; + //wavef = normalize(wavef); vec3 screenspacewavef = (norm_mat*vec4(wavef, 1.0)).xyz; gl_FragData[0] = vec4(color.rgb, 0.5); // diffuse gl_FragData[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec - gl_FragData[2] = vec4(screenspacewavef, 0.0); // normalxyz, displace + gl_FragData[2] = vec4(screenspacewavef.xy*0.5+0.5, screenspacewavef.z, screenspacewavef.z*0.5); // normalxyz, displace } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl index 3e8fdfb3e..00ce944d4 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl @@ -12,7 +12,8 @@ float calcDirectionalLight(vec3 n, vec3 l) return a; } -float calcPointLight(vec3 v, vec3 n, vec4 lp, float la) + +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight) { //get light vector vec3 lv = lp.xyz-v; @@ -26,6 +27,10 @@ float calcPointLight(vec3 v, vec3 n, vec4 lp, float la) //distance attenuation float da = clamp(1.0/(la * d), 0.0, 1.0); + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 + //angular attenuation da *= calcDirectionalLight(n, lv); diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl new file mode 100644 index 000000000..4e16e87d8 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -0,0 +1,127 @@ +/** + * @file alphaF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2D diffuseMap; +uniform sampler2DRectShadow shadowMap0; +uniform sampler2DRectShadow shadowMap1; +uniform sampler2DRectShadow shadowMap2; +uniform sampler2DRectShadow shadowMap3; +uniform sampler2D noiseMap; +uniform sampler2DRect depthMap; + +uniform mat4 shadow_matrix[6]; +uniform vec4 shadow_clip; +uniform vec2 screen_res; +uniform vec2 shadow_res; + +vec3 atmosLighting(vec3 light); +vec3 scaleSoftClip(vec3 light); + +varying vec3 vary_ambient; +varying vec3 vary_directional; +varying vec3 vary_fragcoord; +varying vec3 vary_position; +varying vec3 vary_light; +varying vec3 vary_pointlight_col; + +uniform float shadow_bias; + +uniform mat4 inv_proj; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos.xyz /= pos.w; + pos.w = 1.0; + return pos; +} + +float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl) +{ + stc.xyz /= stc.w; + stc.z += shadow_bias; + + float cs = shadow2DRect(shadowMap, stc.xyz).x; + float shadow = cs; + + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, scl, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, -scl, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, scl, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, -scl, 0.0)).x, cs); + + return shadow/5.0; +} + + +void main() +{ + vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; + frag *= screen_res; + + vec3 samp_pos = getPosition(frag).xyz; + + float shadow = 1.0; + vec4 pos = vec4(vary_position, 1.0); + + vec4 spos = pos; + + if (spos.z > -shadow_clip.w) + { + vec4 lpos; + + if (spos.z < -shadow_clip.z) + { + lpos = shadow_matrix[3]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap3, lpos, 1.5); + shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); + } + else if (spos.z < -shadow_clip.y) + { + lpos = shadow_matrix[2]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap2, lpos, 1.5); + } + else if (spos.z < -shadow_clip.x) + { + lpos = shadow_matrix[1]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap1, lpos, 1.5); + } + else + { + lpos = shadow_matrix[0]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap0, lpos, 1.5); + } + } + + vec4 diff= texture2D(diffuseMap, gl_TexCoord[0].xy); + + vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, gl_Color.a); + vec4 color = diff * col; + + color.rgb = atmosLighting(color.rgb); + + color.rgb = scaleSoftClip(color.rgb); + + color.rgb += diff.rgb * vary_pointlight_col.rgb; + + //gl_FragColor = gl_Color; + gl_FragColor = color; + //gl_FragColor.r = 0.0; + //gl_FragColor = vec4(1,0,1,1)*shadow; + +} + diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl new file mode 100644 index 000000000..da25c42e4 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl @@ -0,0 +1,103 @@ +/** + * @file alphaV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +void calcAtmospherics(vec3 inPositionEye); + +float calcDirectionalLight(vec3 n, vec3 l); +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); + +vec3 atmosAmbient(vec3 light); +vec3 atmosAffectDirectionalLight(float lightIntensity); +vec3 scaleDownLight(vec3 light); +vec3 scaleUpLight(vec3 light); + +varying vec3 vary_ambient; +varying vec3 vary_directional; +varying vec3 vary_fragcoord; +varying vec3 vary_position; +varying vec3 vary_light; +varying vec3 vary_pointlight_col; + +uniform float near_clip; +uniform float shadow_offset; +uniform float shadow_bias; + +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight) +{ + //get light vector + vec3 lv = lp.xyz-v; + + //get distance + float d = length(lv); + + //normalize light vector + lv *= 1.0/d; + + //distance attenuation + float dist2 = d*d/(la*la); + float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + 45 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 + + //angular attenuation + da *= calcDirectionalLight(n, lv); + + return da; +} + +void main() +{ + //transform vertex + gl_Position = ftransform(); + + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + + vec4 pos = (gl_ModelViewMatrix * gl_Vertex); + vec3 norm = normalize(gl_NormalMatrix * gl_Normal); + + float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz)); + vary_position = pos.xyz + gl_LightSource[0].position.xyz * (1.0-dp_directional_light)*shadow_offset; + + calcAtmospherics(pos.xyz); + + //vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.)); + + vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a); + + // Collect normal lights + col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation, gl_LightSource[2].specular.a); + col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation, gl_LightSource[3].specular.a); + col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation, gl_LightSource[4].specular.a); + col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation, gl_LightSource[5].specular.a); + col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation, gl_LightSource[6].specular.a); + col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation, gl_LightSource[7].specular.a); + + vary_pointlight_col = col.rgb*gl_Color.rgb; + + col.rgb = vec3(0,0,0); + + // Add windlight lights + col.rgb = atmosAmbient(vec3(0.)); + + vary_light = gl_LightSource[0].position.xyz; + + vary_ambient = col.rgb*gl_Color.rgb; + vary_directional.rgb = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a))); + + col.rgb = col.rgb*gl_Color.rgb; + + gl_FrontColor = col; + + gl_FogFragCoord = pos.z; + + pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip); + +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl new file mode 100644 index 000000000..5ecbbd2c4 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl @@ -0,0 +1,98 @@ +/** + * @file avatarAlphaF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2D diffuseMap; +uniform sampler2DRectShadow shadowMap0; +uniform sampler2DRectShadow shadowMap1; +uniform sampler2DRectShadow shadowMap2; +uniform sampler2DRectShadow shadowMap3; +uniform sampler2D noiseMap; + +uniform mat4 shadow_matrix[6]; +uniform vec4 shadow_clip; +uniform vec2 screen_res; +uniform vec2 shadow_res; + +vec3 atmosLighting(vec3 light); +vec3 scaleSoftClip(vec3 light); + +varying vec3 vary_ambient; +varying vec3 vary_directional; +varying vec3 vary_position; +varying vec3 vary_normal; + +uniform float shadow_bias; + +float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl) +{ + stc.xyz /= stc.w; + stc.z += shadow_bias; + + float cs = shadow2DRect(shadowMap, stc.xyz).x; + float shadow = cs; + + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, scl, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, -scl, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, scl, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, -scl, 0.0)).x, cs); + + return shadow/5.0; +} + +void main() +{ + float shadow = 1.0; + vec4 pos = vec4(vary_position, 1.0); + vec3 norm = normalize(vary_normal); + + //vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz; + + vec4 spos = pos; + + if (spos.z > -shadow_clip.w) + { + vec4 lpos; + + if (spos.z < -shadow_clip.z) + { + lpos = shadow_matrix[3]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap3, lpos, 1.5); + shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); + } + else if (spos.z < -shadow_clip.y) + { + lpos = shadow_matrix[2]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap2, lpos, 1.5); + } + else if (spos.z < -shadow_clip.x) + { + lpos = shadow_matrix[1]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap1, lpos, 1.5); + } + else + { + lpos = shadow_matrix[0]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap0, lpos, 1.5); + } + } + + + vec4 col = vec4(vary_ambient + vary_directional*shadow, gl_Color.a); + vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col; + + color.rgb = atmosLighting(color.rgb); + + color.rgb = scaleSoftClip(color.rgb); + + gl_FragColor = color; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl new file mode 100644 index 000000000..d7d1111ba --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl @@ -0,0 +1,83 @@ +/** + * @file avatarAlphaV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); +mat4 getSkinnedTransform(); +void calcAtmospherics(vec3 inPositionEye); + +float calcDirectionalLight(vec3 n, vec3 l); +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); + +vec3 atmosAmbient(vec3 light); +vec3 atmosAffectDirectionalLight(float lightIntensity); +vec3 scaleDownLight(vec3 light); +vec3 scaleUpLight(vec3 light); + +varying vec3 vary_position; +varying vec3 vary_ambient; +varying vec3 vary_directional; +varying vec3 vary_normal; + +uniform float near_clip; +uniform float shadow_offset; +uniform float shadow_bias; + +void main() +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + + vec4 pos; + vec3 norm; + + mat4 trans = getSkinnedTransform(); + pos.x = dot(trans[0], gl_Vertex); + pos.y = dot(trans[1], gl_Vertex); + pos.z = dot(trans[2], gl_Vertex); + pos.w = 1.0; + + norm.x = dot(trans[0].xyz, gl_Normal); + norm.y = dot(trans[1].xyz, gl_Normal); + norm.z = dot(trans[2].xyz, gl_Normal); + norm = normalize(norm); + + gl_Position = gl_ProjectionMatrix * pos; + + float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz)); + vary_position = pos.xyz + gl_LightSource[0].position.xyz * (1.0-dp_directional_light)*shadow_offset; + vary_normal = norm; + + calcAtmospherics(pos.xyz); + + //vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.)); + + vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a); + + // Collect normal lights (need to be divided by two, as we later multiply by 2) + col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a); + col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a); + col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a); + col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a); + col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a); + col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a); + col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz); + col.rgb = scaleDownLight(col.rgb); + + // Add windlight lights + col.rgb += atmosAmbient(vec3(0.)); + + vary_ambient = col.rgb*gl_Color.rgb; + vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a))); + + col.rgb = min(col.rgb*gl_Color.rgb, 1.0); + + gl_FrontColor = col; + + gl_FogFragCoord = pos.z; + +} + + diff --git a/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl new file mode 100644 index 000000000..258a9b7c4 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl @@ -0,0 +1,81 @@ +/** + * @file blurLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform sampler2DRect lightMap; + +uniform float dist_factor; +uniform float blur_size; +uniform vec2 delta; +uniform vec3 kern[4]; +uniform float kern_scale; + +varying vec2 vary_fragcoord; + +uniform mat4 inv_proj; +uniform vec2 screen_res; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +void main() +{ + vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + vec3 pos = getPosition(vary_fragcoord.xy).xyz; + vec4 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rgba; + + vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy); + + dlt /= max(-pos.z*dist_factor, 1.0); + + vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free' + vec4 col = defined_weight.xyxx * ccol; + + for (int i = 1; i < 4; i++) + { + vec2 tc = vary_fragcoord.xy + kern[i].z*dlt; + vec3 samppos = getPosition(tc).xyz; + float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane + if (d*d <= 0.003) + { + col += texture2DRect(lightMap, tc)*kern[i].xyxx; + defined_weight += kern[i].xy; + } + } + for (int i = 1; i < 4; i++) + { + vec2 tc = vary_fragcoord.xy - kern[i].z*dlt; + vec3 samppos = getPosition(tc).xyz; + float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane + if (d*d <= 0.003) + { + col += texture2DRect(lightMap, tc)*kern[i].xyxx; + defined_weight += kern[i].xy; + } + } + + + + col /= defined_weight.xyxx; + + gl_FragColor = col; +} + diff --git a/indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl new file mode 100644 index 000000000..b1b3f55f0 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl @@ -0,0 +1,17 @@ +/** + * @file blurLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl new file mode 100644 index 000000000..ff32a15c5 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl @@ -0,0 +1,63 @@ +/** + * @file edgeF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; + +uniform float gi_dist_cutoff; + +varying vec2 vary_fragcoord; + +uniform float depth_cutoff; +uniform float norm_cutoff; + +uniform mat4 inv_proj; +uniform vec2 screen_res; + +float getDepth(vec2 pos_screen) +{ + float z = texture2DRect(depthMap, pos_screen.xy).a; + z = z*2.0-1.0; + vec4 ndc = vec4(0.0, 0.0, z, 1.0); + vec4 p = inv_proj*ndc; + return p.z/p.w; +} + +void main() +{ + vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + float depth = getDepth(vary_fragcoord.xy); + + vec2 tc = vary_fragcoord.xy; + + float sc = 0.75; + + vec2 de; + de.x = (depth-getDepth(tc+vec2(sc, sc))) + (depth-getDepth(tc+vec2(-sc, -sc))); + de.y = (depth-getDepth(tc+vec2(-sc, sc))) + (depth-getDepth(tc+vec2(sc, -sc))); + de /= depth; + de *= de; + de = step(depth_cutoff, de); + + vec2 ne; + vec3 nexnorm = texture2DRect(normalMap, tc+vec2(-sc,-sc)).rgb; + nexnorm = vec3((nexnorm.xy-0.5)*2.0,nexnorm.z); // unpack norm + ne.x = dot(nexnorm, norm); + vec3 neynorm = texture2DRect(normalMap, tc+vec2(sc,sc)).rgb; + neynorm = vec3((neynorm.xy-0.5)*2.0,neynorm.z); // unpack norm + ne.y = dot(neynorm, norm); + + ne = 1.0-ne; + + ne = step(norm_cutoff, ne); + + gl_FragColor.a = dot(de,de)+dot(ne,ne); + //gl_FragColor.a = dot(de,de); +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl new file mode 100644 index 000000000..74f2bd981 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl @@ -0,0 +1,17 @@ +/** + * @file edgeV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl new file mode 100644 index 000000000..d6cd984eb --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl @@ -0,0 +1,236 @@ +/** + * @file multiSpotLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#version 120 + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform samplerCube environmentMap; +uniform sampler2DRect lightMap; +uniform sampler2D noiseMap; +uniform sampler2D lightFunc; +uniform sampler2D projectionMap; + +uniform mat4 proj_mat; //screen space to light space +uniform float proj_near; //near clip for projection +uniform vec3 proj_p; //plane projection is emitting from (in screen space) +uniform vec3 proj_n; +uniform float proj_focus; //distance from plane to begin blurring +uniform float proj_lod; //(number of mips in proj map) +uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambient_lod; +uniform float proj_ambiance; +uniform float near_clip; +uniform float far_clip; + +uniform vec3 proj_origin; //origin of projection to be used for angular attenuation +uniform float sun_wash; +uniform int proj_shadow_idx; +uniform float shadow_fade; + +varying vec4 vary_light; + +varying vec4 vary_fragcoord; +uniform vec2 screen_res; + +uniform mat4 inv_proj; + +vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float det = max(1.0-lod/(proj_lod*0.5), 0.0); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); + + return ret; +} + +vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + + float det = min(lod/(proj_lod*0.5), 1.0); + + float d = min(dist.x, dist.y); + + float edge = 0.25*det; + + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; +} + + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +void main() +{ + vec4 frag = vary_fragcoord; + frag.xyz /= frag.w; + frag.xyz = frag.xyz*0.5+0.5; + frag.xy *= screen_res; + + vec3 pos = getPosition(frag.xy).xyz; + vec3 lv = vary_light.xyz-pos.xyz; + float dist2 = dot(lv,lv); + dist2 /= vary_light.w; + if (dist2 > 1.0) + { + discard; + } + + float shadow = 1.0; + + if (proj_shadow_idx >= 0) + { + vec4 shd = texture2DRect(lightMap, frag.xy); + float sh[2]; + sh[0] = shd.b; + sh[1] = shd.a; + shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0); + } + + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + + norm = normalize(norm); + float l_dist = -dot(lv, proj_n); + + vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); + if (proj_tc.z < 0.0) + { + discard; + } + + proj_tc.xyz /= proj_tc.w; + + float fa = gl_Color.a+1.0; + float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + if (dist_atten <= 0.0) + { + discard; + } + + lv = proj_origin-pos.xyz; + lv = normalize(lv); + float da = dot(norm, lv); + + vec3 col = vec3(0,0,0); + + vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; + + float noise = texture2D(noiseMap, frag.xy/128.0).b; + if (proj_tc.z > 0.0 && + proj_tc.x < 1.0 && + proj_tc.y < 1.0 && + proj_tc.x > 0.0 && + proj_tc.y > 0.0) + { + float lit = 0.0; + float amb_da = proj_ambiance; + + if (da > 0.0) + { + float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); + float lod = diff * proj_lod; + + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); + + vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a; + + lit = da * dist_atten * noise; + + col = lcol*lit*diff_tex*shadow; + amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance; + } + + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); + vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); + + amb_da += (da*da*0.5+0.5)*proj_ambiance; + + amb_da *= dist_atten * noise; + + amb_da = min(amb_da, 1.0-lit); + + col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + } + + + vec4 spec = texture2DRect(specularRect, frag.xy); + if (spec.a > 0.0) + { + vec3 ref = reflect(normalize(pos), norm); + + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); + + if (ds < 0.0) + { + vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; + + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); + + if (stc.z > 0.0) + { + stc.xy /= stc.w; + + float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); + + stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); + + if (stc.x < 1.0 && + stc.y < 1.0 && + stc.x > 0.0 && + stc.y > 0.0) + { + vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); + col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb*shadow; + } + } + } + } + + gl_FragColor.rgb = col; + gl_FragColor.a = 0.0; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl new file mode 100644 index 000000000..757e3e7aa --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl @@ -0,0 +1,59 @@ +/** + * @file postDeferredF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect localLightMap; +uniform sampler2DRect sunLightMap; +uniform sampler2DRect giLightMap; +uniform sampler2D luminanceMap; +uniform sampler2DRect lightMap; + +uniform vec3 gi_lum_quad; +uniform vec3 sun_lum_quad; +uniform vec3 lum_quad; +uniform float lum_lod; +uniform vec4 ambient; + +uniform vec3 gi_quad; + +uniform vec2 screen_res; +varying vec2 vary_fragcoord; + +void main() +{ + vec2 tc = vary_fragcoord.xy; + vec3 lcol = texture2DLod(luminanceMap, tc/screen_res, lum_lod).rgb; + + float lum = sqrt(lcol.r)*lum_quad.x+lcol.r*lcol.r*lum_quad.y+lcol.r*lum_quad.z; + + vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy); + + float ambocc = texture2DRect(lightMap, vary_fragcoord.xy).g; + + vec3 gi_col = texture2DRect(giLightMap, vary_fragcoord.xy).rgb; + gi_col = gi_col*gi_col*gi_quad.x + gi_col*gi_quad.y+gi_quad.z*ambocc*ambient.rgb; + gi_col *= diff; + + vec4 sun_col = texture2DRect(sunLightMap, vary_fragcoord.xy); + + vec3 local_col = texture2DRect(localLightMap, vary_fragcoord.xy).rgb; + + + float sun_lum = 1.0-lum; + sun_lum = sun_lum*sun_lum*sun_lum_quad.x + sun_lum*sun_lum_quad.y+sun_lum_quad.z; + + float gi_lum = lum; + gi_lum = gi_lum*gi_lum*gi_lum_quad.x+gi_lum*gi_lum_quad.y+gi_lum_quad.z; + gi_col *= 1.0/gi_lum; + + vec3 col = sun_col.rgb*(1.0+max(sun_lum,0.0))+gi_col+local_col; + + gl_FragColor.rgb = col.rgb; + gl_FragColor.a = max(sun_lum*min(sun_col.r+sun_col.g+sun_col.b, 1.0), sun_col.a); + + //gl_FragColor.rgb = texture2DRect(giLightMap, vary_fragcoord.xy).rgb; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl new file mode 100644 index 000000000..0ec81dcb0 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl @@ -0,0 +1,17 @@ +/** + * @file postDeferredV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl new file mode 100644 index 000000000..1067be1e6 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl @@ -0,0 +1,344 @@ +/** + * @file softenLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect normalMap; +uniform sampler2DRect lightMap; +uniform sampler2DRect depthMap; +uniform sampler2D noiseMap; +uniform samplerCube environmentMap; +uniform sampler2D lightFunc; +uniform vec3 gi_quad; + +uniform float blur_size; +uniform float blur_fidelity; + +// Inputs +uniform vec4 morphFactor; +uniform vec3 camPosLocal; +//uniform vec4 camPosWorld; +uniform vec4 gamma; +uniform vec4 lightnorm; +uniform vec4 sunlight_color; +uniform vec4 ambient; +uniform vec4 blue_horizon; +uniform vec4 blue_density; +uniform vec4 haze_horizon; +uniform vec4 haze_density; +uniform vec4 cloud_shadow; +uniform vec4 density_multiplier; +uniform vec4 distance_multiplier; +uniform vec4 max_y; +uniform vec4 glow; +uniform float scene_light_strength; +uniform vec3 env_mat[3]; +uniform vec4 shadow_clip; +uniform mat3 ssao_effect_mat; + +uniform mat4 inv_proj; +uniform vec2 screen_res; + +varying vec4 vary_light; +varying vec2 vary_fragcoord; + +vec3 vary_PositionEye; + +vec3 vary_SunlitColor; +vec3 vary_AmblitColor; +vec3 vary_AdditiveColor; +vec3 vary_AtmosAttenuation; + +vec4 getPosition_d(vec2 pos_screen, float depth) +{ + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec4 getPosition(vec2 pos_screen) +{ //get position in screen space (world units) given window coordinate and depth map + float depth = texture2DRect(depthMap, pos_screen.xy).a; + return getPosition_d(pos_screen, depth); +} + +vec3 getPositionEye() +{ + return vary_PositionEye; +} +vec3 getSunlitColor() +{ + return vary_SunlitColor; +} +vec3 getAmblitColor() +{ + return vary_AmblitColor; +} +vec3 getAdditiveColor() +{ + return vary_AdditiveColor; +} +vec3 getAtmosAttenuation() +{ + return vary_AtmosAttenuation; +} + + +void setPositionEye(vec3 v) +{ + vary_PositionEye = v; +} + +void setSunlitColor(vec3 v) +{ + vary_SunlitColor = v; +} + +void setAmblitColor(vec3 v) +{ + vary_AmblitColor = v; +} + +void setAdditiveColor(vec3 v) +{ + vary_AdditiveColor = v; +} + +void setAtmosAttenuation(vec3 v) +{ + vary_AtmosAttenuation = v; +} + +void calcAtmospherics(vec3 inPositionEye, float ambFactor) { + + vec3 P = inPositionEye; + setPositionEye(P); + + //(TERRAIN) limit altitude + if (P.y > max_y.x) P *= (max_y.x / P.y); + if (P.y < -max_y.x) P *= (-max_y.x / P.y); + + vec3 tmpLightnorm = lightnorm.xyz; + + vec3 Pn = normalize(P); + float Plen = length(P); + + vec4 temp1 = vec4(0); + vec3 temp2 = vec3(0); + vec4 blue_weight; + vec4 haze_weight; + vec4 sunlight = sunlight_color; + vec4 light_atten; + + //sunlight attenuation effect (hue and brightness) due to atmosphere + //this is used later for sunlight modulation at various altitudes + light_atten = (blue_density * 1.0 + vec4(haze_density.r) * 0.25) * (density_multiplier.x * max_y.x); + //I had thought blue_density and haze_density should have equal weighting, + //but attenuation due to haze_density tends to seem too strong + + temp1 = blue_density + vec4(haze_density.r); + blue_weight = blue_density / temp1; + haze_weight = vec4(haze_density.r) / temp1; + + //(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain) + temp2.y = max(0.0, tmpLightnorm.y); + temp2.y = 1. / temp2.y; + sunlight *= exp( - light_atten * temp2.y); + + // main atmospheric scattering line integral + temp2.z = Plen * density_multiplier.x; + + // Transparency (-> temp1) + // ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier.x in a variable because the ati + // compiler gets confused. + temp1 = exp(-temp1 * temp2.z * distance_multiplier.x); + + //final atmosphere attenuation factor + setAtmosAttenuation(temp1.rgb); + + //compute haze glow + //(can use temp2.x as temp because we haven't used it yet) + temp2.x = dot(Pn, tmpLightnorm.xyz); + temp2.x = 1. - temp2.x; + //temp2.x is 0 at the sun and increases away from sun + temp2.x = max(temp2.x, .03); //was glow.y + //set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) + temp2.x *= glow.x; + //higher glow.x gives dimmer glow (because next step is 1 / "angle") + temp2.x = pow(temp2.x, glow.z); + //glow.z should be negative, so we're doing a sort of (1 / "angle") function + + //add "minimum anti-solar illumination" + temp2.x += .25; + + //increase ambient when there are more clouds + vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow.x * 0.5; + + /* decrease value and saturation (that in HSV, not HSL) for occluded areas + * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html + * // The following line of code performs the equivalent of: + * float ambAlpha = tmpAmbient.a; + * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis + * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue); + * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha); + */ + tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); + + //haze color + setAdditiveColor( + vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow.x) + tmpAmbient) + + (haze_horizon.r * haze_weight) * (sunlight*(1.-cloud_shadow.x) * temp2.x + + tmpAmbient))); + + //brightness of surface both sunlight and ambient + setSunlitColor(vec3(sunlight * .5)); + setAmblitColor(vec3(tmpAmbient * .25)); + setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1)); +} + +vec3 atmosLighting(vec3 light) +{ + light *= getAtmosAttenuation().r; + light += getAdditiveColor(); + return (2.0 * light); +} + +vec3 atmosTransport(vec3 light) { + light *= getAtmosAttenuation().r; + light += getAdditiveColor() * 2.0; + return light; +} +vec3 atmosGetDiffuseSunlightColor() +{ + return getSunlitColor(); +} + +vec3 scaleDownLight(vec3 light) +{ + return (light / scene_light_strength ); +} + +vec3 scaleUpLight(vec3 light) +{ + return (light * scene_light_strength); +} + +vec3 atmosAmbient(vec3 light) +{ + return getAmblitColor() + light / 2.0; +} + +vec3 atmosAffectDirectionalLight(float lightIntensity) +{ + return getSunlitColor() * lightIntensity; +} + +vec3 scaleSoftClip(vec3 light) +{ + //soft clip effect: + light = 1. - clamp(light, vec3(0.), vec3(1.)); + light = 1. - pow(light, gamma.xxx); + + return light; +} + +void main() +{ + vec2 tc = vary_fragcoord.xy; + float depth = texture2DRect(depthMap, tc.xy).a; + vec3 pos = getPosition_d(tc, depth).xyz; + vec3 norm = texture2DRect(normalMap, tc).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + //vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz; + + float da = max(dot(norm.xyz, vary_light.xyz), 0.0); + + vec4 diffuse = texture2DRect(diffuseRect, tc); + vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); + + vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg; + float scol = max(scol_ambocc.r, diffuse.a); + float ambocc = scol_ambocc.g; + + calcAtmospherics(pos.xyz, ambocc); + + vec3 col = atmosAmbient(vec3(0)); + col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a)); + + col *= diffuse.rgb; + + if (spec.a > 0.0) // specular reflection + { + // the old infinite-sky shiny reflection + // + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + float sa = dot(refnormpersp, vary_light.xyz); + vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a; + + /* + // screen-space cheap fakey reflection map + // + vec3 refnorm = normalize(reflect(vec3(0,0,-1), norm.xyz)); + depth -= 0.5; // unbias depth + // first figure out where we'll make our 2D guess from + vec2 ref2d = (0.25 * screen_res.y) * (refnorm.xy) * abs(refnorm.z) / depth; + // Offset the guess source a little according to a trivial + // checkerboard dither function and spec.a. + // This is meant to be similar to sampling a blurred version + // of the diffuse map. LOD would be better in that regard. + // The goal of the blur is to soften reflections in surfaces + // with low shinyness, and also to disguise our lameness. + float checkerboard = floor(mod(tc.x+tc.y, 2.0)); // 0.0, 1.0 + float checkoffset = (3.0 + (7.0*(1.0-spec.a)))*(checkerboard-0.5); + ref2d += vec2(checkoffset, checkoffset); + ref2d += tc.xy; // use as offset from destination + // Get attributes from the 2D guess point. + // We average two samples of diffuse (not of anything else) per + // pixel to try to reduce aliasing some more. + vec3 refcol = 0.5 * (texture2DRect(diffuseRect, ref2d + vec2(0.0, -checkoffset)).rgb + + texture2DRect(diffuseRect, ref2d + vec2(-checkoffset, 0.0)).rgb); + float refdepth = texture2DRect(depthMap, ref2d).a; + vec3 refpos = getPosition_d(ref2d, refdepth).xyz; + float refshad = texture2DRect(lightMap, ref2d).r; + vec3 refn = texture2DRect(normalMap, ref2d).rgb; + refn = vec3((refn.xy-0.5)*2.0,refn.z); // unpack norm + refn = normalize(refn); + // figure out how appropriate our guess actually was + float refapprop = max(0.0, dot(-refnorm, normalize(pos - refpos))); + // darken reflections from points which face away from the reflected ray - our guess was a back-face + //refapprop *= step(dot(refnorm, refn), 0.0); + refapprop = min(refapprop, max(0.0, -dot(refnorm, refn))); // more conservative variant + // get appropriate light strength for guess-point + // reflect light direction to increase the illusion that + // these are reflections. + vec3 reflight = reflect(lightnorm.xyz, norm.xyz); + float reflit = min(max(dot(refn, reflight.xyz), 0.0), refshad); + // apply sun color to guess-point, dampen according to inappropriateness of guess + float refmod = min(refapprop, reflit); + vec3 refprod = vary_SunlitColor * refcol.rgb * refmod; + vec3 ssshiny = (refprod * spec.a); + ssshiny *= 0.3; // dampen it even more + */ + vec3 ssshiny = vec3(0,0,0); + + // add the two types of shiny together + col += (ssshiny + dumbshiny) * spec.rgb; + } + + col = atmosLighting(col); + col = scaleSoftClip(col); + + gl_FragColor.rgb = col; + gl_FragColor.a = 0.0; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl new file mode 100644 index 000000000..9d187b46e --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl @@ -0,0 +1,24 @@ +/** + * @file softenLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +uniform vec2 screen_res; + +varying vec4 vary_light; +varying vec2 vary_fragcoord; +void main() +{ + //transform vertex + gl_Position = ftransform(); + + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; + + vec4 tex = gl_MultiTexCoord0; + tex.w = 1.0; + + vary_light = gl_MultiTexCoord0; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl new file mode 100644 index 000000000..d0e242c2d --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl @@ -0,0 +1,185 @@ +/** + * @file spotLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#version 120 + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform samplerCube environmentMap; +uniform sampler2DRect lightMap; +uniform sampler2D noiseMap; +uniform sampler2D lightFunc; +uniform sampler2D projectionMap; + +uniform mat4 proj_mat; //screen space to light space +uniform float proj_near; //near clip for projection +uniform vec3 proj_p; //plane projection is emitting from (in screen space) +uniform vec3 proj_n; +uniform float proj_focus; //distance from plane to begin blurring +uniform float proj_lod; //(number of mips in proj map) +uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambiance; +uniform float near_clip; +uniform float far_clip; + +uniform vec3 proj_origin; //origin of projection to be used for angular attenuation +uniform float sun_wash; +uniform int proj_shadow_idx; +uniform float shadow_fade; + +varying vec4 vary_light; + +varying vec4 vary_fragcoord; +uniform vec2 screen_res; + +uniform mat4 inv_proj; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +void main() +{ + vec4 frag = vary_fragcoord; + frag.xyz /= frag.w; + frag.xyz = frag.xyz*0.5+0.5; + frag.xy *= screen_res; + + float shadow = 1.0; + + if (proj_shadow_idx >= 0) + { + vec4 shd = texture2DRect(lightMap, frag.xy); + float sh[2]; + sh[0] = shd.b; + sh[1] = shd.a; + shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0); + } + + vec3 pos = getPosition(frag.xy).xyz; + vec3 lv = vary_light.xyz-pos.xyz; + float dist2 = dot(lv,lv); + dist2 /= vary_light.w; + if (dist2 > 1.0) + { + discard; + } + + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + + norm = normalize(norm); + float l_dist = -dot(lv, proj_n); + + vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); + if (proj_tc.z < 0.0) + { + discard; + } + + proj_tc.xyz /= proj_tc.w; + + float fa = gl_Color.a+1.0; + float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + + lv = proj_origin-pos.xyz; + lv = normalize(lv); + float da = dot(norm, lv); + + vec3 col = vec3(0,0,0); + + vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; + + float noise = texture2D(noiseMap, frag.xy/128.0).b; + if (proj_tc.z > 0.0 && + proj_tc.x < 1.0 && + proj_tc.y < 1.0 && + proj_tc.x > 0.0 && + proj_tc.y > 0.0) + { + float lit = 0.0; + if (da > 0.0) + { + float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); + float lod = diff * proj_lod; + + vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod); + + vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a; + + lit = da * dist_atten * noise; + + col = lcol*lit*diff_tex*shadow; + } + + float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); + float lod = diff * proj_lod; + vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod); + //float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0)); + float amb_da = proj_ambiance; + if (da > 0.0) + { + amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance; + } + + amb_da += (da*da*0.5+0.5)*proj_ambiance; + + amb_da *= dist_atten * noise; + + amb_da = min(amb_da, 1.0-lit); + + col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + } + + + vec4 spec = texture2DRect(specularRect, frag.xy); + if (spec.a > 0.0) + { + vec3 ref = reflect(normalize(pos), norm); + + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); + + if (ds < 0.0) + { + vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; + + vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz; + + if (stc.z > 0.0) + { + stc.xy /= stc.z+proj_near; + + if (stc.x < 1.0 && + stc.y < 1.0 && + stc.x > 0.0 && + stc.y > 0.0) + { + vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); + col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb*shadow; + } + } + } + } + + gl_FragColor.rgb = col; + gl_FragColor.a = 0.0; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl new file mode 100644 index 000000000..f565d3bdb --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl @@ -0,0 +1,197 @@ +/** + * @file sunLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +//class 2, shadows, no SSAO + +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform sampler2DRectShadow shadowMap0; +uniform sampler2DRectShadow shadowMap1; +uniform sampler2DRectShadow shadowMap2; +uniform sampler2DRectShadow shadowMap3; +uniform sampler2DShadow shadowMap4; +uniform sampler2DShadow shadowMap5; +uniform sampler2D noiseMap; + +uniform sampler2D lightFunc; + + +// Inputs +uniform mat4 shadow_matrix[6]; +uniform vec4 shadow_clip; +uniform float ssao_radius; +uniform float ssao_max_radius; +uniform float ssao_factor; +uniform float ssao_factor_inv; + +varying vec2 vary_fragcoord; +varying vec4 vary_light; + +uniform mat4 inv_proj; +uniform vec2 screen_res; +uniform vec2 shadow_res; +uniform vec2 proj_shadow_res; + +uniform float shadow_bias; +uniform float shadow_offset; + +uniform float spot_shadow_bias; +uniform float spot_shadow_offset; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl) +{ + stc.xyz /= stc.w; + stc.z += shadow_bias*scl; + + float cs = shadow2DRect(shadowMap, stc.xyz).x; + float shadow = cs; + + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, 1.5, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, -1.5, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, 1.5, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, -1.5, 0.0)).x, cs); + + return shadow/5.0; + + //return shadow; +} + +float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl) +{ + stc.xyz /= stc.w; + stc.z += spot_shadow_bias*scl; + + float cs = shadow2D(shadowMap, stc.xyz).x; + float shadow = cs; + + vec2 off = 1.5/proj_shadow_res; + + shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, off.y, 0.0)).x, cs); + shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x, cs); + shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x, cs); + shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x, cs); + + return shadow/5.0; + + //return shadow; +} + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + + //try doing an unproject here + + vec4 pos = getPosition(pos_screen); + + vec4 nmap4 = texture2DRect(normalMap, pos_screen); + nmap4 = vec4((nmap4.xy-0.5)*2.0,nmap4.z,nmap4.w); // unpack norm + float displace = nmap4.w; + vec3 norm = nmap4.xyz; + + /*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL + { + gl_FragColor = vec4(0.0); // doesn't matter + return; + }*/ + + float shadow = 1.0; + float dp_directional_light = max(0.0, dot(norm, vary_light.xyz)); + + vec3 shadow_pos = pos.xyz + displace*norm; + vec3 offset = vary_light.xyz * (1.0-dp_directional_light); + + vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0); + + if (spos.z > -shadow_clip.w) + { + if (dp_directional_light == 0.0) + { + // if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup + shadow = 0.0; + } + else + { + vec4 lpos; + + if (spos.z < -shadow_clip.z) + { + lpos = shadow_matrix[3]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap3, lpos, 0.25); + shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); + } + else if (spos.z < -shadow_clip.y) + { + lpos = shadow_matrix[2]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap2, lpos, 0.5); + } + else if (spos.z < -shadow_clip.x) + { + lpos = shadow_matrix[1]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap1, lpos, 0.75); + } + else + { + lpos = shadow_matrix[0]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap0, lpos, 1.0); + } + + // take the most-shadowed value out of these two: + // * the blurred sun shadow in the light (shadow) map + // * an unblurred dot product between the sun and this norm + // the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting + shadow = min(shadow, dp_directional_light); + + //lpos.xy /= lpos.w*32.0; + //if (fract(lpos.x) < 0.1 || fract(lpos.y) < 0.1) + //{ + // shadow = 0.0; + //} + + } + } + else + { + // more distant than the shadow map covers + shadow = 1.0; + } + + gl_FragColor[0] = shadow; + gl_FragColor[1] = 1.0; + + spos = vec4(shadow_pos+norm*spot_shadow_offset, 1.0); + + //spotlight shadow 1 + vec4 lpos = shadow_matrix[4]*spos; + gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.8); + + //spotlight shadow 2 + lpos = shadow_matrix[5]*spos; + gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.8); + + //gl_FragColor.rgb = pos.xyz; + //gl_FragColor.b = shadow; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl new file mode 100644 index 000000000..4e33a1af4 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl @@ -0,0 +1,257 @@ +/** + * @file sunLightSSAOF.glsl + * + * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#extension GL_ARB_texture_rectangle : enable + +//class 2 -- shadows and SSAO + +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform sampler2DRectShadow shadowMap0; +uniform sampler2DRectShadow shadowMap1; +uniform sampler2DRectShadow shadowMap2; +uniform sampler2DRectShadow shadowMap3; +uniform sampler2DShadow shadowMap4; +uniform sampler2DShadow shadowMap5; +uniform sampler2D noiseMap; + +uniform sampler2D lightFunc; + +// Inputs +uniform mat4 shadow_matrix[6]; +uniform vec4 shadow_clip; +uniform float ssao_radius; +uniform float ssao_max_radius; +uniform float ssao_factor; +uniform float ssao_factor_inv; + +varying vec2 vary_fragcoord; +varying vec4 vary_light; + +uniform mat4 inv_proj; +uniform vec2 screen_res; +uniform vec2 shadow_res; +uniform vec2 proj_shadow_res; + +uniform float shadow_bias; +uniform float shadow_offset; + +uniform float spot_shadow_bias; +uniform float spot_shadow_offset; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +//calculate decreases in ambient lighting when crowded out (SSAO) +float calcAmbientOcclusion(vec4 pos, vec3 norm) +{ + float ret = 1.0; + + float dist = dot(pos.xyz,pos.xyz); + + if (dist < 64.0*64.0) + { + vec2 kern[8]; + // exponentially (^2) distant occlusion samples spread around origin + kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; + kern[1] = vec2(1.0, 0.0) * 0.250*0.250; + kern[2] = vec2(0.0, 1.0) * 0.375*0.375; + kern[3] = vec2(0.0, -1.0) * 0.500*0.500; + kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; + kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; + kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; + kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; + + vec2 pos_screen = vary_fragcoord.xy; + vec3 pos_world = pos.xyz; + vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; + + float angle_hidden = 0.0; + int points = 0; + + float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); + + // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) + for (int i = 0; i < 8; i++) + { + vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); + vec3 samppos_world = getPosition(samppos_screen).xyz; + + vec3 diff = pos_world - samppos_world; + float dist2 = dot(diff, diff); + + // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area + // --> solid angle shrinking by the square of distance + //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2 + //(k should vary inversely with # of samples, but this is taken care of later) + + //if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) // -0.05*norm to shift sample point back slightly for flat surfaces + // angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional. max of 1.0 (= ssao_factor_inv * ssao_factor) + angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv); + + // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" + points = points + int(diff.z > -1.0); + } + + angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0); + + ret = (1.0 - (float(points != 0) * angle_hidden)); + ret += max((dist-32.0*32.0)/(32.0*32.0), 0.0); + } + + return min(ret, 1.0); +} + +float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl) +{ + stc.xyz /= stc.w; + stc.z += shadow_bias*scl; + + float cs = shadow2DRect(shadowMap, stc.xyz).x; + float shadow = cs; + + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, 1.5, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, -1.5, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, 1.5, 0.0)).x, cs); + shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, -1.5, 0.0)).x, cs); + + return shadow/5.0; + + //return shadow; +} + +float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl) +{ + stc.xyz /= stc.w; + stc.z += spot_shadow_bias*scl; + + float cs = shadow2D(shadowMap, stc.xyz).x; + float shadow = cs; + + vec2 off = 1.5/proj_shadow_res; + + shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, off.y, 0.0)).x, cs); + shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x, cs); + shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x, cs); + shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x, cs); + + + return shadow/5.0; + + //return shadow; +} + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + + //try doing an unproject here + + vec4 pos = getPosition(pos_screen); + + vec4 nmap4 = texture2DRect(normalMap, pos_screen); + nmap4 = vec4((nmap4.xy-0.5)*2.0,nmap4.z,nmap4.w); // unpack norm + float displace = nmap4.w; + vec3 norm = nmap4.xyz; + + /*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL + { + gl_FragColor = vec4(0.0); // doesn't matter + return; + }*/ + + float shadow = 1.0; + float dp_directional_light = max(0.0, dot(norm, vary_light.xyz)); + + vec3 shadow_pos = pos.xyz + displace*norm; + vec3 offset = vary_light.xyz * (1.0-dp_directional_light); + + vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0); + + if (spos.z > -shadow_clip.w) + { + if (dp_directional_light == 0.0) + { + // if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup + shadow = 0.0; + } + else + { + vec4 lpos; + + if (spos.z < -shadow_clip.z) + { + lpos = shadow_matrix[3]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap3, lpos, 0.25); + shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); + } + else if (spos.z < -shadow_clip.y) + { + lpos = shadow_matrix[2]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap2, lpos, 0.5); + } + else if (spos.z < -shadow_clip.x) + { + lpos = shadow_matrix[1]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap1, lpos, 0.75); + } + else + { + lpos = shadow_matrix[0]*spos; + lpos.xy *= shadow_res; + shadow = pcfShadow(shadowMap0, lpos, 1.0); + } + + // take the most-shadowed value out of these two: + // * the blurred sun shadow in the light (shadow) map + // * an unblurred dot product between the sun and this norm + // the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting + shadow = min(shadow, dp_directional_light); + + //lpos.xy /= lpos.w*32.0; + //if (fract(lpos.x) < 0.1 || fract(lpos.y) < 0.1) + //{ + // shadow = 0.0; + //} + + } + } + else + { + // more distant than the shadow map covers + shadow = 1.0; + } + + gl_FragColor[0] = shadow; + gl_FragColor[1] = calcAmbientOcclusion(pos, norm); + + spos.xyz = shadow_pos+offset*spot_shadow_offset; + + //spotlight shadow 1 + vec4 lpos = shadow_matrix[4]*spos; + gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.8); + + //spotlight shadow 2 + lpos = shadow_matrix[5]*spos; + gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.8); + + //gl_FragColor.rgb = pos.xyz; + //gl_FragColor.b = shadow; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl new file mode 100644 index 000000000..9d092d9ce --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl @@ -0,0 +1,25 @@ +/** + * @file sunLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec4 vary_light; +varying vec2 vary_fragcoord; + +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res; + vec4 tex = gl_MultiTexCoord0; + tex.w = 1.0; + + vary_light = gl_MultiTexCoord0; + + gl_FrontColor = gl_Color; +} diff --git a/indra/newview/app_settings/shaders/class2/effects/blurF.glsl b/indra/newview/app_settings/shaders/class2/effects/blurF.glsl index 7edfebab2..43f37a80a 100644 --- a/indra/newview/app_settings/shaders/class2/effects/blurF.glsl +++ b/indra/newview/app_settings/shaders/class2/effects/blurF.glsl @@ -5,6 +5,7 @@ * $License$ */ +#version 120 #extension GL_ARB_texture_rectangle : enable uniform sampler2DRect RenderTexture; diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl index f4c59734a..19800d96d 100644 --- a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl +++ b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl @@ -6,7 +6,7 @@ */ float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLight(vec3 v, vec3 n, vec4 lp, float la); +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); @@ -18,9 +18,10 @@ vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight) // Collect normal lights (need to be divided by two, as we later multiply by 2) col.rgb += gl_LightSource[1].diffuse.rgb * calcDirectionalLight(norm, gl_LightSource[1].position.xyz); - col.rgb += gl_LightSource[2].diffuse.rgb * calcPointLight(pos, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation); - col.rgb += gl_LightSource[3].diffuse.rgb * calcPointLight(pos, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation); - //col.rgb += gl_LightSource[4].diffuse.rgb * calcPointLight(pos, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation); + + col.rgb += gl_LightSource[2].diffuse.rgb * calcPointLightOrSpotLight(pos, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a); + col.rgb += gl_LightSource[3].diffuse.rgb * calcPointLightOrSpotLight(pos, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a); + //col.rgb += gl_LightSource[4].diffuse.rgb * calcPointLightOrSpotLight(pos, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a); col.rgb = scaleDownLight(col.rgb); // Add windlight lights diff --git a/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl new file mode 100644 index 000000000..d26b244fa --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl @@ -0,0 +1,86 @@ +/** + * @file giDownsampleF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +uniform sampler2DRect giLightMap; + +uniform vec2 kern[32]; +uniform float dist_factor; +uniform float blur_size; +uniform vec2 delta; +uniform int kern_length; +uniform float kern_scale; +uniform vec3 blur_quad; + +varying vec2 vary_fragcoord; + +uniform mat4 inv_proj; +uniform vec2 screen_res; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +float getDepth(vec2 pos_screen) +{ + float z = texture2DRect(depthMap, pos_screen.xy).a; + z = z*2.0-1.0; + vec4 ndc = vec4(0.0, 0.0, z, 1.0); + vec4 p = inv_proj*ndc; + return p.z/p.w; +} + +void main() +{ + vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + float depth = getDepth(vary_fragcoord.xy); + + vec3 ccol = texture2DRect(giLightMap, vary_fragcoord.xy).rgb; + vec2 dlt = kern_scale * delta/(vec2(1.0,1.0)+norm.xy*norm.xy); + dlt /= clamp(-depth*blur_quad.x, 1.0, 3.0); + float defined_weight = kern[0].x; + vec3 col = ccol*kern[0].x; + + for (int i = 0; i < kern_length; i++) + { + vec2 tc = vary_fragcoord.xy + kern[i].y*dlt; + vec3 sampNorm = texture2DRect(normalMap, tc.xy).xyz; + sampNorm = vec3((sampNorm.xy-0.5)*2.0,sampNorm.z); // unpack norm + + float d = dot(norm.xyz, sampNorm); + + if (d > 0.5) + { + float sampdepth = getDepth(tc.xy); + sampdepth -= depth; + if (sampdepth*sampdepth < blur_quad.z) + { + col += texture2DRect(giLightMap, tc).rgb*kern[i].x; + defined_weight += kern[i].x; + } + } + } + + col /= defined_weight; + + //col = ccol; + + col = col*blur_quad.y; + + gl_FragData[0].xyz = col; + + //gl_FragColor = ccol; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl new file mode 100644 index 000000000..e5f621764 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl @@ -0,0 +1,17 @@ +/** + * @file postgiV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/giF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giF.glsl new file mode 100644 index 000000000..735150a78 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/giF.glsl @@ -0,0 +1,191 @@ +/** + * @file giF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform sampler2DRect lightMap; +uniform sampler2DRect specularRect; + +uniform sampler2D noiseMap; + +uniform sampler2D diffuseGIMap; +uniform sampler2D specularGIMap; +uniform sampler2D normalGIMap; +uniform sampler2D depthGIMap; + +uniform sampler2D lightFunc; + +// Inputs +varying vec2 vary_fragcoord; + +uniform vec2 screen_res; + +uniform vec4 sunlight_color; + +uniform mat4 inv_proj; +uniform mat4 gi_mat; //gPipeline.mGIMatrix - eye space to sun space +uniform mat4 gi_mat_proj; //gPipeline.mGIMatrixProj - eye space to projected sun space +uniform mat4 gi_norm_mat; //gPipeline.mGINormalMatrix - eye space normal to sun space normal matrix +uniform mat4 gi_inv_proj; //gPipeline.mGIInvProj - projected sun space to sun space +uniform float gi_sample_width; +uniform float gi_noise; +uniform float gi_attenuation; +uniform float gi_range; + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMap, pos_screen.xy).a; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec4 getGIPosition(vec2 gi_tc) +{ + float depth = texture2D(depthGIMap, gi_tc).a; + vec2 sc = gi_tc*2.0; + sc -= vec2(1.0, 1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = gi_inv_proj*ndc; + pos.xyz /= pos.w; + pos.w = 1.0; + return pos; +} + +vec3 giAmbient(vec3 pos, vec3 norm) +{ + vec4 gi_c = gi_mat_proj * vec4(pos, 1.0); + gi_c.xyz /= gi_c.w; + + vec4 gi_pos = gi_mat*vec4(pos,1.0); + vec3 gi_norm = (gi_norm_mat*vec4(norm,1.0)).xyz; + gi_norm = normalize(gi_norm); + + vec4 c_spec = texture2DRect(specularRect, vary_fragcoord.xy); + vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).rgb; + gi_pos.xyz += nz.x*gi_noise*gi_norm.xyz; + vec2 tcx = gi_norm.xy; + vec2 tcy = gi_norm.yx; + + vec4 eye_pos = gi_mat*vec4(0,0,0,1.0); + + vec3 eye_dir = normalize(gi_pos.xyz-eye_pos.xyz); + vec3 eye_ref = reflect(eye_dir, gi_norm); + + float da = 0.0; //texture2DRect(lightMap, vary_fragcoord.xy).r*0.5; + vec3 fdiff = vec3(da); + float fda = da; + + vec3 rcol = vec3(0,0,0); + + float fsa = 0.0; + + + for (int i = -1; i <= 1; i += 2 ) + { + for (int j = -1; j <= 1; j+= 2) + { + vec2 tc = vec2(i, j)*0.75+gi_norm.xy*nz.z; + tc += nz.xy*2.0; + tc *= gi_sample_width*0.25; + tc += gi_c.xy; + + vec3 lnorm = -(texture2D(normalGIMap, tc.xy).xyz*2.0-1.0); + vec3 lpos = getGIPosition(tc.xy).xyz; + + vec3 at = lpos-gi_pos.xyz; + float dist = length(at); + float dist_atten = clamp(1.0/(gi_attenuation*dist), 0.0, 1.0); + + + if (dist_atten > 0.01) + { //possible contribution of indirect light to this surface + vec3 ldir = at; + + float ld = -dot(ldir, lnorm); + + if (ld < 0.0) + { + float ang_atten = dot(ldir, gi_norm); + + if (ang_atten > 0.0) + { + vec4 spec = texture2D(specularGIMap, tc.xy); + at = normalize(at); + vec3 diff; + + float da = 0.0; + + //contribution from indirect source to visible pixel + vec3 ha = at; + ha.z -= 1.0; + ha = normalize(ha); + if (spec.a > 0.0) + { + float sa = dot(ha,lnorm); + da = texture2D(lightFunc, vec2(sa, spec.a)).a; + } + else + { + da = -lnorm.z; + } + + diff = texture2D(diffuseGIMap, tc.xy).rgb+spec.rgb*spec.a*2.0; + + if (da > 0.0) + { //contribution from visible pixel to eye + vec3 ha = normalize(at-eye_dir); + if (c_spec.a > 0.0) + { + float sa = dot(ha, gi_norm); + da = dist_atten*texture2D(lightFunc, vec2(sa, c_spec.a)).a; + } + else + { + da = dist_atten*dot(gi_norm, normalize(ldir)); + } + fda += da; + fdiff += da*(c_spec.rgb*c_spec.a*2.0+vec3(1,1,1))*diff.rgb; + } + } + } + } + } + } + + fdiff *= sunlight_color.rgb; + + vec3 ret = fda*fdiff; + + return clamp(ret,vec3(0.0), vec3(1.0)); +} + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + vec4 pos = getPosition(pos_screen); + + float rad = gi_range*0.5; + + vec3 norm = texture2DRect(normalMap, pos_screen).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + float dist = max(length(pos.xyz)-rad, 0.0); + + float da = clamp(1.0-dist/rad, 0.0, 1.0); + + vec3 ambient = da > 0.0 ? giAmbient(pos.xyz, norm) : vec3(0); + + + gl_FragData[0].xyz = mix(vec3(0), ambient, da); +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl new file mode 100644 index 000000000..e0f4a3e4f --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl @@ -0,0 +1,25 @@ +/** + * @file giFinalF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect diffuseRect; +uniform sampler2D bloomMap; +uniform sampler2DRect edgeMap; + +uniform vec2 screen_res; +varying vec2 vary_fragcoord; + + +void main() +{ + vec4 bloom = texture2D(bloomMap, vary_fragcoord.xy/screen_res); + vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy); + + gl_FragColor = bloom + diff; + //gl_FragColor.rgb = vec3(texture2DRect(edgeMap, vary_fragcoord.xy).a); +} \ No newline at end of file diff --git a/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl b/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl new file mode 100644 index 000000000..fbf2c1737 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl @@ -0,0 +1,17 @@ +/** + * @file giFinalV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/giV.glsl b/indra/newview/app_settings/shaders/class3/deferred/giV.glsl new file mode 100644 index 000000000..543527612 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/giV.glsl @@ -0,0 +1,22 @@ +/** + * @file giV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; + +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res; + vec4 tex = gl_MultiTexCoord0; + tex.w = 1.0; + + gl_FrontColor = gl_Color; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl new file mode 100644 index 000000000..d9483bc6e --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl @@ -0,0 +1,19 @@ +/** + * @file luminanceF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect lightMap; +uniform sampler2DRect diffuseRect; + +varying vec2 vary_fragcoord; +void main() +{ + float i = texture2DRect(lightMap, vary_fragcoord.xy).r; + gl_FragColor.rgb = vec3(i); + gl_FragColor.a = 1.0; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl b/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl new file mode 100644 index 000000000..6368def83 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl @@ -0,0 +1,20 @@ +/** + * @file giV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; + +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res; + + gl_FrontColor = gl_Color; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl new file mode 100644 index 000000000..51ab579e3 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl @@ -0,0 +1,80 @@ +/** + * @file postDeferredF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; + +uniform sampler2DRect localLightMap; +uniform sampler2DRect sunLightMap; +uniform sampler2DRect giLightMap; +uniform sampler2DRect edgeMap; + +uniform sampler2D luminanceMap; + +uniform sampler2DRect lightMap; + +uniform sampler2D lightFunc; +uniform sampler2D noiseMap; + +uniform float sun_lum_scale; +uniform float sun_lum_offset; +uniform float lum_scale; +uniform float lum_lod; +uniform vec4 ambient; +uniform float gi_brightness; +uniform float gi_luminance; + +uniform vec4 sunlight_color; + +uniform vec2 screen_res; +varying vec2 vary_fragcoord; + +void main() +{ + vec2 tc = vary_fragcoord.xy; + vec4 lcol = texture2DLod(luminanceMap, vec2(0.5, 0.5), lum_lod); + + vec3 gi_col = texture2DRect(giLightMap, vary_fragcoord.xy).rgb; + vec4 sun_col = texture2DRect(sunLightMap, vary_fragcoord.xy); + vec3 local_col = texture2DRect(localLightMap, vary_fragcoord.xy).rgb; + + float scol = texture2DRect(lightMap, vary_fragcoord.xy).r; + + vec3 diff = texture2DRect(diffuseRect, vary_fragcoord.xy).rgb; + vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); + + gi_col = gi_col*(diff.rgb+spec.rgb*spec.a); + + float lum = 1.0-clamp(pow(lcol.r, gi_brightness)+sun_lum_offset, 0.0, 1.0); + + lum *= sun_lum_scale; + + sun_col *= 1.0+(lum*lum_scale*scol); + + vec4 col; + col.rgb = gi_col+sun_col.rgb+local_col; + + col.a = sun_col.a; + + vec3 bcol = vec3(0,0,0); + float tweight = 0.0; + for (int i = 0; i < 16; i++) + { + float weight = (float(i)+1.0)/2.0; + bcol += texture2DLod(luminanceMap, vary_fragcoord.xy/screen_res, weight).rgb*weight*weight*weight; + tweight += weight*weight; + } + + bcol /= tweight; + bcol *= gi_luminance; + col.rgb += bcol*lum; + + gl_FragColor = col; + //gl_FragColor.rgb = texture2DRect(giLightMap, vary_fragcoord.xy).rgb; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl new file mode 100644 index 000000000..0ec81dcb0 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl @@ -0,0 +1,17 @@ +/** + * @file postDeferredV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl b/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl new file mode 100644 index 000000000..24fa07f25 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl @@ -0,0 +1,69 @@ +/** + * @file postgiF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect depthMap; +uniform sampler2DRect normalMap; +uniform sampler2DRect giLightMap; +uniform sampler2D noiseMap; +uniform sampler2D giMip; +uniform sampler2DRect edgeMap; + + +uniform vec2 delta; +uniform float kern_scale; +uniform float gi_edge_weight; +uniform float gi_blur_brightness; + +varying vec2 vary_fragcoord; + +void main() +{ + vec2 dlt = kern_scale*delta; + float defined_weight = 0.0; + vec3 col = vec3(0.0); + + float e = 1.0; + + for (int i = 1; i < 8; i++) + { + vec2 tc = vary_fragcoord.xy + float(i) * dlt; + + e = max(e, 0.0); + float wght = e; + + col += texture2DRect(giLightMap, tc).rgb*wght; + defined_weight += wght; + + e *= e; + e -=(texture2DRect(edgeMap, tc.xy-dlt*0.25).a+ + texture2DRect(edgeMap, tc.xy+dlt*0.25).a)*gi_edge_weight; + } + + e = 1.0; + + for (int i = 1; i < 8; i++) + { + vec2 tc = vary_fragcoord.xy - float(i) * dlt; + + e = max(e,0.0); + float wght = e; + + col += texture2DRect(giLightMap, tc).rgb*wght; + defined_weight += wght; + + e *= e; + e -= (texture2DRect(edgeMap, tc.xy-dlt*0.25).a+ + texture2DRect(edgeMap, tc.xy+dlt*0.25).a)*gi_edge_weight; + + } + + col /= max(defined_weight, 0.01); + + gl_FragColor.rgb = col * gi_blur_brightness; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl b/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl new file mode 100644 index 000000000..e5f621764 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl @@ -0,0 +1,17 @@ +/** + * @file postgiV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +varying vec2 vary_fragcoord; +uniform vec2 screen_res; + +void main() +{ + //transform vertex + gl_Position = ftransform(); + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl new file mode 100644 index 000000000..a2db24733 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -0,0 +1,356 @@ +/** + * @file softenLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +#extension GL_ARB_texture_rectangle : enable + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect normalMap; +uniform sampler2DRect lightMap; +uniform sampler2D noiseMap; +uniform samplerCube environmentMap; +uniform sampler2D lightFunc; +uniform vec3 gi_quad; + +uniform float blur_size; +uniform float blur_fidelity; + +// Inputs +uniform vec4 morphFactor; +uniform vec3 camPosLocal; +//uniform vec4 camPosWorld; +uniform vec4 gamma; +uniform vec4 lightnorm; +uniform vec4 sunlight_color; +uniform vec4 ambient; +uniform vec4 blue_horizon; +uniform vec4 blue_density; +uniform vec4 haze_horizon; +uniform vec4 haze_density; +uniform vec4 cloud_shadow; +uniform vec4 density_multiplier; +uniform vec4 distance_multiplier; +uniform vec4 max_y; +uniform vec4 glow; +uniform float scene_light_strength; +uniform vec3 env_mat[3]; +uniform vec4 shadow_clip; +uniform mat3 ssao_effect_mat; + +uniform sampler2DRect depthMap; +uniform mat4 inv_proj; +uniform vec2 screen_res; + +varying vec4 vary_light; +varying vec2 vary_fragcoord; + +vec3 vary_PositionEye; + +vec3 vary_SunlitColor; +vec3 vary_AmblitColor; +vec3 vary_AdditiveColor; +vec3 vary_AtmosAttenuation; +uniform float gi_ambiance; + +vec4 getPosition_d(vec2 pos_screen, float depth) +{ + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec4 getPosition(vec2 pos_screen) +{ //get position in screen space (world units) given window coordinate and depth map + float depth = texture2DRect(depthMap, pos_screen.xy).a; + return getPosition_d(pos_screen, depth); +} + +vec3 getPositionEye() +{ + return vary_PositionEye; +} +vec3 getSunlitColor() +{ + return vary_SunlitColor; +} +vec3 getAmblitColor() +{ + return vary_AmblitColor; +} +vec3 getAdditiveColor() +{ + return vary_AdditiveColor; +} +vec3 getAtmosAttenuation() +{ + return vary_AtmosAttenuation; +} + + +void setPositionEye(vec3 v) +{ + vary_PositionEye = v; +} + +void setSunlitColor(vec3 v) +{ + vary_SunlitColor = v; +} + +void setAmblitColor(vec3 v) +{ + vary_AmblitColor = v; +} + +void setAdditiveColor(vec3 v) +{ + vary_AdditiveColor = v; +} + +void setAtmosAttenuation(vec3 v) +{ + vary_AtmosAttenuation = v; +} + +void calcAtmospherics(vec3 inPositionEye, float ambFactor) { + + vec3 P = inPositionEye; + setPositionEye(P); + + //(TERRAIN) limit altitude + if (P.y > max_y.x) P *= (max_y.x / P.y); + if (P.y < -max_y.x) P *= (-max_y.x / P.y); + + vec3 tmpLightnorm = lightnorm.xyz; + + vec3 Pn = normalize(P); + float Plen = length(P); + + vec4 temp1 = vec4(0); + vec3 temp2 = vec3(0); + vec4 blue_weight; + vec4 haze_weight; + vec4 sunlight = sunlight_color; + vec4 light_atten; + + //sunlight attenuation effect (hue and brightness) due to atmosphere + //this is used later for sunlight modulation at various altitudes + light_atten = (blue_density * 1.0 + vec4(haze_density.r) * 0.25) * (density_multiplier.x * max_y.x); + //I had thought blue_density and haze_density should have equal weighting, + //but attenuation due to haze_density tends to seem too strong + + temp1 = blue_density + vec4(haze_density.r); + blue_weight = blue_density / temp1; + haze_weight = vec4(haze_density.r) / temp1; + + //(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain) + temp2.y = max(0.0, tmpLightnorm.y); + temp2.y = 1. / temp2.y; + sunlight *= exp( - light_atten * temp2.y); + + // main atmospheric scattering line integral + temp2.z = Plen * density_multiplier.x; + + // Transparency (-> temp1) + // ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier.x in a variable because the ati + // compiler gets confused. + temp1 = exp(-temp1 * temp2.z * distance_multiplier.x); + + //final atmosphere attenuation factor + setAtmosAttenuation(temp1.rgb); + + //compute haze glow + //(can use temp2.x as temp because we haven't used it yet) + temp2.x = dot(Pn, tmpLightnorm.xyz); + temp2.x = 1. - temp2.x; + //temp2.x is 0 at the sun and increases away from sun + temp2.x = max(temp2.x, .03); //was glow.y + //set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) + temp2.x *= glow.x; + //higher glow.x gives dimmer glow (because next step is 1 / "angle") + temp2.x = pow(temp2.x, glow.z); + //glow.z should be negative, so we're doing a sort of (1 / "angle") function + + //add "minimum anti-solar illumination" + temp2.x += .25; + + //increase ambient when there are more clouds + vec4 tmpAmbient = ambient*gi_ambiance + (vec4(1.) - ambient*gi_ambiance) * cloud_shadow.x * 0.5; + + /* decrease value and saturation (that in HSV, not HSL) for occluded areas + * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html + * // The following line of code performs the equivalent of: + * float ambAlpha = tmpAmbient.a; + * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis + * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue); + * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha); + */ + tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); + + //haze color + setAdditiveColor( + vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow.x) + tmpAmbient) + + (haze_horizon.r * haze_weight) * (sunlight*(1.-cloud_shadow.x) * temp2.x + + tmpAmbient))); + + //brightness of surface both sunlight and ambient + setSunlitColor(vec3(sunlight * .5)); + setAmblitColor(vec3(tmpAmbient * .25)); + setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1)); +} + +vec3 atmosLighting(vec3 light) +{ + light *= getAtmosAttenuation().r; + light += getAdditiveColor(); + return (2.0 * light); +} + +vec3 atmosTransport(vec3 light) { + light *= getAtmosAttenuation().r; + light += getAdditiveColor() * 2.0; + return light; +} +vec3 atmosGetDiffuseSunlightColor() +{ + return getSunlitColor(); +} + +vec3 scaleDownLight(vec3 light) +{ + return (light / scene_light_strength ); +} + +vec3 scaleUpLight(vec3 light) +{ + return (light * scene_light_strength); +} + +vec3 atmosAmbient(vec3 light) +{ + return getAmblitColor() + light / 2.0; +} + +vec3 atmosAffectDirectionalLight(float lightIntensity) +{ + return getSunlitColor() * lightIntensity; +} + +vec3 scaleSoftClip(vec3 light) +{ + //soft clip effect: + light = 1. - clamp(light, vec3(0.), vec3(1.)); + light = 1. - pow(light, gamma.xxx); + + return light; +} + +void main() +{ + vec2 tc = vary_fragcoord.xy; + float depth = texture2DRect(depthMap, tc.xy).a; + vec3 pos = getPosition_d(tc, depth).xyz; + vec3 norm = texture2DRect(normalMap, tc).xyz; + norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + //vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz; + + float da = max(dot(norm.xyz, vary_light.xyz), 0.0); + + vec4 diffuse = texture2DRect(diffuseRect, tc); + vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); + + da = texture2D(lightFunc, vec2(da, 0.0)).a; + + vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg; + float scol = max(scol_ambocc.r, diffuse.a); + float ambocc = scol_ambocc.g; + + calcAtmospherics(pos.xyz, ambocc); + + vec3 col = atmosAmbient(vec3(0)); + col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a)); + + col *= diffuse.rgb; + + if (spec.a > 0.0) // specular reflection + { + // the old infinite-sky shiny reflection + // + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + float sa = dot(refnormpersp, vary_light.xyz); + vec3 dumbshiny = vary_SunlitColor*scol*texture2D(lightFunc, vec2(sa, spec.a)).a; + + /* + // screen-space cheap fakey reflection map + // + vec3 refnorm = normalize(reflect(vec3(0,0,-1), norm.xyz)); + depth -= 0.5; // unbias depth + // first figure out where we'll make our 2D guess from + vec2 ref2d = (0.25 * screen_res.y) * (refnorm.xy) * abs(refnorm.z) / depth; + // Offset the guess source a little according to a trivial + // checkerboard dither function and spec.a. + // This is meant to be similar to sampling a blurred version + // of the diffuse map. LOD would be better in that regard. + // The goal of the blur is to soften reflections in surfaces + // with low shinyness, and also to disguise our lameness. + float checkerboard = floor(mod(tc.x+tc.y, 2.0)); // 0.0, 1.0 + float checkoffset = (3.0 + (7.0*(1.0-spec.a)))*(checkerboard-0.5); + + ref2d += vec2(checkoffset, checkoffset); + ref2d += tc.xy; // use as offset from destination + // Get attributes from the 2D guess point. + // We average two samples of diffuse (not of anything else) per + // pixel to try to reduce aliasing some more. + vec3 refcol = 0.5 * (texture2DRect(diffuseRect, ref2d + vec2(0.0, -checkoffset)).rgb + + texture2DRect(diffuseRect, ref2d + vec2(-checkoffset, 0.0)).rgb); + float refdepth = texture2DRect(depthMap, ref2d).a; + vec3 refpos = getPosition_d(ref2d, refdepth).xyz; + float refshad = texture2DRect(lightMap, ref2d).r; + vec3 refn = texture2DRect(normalMap, ref2d).rgb; + refn = vec3((refn.xy-0.5)*2.0,refn.z); // unpack norm + refn = normalize(refn); + // figure out how appropriate our guess actually was + float refapprop = max(0.0, dot(-refnorm, normalize(pos - refpos))); + // darken reflections from points which face away from the reflected ray - our guess was a back-face + //refapprop *= step(dot(refnorm, refn), 0.0); + refapprop = min(refapprop, max(0.0, -dot(refnorm, refn))); // more conservative variant + // get appropriate light strength for guess-point. + // reflect light direction to increase the illusion that + // these are reflections. + vec3 reflight = reflect(lightnorm.xyz, norm.xyz); + float reflit = min(max(dot(refn, reflight.xyz), 0.0), refshad); + // apply sun color to guess-point, dampen according to inappropriateness of guess + float refmod = min(refapprop, reflit); + vec3 refprod = vary_SunlitColor * refcol.rgb * refmod; + vec3 ssshiny = (refprod * spec.a); + ssshiny *= 0.3; // dampen it even more + */ + vec3 ssshiny = vec3(0,0,0); + + // add the two types of shiny together + col += (ssshiny + dumbshiny) * spec.rgb; + } + + col = atmosLighting(col); + col = scaleSoftClip(col); + + gl_FragColor.rgb = col; + + //gl_FragColor.rgb = gi_col.rgb; + gl_FragColor.a = 0.0; + + //gl_FragColor.rg = scol_ambocc.rg; + //gl_FragColor.rgb = texture2DRect(lightMap, vary_fragcoord.xy).rgb; + //gl_FragColor.rgb = norm.rgb*0.5+0.5; + //gl_FragColor.rgb = vec3(ambocc); + //gl_FragColor.rgb = vec3(scol); +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl new file mode 100644 index 000000000..9d187b46e --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl @@ -0,0 +1,24 @@ +/** + * @file softenLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +uniform vec2 screen_res; + +varying vec4 vary_light; +varying vec2 vary_fragcoord; +void main() +{ + //transform vertex + gl_Position = ftransform(); + + vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex; + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; + + vec4 tex = gl_MultiTexCoord0; + tex.w = 1.0; + + vary_light = gl_MultiTexCoord0; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl new file mode 100644 index 000000000..1c1725a95 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl @@ -0,0 +1,19 @@ +/** + * @file treeF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $/LicenseInfo$ + */ + +uniform sampler2D diffuseMap; + +varying vec3 vary_normal; + +void main() +{ + vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy); + gl_FragData[0] = vec4(gl_Color.rgb*col.rgb, col.a <= 0.5 ? 0.0 : 0.005); + gl_FragData[1] = vec4(0,0,0,0); + vec3 nvn = normalize(vary_normal); + gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0); +} diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl index 1c5234c45..f129a1517 100644 --- a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl +++ b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl @@ -6,7 +6,7 @@ */ float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLight(vec3 v, vec3 n, vec4 lp, float la); +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); @@ -15,24 +15,21 @@ vec3 scaleUpLight(vec3 light); vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight) { - vec4 col; - col.a = color.a; + vec4 col = vec4(0.0, 0.0, 0.0, color.a); - // Add windlight lights - col.rgb = atmosAffectDirectionalLight(calcDirectionalLight(norm, gl_LightSource[0].position.xyz)); - col.rgb += atmosAmbient(baseLight.rgb); - col.rgb = scaleUpLight(col.rgb); - // Collect normal lights (need to be divided by two, as we later multiply by 2) - col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation); - col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation); - col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation); - col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation); - col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation); - col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation); + col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a); + col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a); + col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a); + col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a); + col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a); + col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a); col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz); col.rgb = scaleDownLight(col.rgb); - + + // Add windlight lights + col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, gl_LightSource[0].position.xyz)); + col.rgb += atmosAmbient(baseLight.rgb); col.rgb = min(col.rgb*color.rgb, 1.0); diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 0d41ab85f..474538a17 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -296,13 +296,6 @@ void LLFacePool::drawLoop() } } -void LLFacePool::renderFaceSelected(LLFace *facep, - LLViewerTexture *image, - const LLColor4 &color, - const S32 index_offset, const S32 index_count) -{ -} - void LLFacePool::enqueue(LLFace* facep) { mDrawFace.push_back(facep); diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index f92756ae3..440a2a845 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -169,10 +169,10 @@ public: LLFacePool(const U32 type); virtual ~LLFacePool(); - virtual void renderForSelect() = 0; + virtual void renderForSelect() {}; //Override if neded. BOOL isDead() { return mReferences.empty(); } virtual void renderFaceSelected(LLFace *facep, LLViewerTexture *image, const LLColor4 &color, - const S32 index_offset = 0, const S32 index_count = 0); + const S32 index_offset = 0, const S32 index_count = 0) {}; //Override if neded. virtual LLViewerTexture *getTexture(); virtual void dirtyTextures(const std::set& textures); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 08c430e62..07379971e 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -280,6 +280,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) { BOOL initialized_lighting = FALSE; BOOL light_enabled = TRUE; + S32 diffuse_channel = 0; + //BOOL is_particle = FALSE; BOOL use_shaders = (LLPipeline::sUnderWaterRender && gPipeline.canUseVertexShaders()) || gPipeline.canUseWindLightShadersOnObjects(); @@ -360,11 +362,13 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) if (deferred_render && current_shader != NULL) { gPipeline.unbindDeferredShader(*current_shader); + diffuse_channel = 0; } current_shader = target_shader; if (deferred_render) { gPipeline.bindDeferredShader(*current_shader); + diffuse_channel = current_shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } else { @@ -373,10 +377,10 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) } else if (!use_shaders && current_shader != NULL) { - if (deferred_render) { gPipeline.unbindDeferredShader(*current_shader); + diffuse_channel = 0; } LLGLSLShader::bindNoShader(); current_shader = NULL; @@ -390,7 +394,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) if (params.mTexture.notNull()) { - gGL.getTexUnit(0)->bind(params.mTexture.get()); + gGL.getTexUnit(diffuse_channel)->bind(params.mTexture.get()); if(params.mTexture.notNull()) { params.mTexture->addTextureStats(params.mVSize); diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index a6e43e5b5..92d257734 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -94,6 +94,7 @@ BOOL gAvatarEmbossBumpMap = FALSE; static BOOL sRenderingSkinned = FALSE; S32 normal_channel = -1; S32 specular_channel = -1; +S32 diffuse_channel = -1; LLDrawPoolAvatar::LLDrawPoolAvatar() : LLFacePool(POOL_AVATAR) @@ -400,6 +401,7 @@ void LLDrawPoolAvatar::beginImpostor() } gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + diffuse_channel = 0; } void LLDrawPoolAvatar::endImpostor() @@ -452,6 +454,7 @@ void LLDrawPoolAvatar::beginDeferredImpostor() normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL); specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP); + diffuse_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); sVertexProgram->bind(); } @@ -461,6 +464,7 @@ void LLDrawPoolAvatar::endDeferredImpostor() sShaderLevel = mVertexShaderLevel; sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL); sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP); + sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); sVertexProgram->unbind(); gGL.getTexUnit(0)->activate(); } @@ -659,8 +663,10 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) gGL.translatef((F32)(pos.mV[VX]), (F32)(pos.mV[VY]), (F32)(pos.mV[VZ])); - gGL.scalef(0.15f, 0.15f, 0.3f); - gSphere.render(); + gGL.scalef(0.15f, 0.15f, 0.3f); + + gSphere.renderGGL(); + gGL.popMatrix(); gGL.setColorMask(true, false); } @@ -702,7 +708,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) avatarp->mImpostor.bindTexture(1, specular_channel); } } - avatarp->renderImpostor(); + avatarp->renderImpostor(LLColor4U(255,255,255,255), diffuse_channel); } else if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS) && !LLPipeline::sRenderDeferred) { diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index fc5f9dbff..d24726052 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -39,8 +39,6 @@ class LLVOAvatar; class LLDrawPoolAvatar : public LLFacePool { -protected: - S32 mNumFaces; public: enum { diff --git a/indra/newview/lldrawpoolclouds.cpp b/indra/newview/lldrawpoolclouds.cpp index 1d159998a..8844c3c71 100644 --- a/indra/newview/lldrawpoolclouds.cpp +++ b/indra/newview/lldrawpoolclouds.cpp @@ -101,6 +101,3 @@ void LLDrawPoolClouds::render(S32 pass) } -void LLDrawPoolClouds::renderForSelect() -{ -} diff --git a/indra/newview/lldrawpoolclouds.h b/indra/newview/lldrawpoolclouds.h index c70dd41f7..7c95b3ec0 100644 --- a/indra/newview/lldrawpoolclouds.h +++ b/indra/newview/lldrawpoolclouds.h @@ -55,7 +55,6 @@ public: /*virtual*/ void enqueue(LLFace *face); /*virtual*/ void beginRenderPass(S32 pass); /*virtual*/ void render(S32 pass = 0); - /*virtual*/ void renderForSelect(); }; #endif // LL_LLDRAWPOOLSKY_H diff --git a/indra/newview/lldrawpoolground.cpp b/indra/newview/lldrawpoolground.cpp index c65524b7c..9d63113d5 100644 --- a/indra/newview/lldrawpoolground.cpp +++ b/indra/newview/lldrawpoolground.cpp @@ -91,7 +91,3 @@ void LLDrawPoolGround::render(S32 pass) glPopMatrix(); } -void LLDrawPoolGround::renderForSelect() -{ -} - diff --git a/indra/newview/lldrawpoolground.h b/indra/newview/lldrawpoolground.h index 6c7d20bec..9ac96ca59 100644 --- a/indra/newview/lldrawpoolground.h +++ b/indra/newview/lldrawpoolground.h @@ -53,7 +53,6 @@ public: /*virtual*/ void prerender(); /*virtual*/ void render(S32 pass = 0); - /*virtual*/ void renderForSelect(); }; #endif // LL_LLDRAWPOOLGROUND_H diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp index 98c729dfe..ee691aa77 100644 --- a/indra/newview/lldrawpoolsky.cpp +++ b/indra/newview/lldrawpoolsky.cpp @@ -136,6 +136,7 @@ void LLDrawPoolSky::renderSkyCubeFace(U8 side) return; } + llassert(mSkyTex); mSkyTex[side].bindTexture(TRUE); face.renderIndexed(); @@ -149,10 +150,6 @@ void LLDrawPoolSky::renderSkyCubeFace(U8 side) } } -void LLDrawPoolSky::renderForSelect() -{ -} - void LLDrawPoolSky::endRenderPass( S32 pass ) { } diff --git a/indra/newview/lldrawpoolsky.h b/indra/newview/lldrawpoolsky.h index 8595d73ae..3da493cc9 100644 --- a/indra/newview/lldrawpoolsky.h +++ b/indra/newview/lldrawpoolsky.h @@ -64,7 +64,6 @@ public: /*virtual*/ void prerender(); /*virtual*/ void render(S32 pass = 0); - /*virtual*/ void renderForSelect(); /*virtual*/ void endRenderPass(S32 pass); void setSkyTex(LLSkyTex* const st) { mSkyTex = st; } diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index 957869004..03b2cf163 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -167,6 +167,10 @@ void LLDrawPoolTree::beginShadowPass(S32 pass) { LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE); gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); + static const LLCachedControl render_deferred_offset("RenderDeferredTreeShadowOffset",1.f); + static const LLCachedControl render_deferred_bias("RenderDeferredTreeShadowBias",1.f); + glPolygonOffset(render_deferred_offset,render_deferred_bias); + gDeferredShadowProgram.bind(); } @@ -179,7 +183,11 @@ void LLDrawPoolTree::endShadowPass(S32 pass) { LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - gDeferredShadowProgram.unbind(); + static const LLCachedControl render_deferred_offset("RenderDeferredTreeShadowOffset",1.f); + static const LLCachedControl render_deferred_bias("RenderDeferredTreeShadowBias",1.f); + glPolygonOffset(render_deferred_offset,render_deferred_bias); + + //gDeferredShadowProgram.unbind(); } @@ -323,15 +331,16 @@ void LLDrawPoolTree::renderTree(BOOL selecting) scale_mat *= rot_mat; + //TO-DO: Make these set-able? const F32 THRESH_ANGLE_FOR_BILLBOARD = 7.5f; //Made LoD now a little less aggressive here -Shyotl - /*const F32 BLEND_RANGE_FOR_BILLBOARD = 1.5f;*/ //Unused, really + const F32 BLEND_RANGE_FOR_BILLBOARD = 1.5f; F32 droop = treep->mDroop + 25.f*(1.f - treep->mTrunkBend.magVec()); S32 stop_depth = 0; F32 app_angle = treep->getAppAngle()*LLVOTree::sTreeFactor; F32 alpha = 1.0; - S32 trunk_LOD = 0; + S32 trunk_LOD = LLVOTree::sMAX_NUM_TREE_LOD_LEVELS; for (S32 j = 0; j < 4; j++) { @@ -342,8 +351,12 @@ void LLDrawPoolTree::renderTree(BOOL selecting) break; } } + if(trunk_LOD >= LLVOTree::sMAX_NUM_TREE_LOD_LEVELS) + { + continue ; //do not render. + } - if (app_angle < (THRESH_ANGLE_FOR_BILLBOARD/* - BLEND_RANGE_FOR_BILLBOARD*/)) + if (app_angle < (THRESH_ANGLE_FOR_BILLBOARD - BLEND_RANGE_FOR_BILLBOARD)) { // // Draw only the billboard diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 3e260f8b1..69e811905 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -55,7 +55,8 @@ #include "llviewershadermgr.h" #include "llwaterparammanager.h" -const LLUUID WATER_TEST("2bfd3884-7e27-69b9-ba3a-3e673f680004"); +const LLUUID TRANSPARENT_WATER_TEXTURE("2bfd3884-7e27-69b9-ba3a-3e673f680004"); +const LLUUID OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf86315de055"); static float sTime; @@ -79,9 +80,11 @@ LLDrawPoolWater::LLDrawPoolWater() : mHBTex[1]->setAddressMode(LLTexUnit::TAM_CLAMP); - mWaterImagep = LLViewerTextureManager::getFetchedTexture(WATER_TEST); + mWaterImagep = LLViewerTextureManager::getFetchedTexture(TRANSPARENT_WATER_TEXTURE); llassert(mWaterImagep); - mWaterImagep->setNoDelete() ; + mWaterImagep->setNoDelete(); + mOpaqueWaterImagep = LLViewerTextureManager::getFetchedTexture(OPAQUE_WATER_TEXTURE); + llassert(mOpaqueWaterImagep); mWaterNormp = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL); mWaterNormp->setNoDelete(); @@ -169,6 +172,13 @@ void LLDrawPoolWater::render(S32 pass) } std::sort(mDrawFace.begin(), mDrawFace.end(), LLFace::CompareDistanceGreater()); + static const LLCachedControl render_transparent_water("RenderTransparentWater",false); + if(!render_transparent_water) + { + // render water for low end hardware + renderOpaqueLegacyWater(); + return; + } LLGLEnable blend(GL_BLEND); @@ -323,6 +333,87 @@ void LLDrawPoolWater::render(S32 pass) gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } +// for low end hardware +void LLDrawPoolWater::renderOpaqueLegacyWater() +{ + LLVOSky *voskyp = gSky.mVOSkyp; + + stop_glerror(); + + // Depth sorting and write to depth buffer + // since this is opaque, we should see nothing + // behind the water. No blending because + // of no transparency. And no face culling so + // that the underside of the water is also opaque. + LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); + LLGLDisable no_cull(GL_CULL_FACE); + LLGLDisable no_blend(GL_BLEND); + + gPipeline.disableLights(); + + mOpaqueWaterImagep->addTextureStats(1024.f*1024.f); + + // Activate the texture binding and bind one + // texture since all images will have the same texture + gGL.getTexUnit(0)->activate(); + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->bind(mOpaqueWaterImagep); + + // Automatically generate texture coords for water texture + glEnable(GL_TEXTURE_GEN_S); //texture unit 0 + glEnable(GL_TEXTURE_GEN_T); //texture unit 0 + glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + + // Use the fact that we know all water faces are the same size + // to save some computation + + // Slowly move texture coordinates over time so the watter appears + // to be moving. + F32 movement_period_secs = 50.f; + + F32 offset = fmod(gFrameTimeSeconds, movement_period_secs); + + if (movement_period_secs != 0) + { + offset /= movement_period_secs; + } + else + { + offset = 0; + } + + F32 tp0[4] = { 16.f / 256.f, 0.0f, 0.0f, offset }; + F32 tp1[4] = { 0.0f, 16.f / 256.f, 0.0f, offset }; + + glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0); + glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1); + + glColor3f(1.f, 1.f, 1.f); + + for (std::vector::iterator iter = mDrawFace.begin(); + iter != mDrawFace.end(); iter++) + { + LLFace *face = *iter; + if (voskyp->isReflFace(face)) + { + continue; + } + + face->renderIndexed(); + } + + stop_glerror(); + + // Reset the settings back to expected values + glDisable(GL_TEXTURE_GEN_S); //texture unit 0 + glDisable(GL_TEXTURE_GEN_T); //texture unit 0 + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); +} + + void LLDrawPoolWater::renderReflection(LLFace* face) { LLVOSky *voskyp = gSky.mVOSkyp; @@ -603,23 +694,6 @@ void LLDrawPoolWater::shade() } -void LLDrawPoolWater::renderForSelect() -{ - // Can't select water! - return; -} - - -void LLDrawPoolWater::renderFaceSelected(LLFace *facep, - LLViewerTexture *image, - const LLColor4 &color, - const S32 index_offset, const S32 index_count) -{ - // Can't select water - return; -} - - LLViewerTexture *LLDrawPoolWater::getDebugTexture() { return LLViewerFetchedTexture::sSmokeImagep; diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h index 0ce14eae3..fe579ec26 100644 --- a/indra/newview/lldrawpoolwater.h +++ b/indra/newview/lldrawpoolwater.h @@ -45,6 +45,7 @@ class LLDrawPoolWater: public LLFacePool protected: LLPointer mHBTex[2]; LLPointer mWaterImagep; + LLPointer mOpaqueWaterImagep; LLPointer mWaterNormp; public: @@ -79,16 +80,16 @@ public: /*virtual*/ S32 getNumPasses(); /*virtual*/ void render(S32 pass = 0); - /*virtual*/ void renderFaceSelected(LLFace *facep, LLViewerTexture *image, const LLColor4 &color, - const S32 index_offset = 0, const S32 index_count = 0); /*virtual*/ void prerender(); - /*virtual*/ void renderForSelect(); /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display void renderReflection(LLFace* face); void shade(); + +protected: + void renderOpaqueLegacyWater(); }; void cgErrorCallback(); diff --git a/indra/newview/llpaneldisplay.cpp b/indra/newview/llpaneldisplay.cpp index 273e68fdb..c5606355e 100644 --- a/indra/newview/llpaneldisplay.cpp +++ b/indra/newview/llpaneldisplay.cpp @@ -697,7 +697,6 @@ void LLPanelDisplay::cancel() gSavedSettings.setBOOL("RenderUseImpostors", mAvatarImpostors); gSavedSettings.setBOOL("RenderAvatarCloth", mAvatarCloth); - gSavedSettings.setS32("RenderLightingDetail", mLightingDetail); gSavedSettings.setS32("RenderTerrainDetail", mTerrainDetail); gSavedSettings.setF32("RenderFarClip", mRenderFarClip); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 23c9535fa..f52e1703a 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -186,6 +186,12 @@ static bool handleSetSelfInvisible( const LLSD& newvalue) return true; } +bool handleRenderTransparentWaterChanged(const LLSD& newvalue) +{ + LLWorld::getInstance()->updateWaterObjects(); + return true; +} + static bool handleReleaseGLBufferChanged(const LLSD& newvalue) { if (gPipeline.isInit()) @@ -400,15 +406,6 @@ static bool handleWLSkyDetailChanged(const LLSD&) return true; } -static bool handleRenderLightingDetailChanged(const LLSD& newvalue) -{ - if (gPipeline.isInit()) - { - gPipeline.setLightingDetail(newvalue.asInteger()); - } - return true; -} - static bool handleResetVertexBuffersChanged(const LLSD&) { if (gPipeline.isInit()) @@ -574,8 +571,12 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderAnimateTrees")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _1)); gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); + gSavedSettings.getControl("RenderSpecularResX")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1)); + gSavedSettings.getControl("RenderSpecularResY")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1)); + gSavedSettings.getControl("RenderSpecularExponent")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1)); gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1)); gSavedSettings.getControl("RenderAnisotropic")->getSignal()->connect(boost::bind(&handleAnisotropicChanged, _1)); + gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1)); gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1)); gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); gSavedSettings.getControl("EnableRippleWater")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); @@ -587,19 +588,12 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderAvatarInvisible")->getSignal()->connect(boost::bind(&handleSetSelfInvisible, _1)); gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _1)); gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _1)); + gSavedSettings.getControl("RenderAvatarPhysicsLODFactor")->getSignal()->connect(boost::bind(&handleAvatarPhysicsLODChanged, _1)); gSavedSettings.getControl("RenderTerrainLODFactor")->getSignal()->connect(boost::bind(&handleTerrainLODChanged, _1)); gSavedSettings.getControl("RenderTreeLODFactor")->getSignal()->connect(boost::bind(&handleTreeLODChanged, _1)); - gSavedSettings.getControl("RenderAvatarPhysicsLODFactor")->getSignal()->connect(boost::bind(&handleAvatarPhysicsLODChanged, _1)); gSavedSettings.getControl("RenderFlexTimeFactor")->getSignal()->connect(boost::bind(&handleFlexLODChanged, _1)); gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&handleBandwidthChanged, _1)); gSavedSettings.getControl("RenderGamma")->getSignal()->connect(boost::bind(&handleGammaChanged, _1)); - gSavedSettings.getControl("EmeraldBoobMass")->getSignal()->connect(boost::bind(&handleAvatarBoobMassChanged, _1)); - gSavedSettings.getControl("EmeraldBoobHardness")->getSignal()->connect(boost::bind(&handleAvatarBoobHardnessChanged, _1)); - gSavedSettings.getControl("EmeraldBoobVelMax")->getSignal()->connect(boost::bind(&handleAvatarBoobVelMaxChanged, _1)); - gSavedSettings.getControl("EmeraldBoobFriction")->getSignal()->connect(boost::bind(&handleAvatarBoobFrictionChanged, _1)); - gSavedSettings.getControl("EmeraldBoobVelMin")->getSignal()->connect(boost::bind(&handleAvatarBoobVelMinChanged, _1)); - gSavedSettings.getControl("EmeraldBreastPhysicsToggle")->getSignal()->connect(boost::bind(&handleAvatarBoobToggleChanged, _1)); - gSavedSettings.getControl("EmeraldBoobXYInfluence")->getSignal()->connect(boost::bind(&handleAvatarBoobXYInfluence, _1)); gSavedSettings.getControl("RenderFogRatio")->getSignal()->connect(boost::bind(&handleFogRatioChanged, _1)); gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _1)); gSavedSettings.getControl("RenderDynamicLOD")->getSignal()->connect(boost::bind(&handleRenderDynamicLODChanged, _1)); @@ -617,7 +611,11 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _1)); gSavedSettings.getControl("RenderResolutionDivisor")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _1)); gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); + gSavedSettings.getControl("RenderShadowDetail")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); + gSavedSettings.getControl("RenderDeferredSSAO")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); + gSavedSettings.getControl("RenderDeferredGI")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _1)); + gSavedSettings.getControl("AuditTexture")->getSignal()->connect(boost::bind(&handleAuditTextureChanged, _1)); gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&handleChatFontSizeChanged, _1)); gSavedSettings.getControl("ChatPersistTime")->getSignal()->connect(boost::bind(&handleChatPersistTimeChanged, _1)); gSavedSettings.getControl("UploadBakedTexOld")->getSignal()->connect(boost::bind(&handleUploadBakedTexOldChanged, _1)); @@ -632,7 +630,6 @@ void settings_setup_listeners() gSavedSettings.getControl("AudioLevelDoppler")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); gSavedSettings.getControl("AudioStreamingMusic")->getSignal()->connect(boost::bind(&handleAudioStreamMusicChanged, _1)); - gSavedSettings.getControl("AuditTexture")->getSignal()->connect(boost::bind(&handleAuditTextureChanged, _1)); gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); @@ -642,7 +639,6 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleRenderUseVBOChanged, _1)); gSavedSettings.getControl("RenderVBOMappingDisable")->getSignal()->connect(boost::bind(&handleRenderUseVBOMappingChanged, _1)); gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _1)); - gSavedSettings.getControl("RenderLightingDetail")->getSignal()->connect(boost::bind(&handleRenderLightingDetailChanged, _1)); gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _1)); gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); gSavedSettings.getControl("JoystickAxis1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); @@ -710,7 +706,16 @@ void settings_setup_listeners() gSavedSettings.getControl("CloudsEnabled")->getSignal()->connect(boost::bind(&handleCloudSettingsChanged, _1)); gSavedSettings.getControl("SkyUseClassicClouds")->getSignal()->connect(boost::bind(&handleCloudSettingsChanged, _1)); + gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _1)); + gSavedSettings.getControl("EmeraldBoobMass")->getSignal()->connect(boost::bind(&handleAvatarBoobMassChanged, _1)); + gSavedSettings.getControl("EmeraldBoobHardness")->getSignal()->connect(boost::bind(&handleAvatarBoobHardnessChanged, _1)); + gSavedSettings.getControl("EmeraldBoobVelMax")->getSignal()->connect(boost::bind(&handleAvatarBoobVelMaxChanged, _1)); + gSavedSettings.getControl("EmeraldBoobFriction")->getSignal()->connect(boost::bind(&handleAvatarBoobFrictionChanged, _1)); + gSavedSettings.getControl("EmeraldBoobVelMin")->getSignal()->connect(boost::bind(&handleAvatarBoobVelMinChanged, _1)); + gSavedSettings.getControl("EmeraldBreastPhysicsToggle")->getSignal()->connect(boost::bind(&handleAvatarBoobToggleChanged, _1)); + gSavedSettings.getControl("EmeraldBoobXYInfluence")->getSignal()->connect(boost::bind(&handleAvatarBoobXYInfluence, _1)); + gSavedSettings.getControl("AscentUseTag")->getSignal()->connect(boost::bind(&handleAscentSelfTag,_1)); gSavedSettings.getControl("AscentUseCustomTag")->getSignal()->connect(boost::bind(&handleAscentSelfTag,_1)); gSavedSettings.getControl("AscentCustomTagColor")->getSignal()->connect(boost::bind(&handleAscentSelfTag,_1)); @@ -826,7 +831,7 @@ static LLCachedControl test_BrowserHomePage("BrowserHomePage", "hah void test_cached_control() { -#define TEST_LLCC(T, V) if((T)mySetting_##T != V) llerrs << "Fail "#T << llendl +#define do { TEST_LLCC(T, V) if((T)mySetting_##T != V) llerrs << "Fail "#T << llendl; } while(0) TEST_LLCC(U32, 666); TEST_LLCC(S32, (S32)-666); TEST_LLCC(F32, (F32)-666.666); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index ab8dc18f8..4d7642777 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -655,7 +655,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo LLPipeline::sFastAlpha = gSavedSettings.getBOOL("RenderFastAlpha"); LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip"); - LLVOAvatar::sMaxVisible = gSavedSettings.getS32("RenderAvatarMaxVisible"); + LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible"); LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate"); S32 occlusion = LLPipeline::sUseOcclusion; @@ -904,6 +904,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo for (U32 i = 0; i < 16; i++) { gGLLastModelView[i] = gGLModelView[i]; + gGLLastProjection[i] = gGLProjection[i]; } stop_glerror(); } @@ -1338,7 +1339,7 @@ void render_ui_2d() // render outline for HUD if (gAgent.getAvatarObject() && gAgent.mHUDCurZoom < 0.98f) { - glPushMatrix(); + gGL.pushMatrix(); S32 half_width = (gViewerWindow->getWindowWidth() / 2); S32 half_height = (gViewerWindow->getWindowHeight() / 2); glScalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f); @@ -1347,7 +1348,7 @@ void render_ui_2d() glScalef(zoom,zoom,1.f); gGL.color4fv(LLColor4::white.mV); gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE); - glPopMatrix(); + gGL.popMatrix(); stop_glerror(); } gViewerWindow->draw(); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 8ef475a24..84dedde5b 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -106,6 +106,7 @@ LLGLSLShader gPostGaussianBlurProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not // Deferred rendering shaders LLGLSLShader gDeferredImpostorProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredEdgeProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredWaterProgram(LLViewerShaderMgr::SHADER_DEFERRED); //calculatesAtmospherics LLGLSLShader gDeferredDiffuseProgram(LLViewerShaderMgr::SHADER_DEFERRED);//Not in mShaderList LLGLSLShader gDeferredBumpProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList @@ -115,14 +116,21 @@ LLGLSLShader gDeferredAvatarProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not LLGLSLShader gDeferredAvatarAlphaProgram(LLViewerShaderMgr::SHADER_DEFERRED); //calculatesAtmospherics LLGLSLShader gDeferredLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredMultiLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredSpotLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList +LLGLSLShader gDeferredMultiSpotLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList LLGLSLShader gDeferredSunProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredBlurLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredSoftenProgram(LLViewerShaderMgr::SHADER_DEFERRED); -LLGLSLShader gDeferredShadowProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList +LLGLSLShader gDeferredShadowProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList LLGLSLShader gDeferredAvatarShadowProgram(LLViewerShaderMgr::SHADER_DEFERRED);//Not in mShaderList LLGLSLShader gDeferredAlphaProgram(LLViewerShaderMgr::SHADER_DEFERRED); //calculatesAtmospherics LLGLSLShader gDeferredFullbrightProgram(LLViewerShaderMgr::SHADER_DEFERRED); //calculatesAtmospherics +LLGLSLShader gDeferredGIProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredGIFinalProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredPostGIProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredPostProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gLuminanceGatherProgram(LLViewerShaderMgr::SHADER_DEFERRED); //current avatar shader parameter pointer GLint gAvatarMatrixParam; @@ -195,13 +203,35 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void) mReservedUniforms.push_back("shadowMap1"); mReservedUniforms.push_back("shadowMap2"); mReservedUniforms.push_back("shadowMap3"); + mReservedUniforms.push_back("shadowMap4"); + mReservedUniforms.push_back("shadowMap5"); + 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("luminanceMap"); + mReservedUniforms.push_back("giLightMap"); + mReservedUniforms.push_back("giMip"); + mReservedUniforms.push_back("edgeMap"); + mReservedUniforms.push_back("bloomMap"); + mReservedUniforms.push_back("sunLightMap"); + mReservedUniforms.push_back("localLightMap"); + mReservedUniforms.push_back("projectionMap"); + mReservedUniforms.push_back("diffuseGIMap"); + mReservedUniforms.push_back("specularGIMap"); + mReservedUniforms.push_back("normalGIMap"); + mReservedUniforms.push_back("minpGIMap"); + mReservedUniforms.push_back("maxpGIMap"); + mReservedUniforms.push_back("depthGIMap"); + mReservedUniforms.push_back("lastDiffuseGIMap"); + mReservedUniforms.push_back("lastNormalGIMap"); + mReservedUniforms.push_back("lastMinpGIMap"); + mReservedUniforms.push_back("lastMaxpGIMap"); + mWLUniforms.push_back("camPosLocal"); mTerrainUniforms.reserve(5); @@ -312,7 +342,21 @@ void LLViewerShaderMgr::setShaders() if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && gSavedSettings.getBOOL("RenderDeferred")) { - deferred_class = 1; + if (gSavedSettings.getS32("RenderShadowDetail") > 0) + { + if (gSavedSettings.getBOOL("RenderDeferredGI")) + { //shadows + gi + deferred_class = 3; + } + else + { //shadows + deferred_class = 2; + } + } + else + { //no shadows + deferred_class = 1; + } //make sure framebuffer objects are enabled gSavedSettings.setBOOL("RenderUseFBO", TRUE); @@ -323,6 +367,8 @@ void LLViewerShaderMgr::setShaders() //make sure atmospheric shaders are enabled gSavedSettings.setBOOL("WindLightUseAtmosShaders", TRUE); } + + if (!(LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders") && gSavedSettings.getBOOL("WindLightUseAtmosShaders"))) { @@ -838,10 +884,41 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { + gDeferredSpotLightProgram.mName = "Deferred SpotLight Shader"; + gDeferredSpotLightProgram.mShaderFiles.clear(); + gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredSpotLightProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredMultiSpotLightProgram.mName = "Deferred MultiSpotLight Shader"; + gDeferredMultiSpotLightProgram.mShaderFiles.clear(); + gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredMultiSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredMultiSpotLightProgram.createShader(NULL, NULL); + } + + if (success) + { + std::string fragment; + + if (gSavedSettings.getBOOL("RenderDeferredSSAO")) + { + fragment = "deferred/sunLightSSAOF.glsl"; + } + else + { + fragment = "deferred/sunLightF.glsl"; + } + gDeferredSunProgram.mName = "Deferred Sun Shader"; gDeferredSunProgram.mShaderFiles.clear(); gDeferredSunProgram.mShaderFiles.push_back(make_pair("deferred/sunLightV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredSunProgram.mShaderFiles.push_back(make_pair("deferred/sunLightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSunProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER_ARB)); gDeferredSunProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredSunProgram.createShader(NULL, NULL); } @@ -967,6 +1044,72 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredAvatarAlphaProgram.createShader(&mAvatarAttribs, &mAvatarUniforms); } + if (mVertexShaderLevel[SHADER_DEFERRED] > 1) + { + if (success) + { + gDeferredEdgeProgram.mName = "Deferred Edge Shader"; + gDeferredEdgeProgram.mShaderFiles.clear(); + gDeferredEdgeProgram.mShaderFiles.push_back(make_pair("deferred/edgeV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredEdgeProgram.mShaderFiles.push_back(make_pair("deferred/edgeF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredEdgeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredEdgeProgram.createShader(NULL, NULL); + } + } + + if (mVertexShaderLevel[SHADER_DEFERRED] > 2) + { + if (success) + { + gDeferredPostProgram.mName = "Deferred Post Shader"; + gDeferredPostProgram.mShaderFiles.clear(); + gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredPostProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredPostProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredPostGIProgram.mName = "Deferred Post GI Shader"; + gDeferredPostGIProgram.mShaderFiles.clear(); + gDeferredPostGIProgram.mShaderFiles.push_back(make_pair("deferred/postgiV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredPostGIProgram.mShaderFiles.push_back(make_pair("deferred/postgiF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredPostGIProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredPostGIProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredGIProgram.mName = "Deferred GI Shader"; + gDeferredGIProgram.mShaderFiles.clear(); + gDeferredGIProgram.mShaderFiles.push_back(make_pair("deferred/giV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredGIProgram.mShaderFiles.push_back(make_pair("deferred/giF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredGIProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredGIProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredGIFinalProgram.mName = "Deferred GI Final Shader"; + gDeferredGIFinalProgram.mShaderFiles.clear(); + gDeferredGIFinalProgram.mShaderFiles.push_back(make_pair("deferred/giFinalV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredGIFinalProgram.mShaderFiles.push_back(make_pair("deferred/giFinalF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredGIFinalProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredGIFinalProgram.createShader(NULL, NULL); + } + + if (success) + { + gLuminanceGatherProgram.mName = "Luminance Gather Shader"; + gLuminanceGatherProgram.mShaderFiles.clear(); + gLuminanceGatherProgram.mShaderFiles.push_back(make_pair("deferred/luminanceV.glsl", GL_VERTEX_SHADER_ARB)); + gLuminanceGatherProgram.mShaderFiles.push_back(make_pair("deferred/luminanceF.glsl", GL_FRAGMENT_SHADER_ARB)); + gLuminanceGatherProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gLuminanceGatherProgram.createShader(NULL, NULL); + } + } + return success; } diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 8fa582909..10abc9935 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -116,12 +116,33 @@ public: 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_LUMINANCE, + DEFERRED_GI_LIGHT, + DEFERRED_GI_MIP, + DEFERRED_EDGE, + DEFERRED_BLOOM, + DEFERRED_SUN_LIGHT, + DEFERRED_LOCAL_LIGHT, + DEFERRED_PROJECTION, + DEFERRED_GI_DIFFUSE, + DEFERRED_GI_SPECULAR, + DEFERRED_GI_NORMAL, + DEFERRED_GI_MIN_POS, + DEFERRED_GI_MAX_POS, + DEFERRED_GI_DEPTH, + DEFERRED_GI_LAST_DIFFUSE, + DEFERRED_GI_LAST_NORMAL, + DEFERRED_GI_LAST_MIN_POS, + DEFERRED_GI_LAST_MAX_POS, END_RESERVED_UNIFORMS } eGLSLReservedUniforms; @@ -324,6 +345,7 @@ extern LLGLSLShader gPostGaussianBlurProgram; // Deferred rendering shaders extern LLGLSLShader gDeferredImpostorProgram; +extern LLGLSLShader gDeferredEdgeProgram; extern LLGLSLShader gDeferredWaterProgram; extern LLGLSLShader gDeferredDiffuseProgram; extern LLGLSLShader gDeferredBumpProgram; @@ -331,16 +353,24 @@ extern LLGLSLShader gDeferredTerrainProgram; extern LLGLSLShader gDeferredTreeProgram; extern LLGLSLShader gDeferredLightProgram; extern LLGLSLShader gDeferredMultiLightProgram; +extern LLGLSLShader gDeferredSpotLightProgram; +extern LLGLSLShader gDeferredMultiSpotLightProgram; extern LLGLSLShader gDeferredSunProgram; +extern LLGLSLShader gDeferredGIProgram; +extern LLGLSLShader gDeferredGIFinalProgram; extern LLGLSLShader gDeferredBlurLightProgram; extern LLGLSLShader gDeferredAvatarProgram; extern LLGLSLShader gDeferredSoftenProgram; extern LLGLSLShader gDeferredShadowProgram; +extern LLGLSLShader gDeferredPostGIProgram; +extern LLGLSLShader gDeferredPostProgram; extern LLGLSLShader gDeferredAvatarShadowProgram; extern LLGLSLShader gDeferredAlphaProgram; extern LLGLSLShader gDeferredFullbrightProgram; extern LLGLSLShader gDeferredAvatarAlphaProgram; +extern LLGLSLShader gLuminanceGatherProgram; + //current avatar shader parameter pointer extern GLint gAvatarMatrixParam; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 5c1b22fa6..997a393ff 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -531,7 +531,7 @@ void update_statistics(U32 frame_count) } } LLViewerStats::getInstance()->setStat(LLViewerStats::ST_ENABLE_VBO, (F64)gSavedSettings.getBOOL("RenderVBOEnable")); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gSavedSettings.getS32("RenderLightingDetail")); + //LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gSavedSettings.getS32("RenderLightingDetail")); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_DRAW_DIST, (F64)gSavedSettings.getF32("RenderFarClip")); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CHAT_BUBBLES, (F64)gSavedSettings.getBOOL("UseChatBubbles")); #if 0 // 1.9.2 diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 85d0e5f4c..f8a6ff0a0 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -5321,7 +5321,7 @@ U32 LLVOAvatar::renderFootShadows() return num_indices; } -U32 LLVOAvatar::renderImpostor(LLColor4U color) +U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) { if (!mImpostor.isComplete()) { @@ -5341,7 +5341,7 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color) gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f); gGL.color4ubv(color.mV); - gGL.getTexUnit(0)->bind(&mImpostor); + gGL.getTexUnit(diffuse_channel)->bind(&mImpostor); gGL.begin(LLRender::QUADS); gGL.texCoord2f(0,0); gGL.vertex3fv((pos+left-up).mV); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index e21337c90..068b7369e 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -139,7 +139,7 @@ public: // Graphical stuff for objects - maybe broken out into render class later? U32 renderFootShadows(); - U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255)); + U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0); U32 renderRigid(); U32 renderSkinned(EAvatarRenderPass pass); U32 renderTransparent(BOOL first_pass); diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index b6ba7e50f..3b61a7fa9 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -486,7 +486,9 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) U32 end = start + facep->getGeomCount()-1; U32 offset = facep->getIndicesStart(); U32 count = facep->getIndicesCount(); - LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), buffer, fullbright); + LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), + //facep->getTexture(), + buffer, fullbright); info->mExtents[0] = group->mObjectExtents[0]; info->mExtents[1] = group->mObjectExtents[1]; info->mVSize = vsize; diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index f2f835220..f27d3f582 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -1039,7 +1039,7 @@ void LLVOSky::calcAtmospherics(void) // Since WL scales everything by 2, there should always be at least a 2:1 brightness ratio // between sunlight and point lights in windlight to normalize point lights. - static const LLCachedControl render_sun_dynamic_range("RenderSunDynamicRange", 1); + static const LLCachedControl render_sun_dynamic_range("RenderSunDynamicRange", 1.f); F32 sun_dynamic_range = llmax((float)render_sun_dynamic_range, 0.0001f); LLWLParamManager::instance()->mSceneLightStrength = 2.0f * (1.0f + sun_dynamic_range * dp); diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 8e0d09f2a..a6e09e0a4 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -388,12 +388,11 @@ BOOL LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) } } - S32 trunk_LOD = 0; + S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS ; F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor; - for (S32 j = 0; j < 4; j++) + for (S32 j = 0; j < sMAX_NUM_TREE_LOD_LEVELS; j++) { - if (app_angle > LLVOTree::sLODAngles[j]) { trunk_LOD = j; @@ -531,6 +530,13 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE); + if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree. + { + mReferenceBuffer = NULL ; + mDrawable->getFace(0)->mVertexBuffer = NULL ; + return TRUE ; + } + if (mReferenceBuffer.isNull() || mDrawable->getFace(0)->mVertexBuffer.isNull()) { const F32 SRR3 = 0.577350269f; // sqrt(1/3) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 62c9ec640..d9411c67d 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -95,6 +95,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mNumFaces = 0; mLODChanged = FALSE; mSculptChanged = FALSE; + mSpotLightPriority = 0.f; mIndexInTex = 0; } @@ -614,6 +615,19 @@ void LLVOVolume::updateTextureVirtualSize() } } + if (getLightTextureID().notNull()) + { + LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + LLUUID id = params->getLightTexture(); + mLightTexture = LLViewerTextureManager::getFetchedTexture(id); + if (mLightTexture.notNull()) + { + F32 rad = getLightRadius(); + mLightTexture->addTextureStats(gPipeline.calcPixelArea(getPositionAgent(), + LLVector3(rad,rad,rad), + *camera)); + } + } if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) { @@ -1494,6 +1508,41 @@ void LLVOVolume::updateTEData() //---------------------------------------------------------------------------- +void LLVOVolume::setLightTextureID(LLUUID id) +{ + if (id.notNull()) + { + if (!hasLightTexture()) + { + setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, TRUE, true); + } + LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + if (param_block && param_block->getLightTexture() != id) + { + param_block->setLightTexture(id); + parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true); + } + } + else + { + if (hasLightTexture()) + { + setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, FALSE, true); + mLightTexture = NULL; + } + } +} + +void LLVOVolume::setSpotLightParams(LLVector3 params) +{ + LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + if (param_block && param_block->getParams() != params) + { + param_block->setParams(params); + parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true); + } +} + void LLVOVolume::setIsLight(BOOL is_light) { if (is_light != getIsLight()) @@ -1620,6 +1669,94 @@ LLColor3 LLVOVolume::getLightColor() const } } +LLUUID LLVOVolume::getLightTextureID() const +{ + if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + { + const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + if (param_block) + { + return param_block->getLightTexture(); + } + } + + return LLUUID::null; +} + + +LLVector3 LLVOVolume::getSpotLightParams() const +{ + if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + { + const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + if (param_block) + { + return param_block->getParams(); + } + } + + return LLVector3(); +} + +F32 LLVOVolume::getSpotLightPriority() const +{ + return mSpotLightPriority; +} + +void LLVOVolume::updateSpotLightPriority() +{ + LLVector3 pos = mDrawable->getPositionAgent(); + LLVector3 at(0,0,-1); + at *= getRenderRotation(); + + F32 r = getLightRadius()*0.5f; + + pos += at * r; + + at = LLViewerCamera::getInstance()->getAtAxis(); + + pos -= at * r; + + mSpotLightPriority = gPipeline.calcPixelArea(pos, LLVector3(r,r,r), *LLViewerCamera::getInstance()); + + if (mLightTexture.notNull()) + { + mLightTexture->addTextureStats(mSpotLightPriority); + mLightTexture->setBoostLevel(LLViewerTexture::BOOST_CLOUDS); + } +} + + +bool LLVOVolume::isLightSpotlight() const +{ + LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + if (params) + { + return params->isLightSpotlight(); + } + return false; +} + + +LLViewerTexture* LLVOVolume::getLightTexture() +{ + LLUUID id = getLightTextureID(); + + if (id.notNull()) + { + if (mLightTexture.isNull() || id != mLightTexture->getID()) + { + mLightTexture = LLViewerTextureManager::getFetchedTexture(id); + } + } + else + { + mLightTexture = NULL; + } + + return mLightTexture; +} + F32 LLVOVolume::getLightIntensity() const { const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); @@ -1711,6 +1848,16 @@ BOOL LLVOVolume::isSculpted() const return FALSE; } +BOOL LLVOVolume::hasLightTexture() const +{ + if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + { + return TRUE; + } + + return FALSE; +} + BOOL LLVOVolume::isVolumeGlobal() const { if (mVolumeImpl) diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 8f1b11bae..8b7dc172e 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -201,9 +201,19 @@ public: void setLightRadius(F32 radius); void setLightFalloff(F32 falloff); void setLightCutoff(F32 cutoff); + void setLightTextureID(LLUUID id); + void setSpotLightParams(LLVector3 params); + BOOL getIsLight() const; LLColor3 getLightBaseColor() const; // not scaled by intensity LLColor3 getLightColor() const; // scaled by intensity + LLUUID getLightTextureID() const; + bool isLightSpotlight() const; + LLVector3 getSpotLightParams() const; + void updateSpotLightPriority(); + F32 getSpotLightPriority() const; + + LLViewerTexture* getLightTexture(); F32 getLightIntensity() const; F32 getLightRadius() const; F32 getLightFalloff() const; @@ -213,6 +223,8 @@ public: U32 getVolumeInterfaceID() const; virtual BOOL isFlexible() const; virtual BOOL isSculpted() const; + virtual BOOL hasLightTexture() const; + BOOL isVolumeGlobal() const; BOOL canBeFlexible() const; BOOL setIsFlexible(BOOL is_flexible); @@ -237,12 +249,14 @@ private: S32 mLOD; BOOL mLODChanged; BOOL mSculptChanged; + F32 mSpotLightPriority; LLMatrix4 mRelativeXform; LLMatrix3 mRelativeXformInvTrans; BOOL mVolumeChanged; F32 mVObjRadius; LLVolumeInterface *mVolumeImpl; LLPointer mSculptTexture; + LLPointer mLightTexture; S32 mIndexInTex; // statics diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 0e80c62b2..34ad85f44 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -69,7 +69,9 @@ const U32 WIDTH = (N_RES * WAVE_STEP); //128.f //64 // width of wave tile, in const F32 WAVE_STEP_INV = (1. / WAVE_STEP); -LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : +LLVOWater::LLVOWater(const LLUUID &id, + const LLPCode pcode, + LLViewerRegion *regionp) : LLStaticViewerObject(id, pcode, regionp), mRenderType(LLPipeline::RENDER_TYPE_WATER) { @@ -160,10 +162,16 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) LLStrider indicesp; U16 index_offset; - S32 size = 16; - S32 num_quads = size*size; - face->setSize(4*num_quads, 6*num_quads); + // A quad is 4 vertices and 6 indices (making 2 triangles) + static const unsigned int vertices_per_quad = 4; + static const unsigned int indices_per_quad = 6; + + static const LLCachedControl render_transparent_water("RenderTransparentWater",false); + const S32 size = render_transparent_water ? 16 : 1; + const S32 num_quads = size * size; + face->setSize(vertices_per_quad * num_quads, + indices_per_quad * num_quads); if (face->mVertexBuffer.isNull()) { diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index e10b64409..66d459501 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -166,6 +166,9 @@ std::string gPoolNames[] = "POOL_INVALID_OUCH_CATASTROPHE_ERROR" }; +void drawBox(const LLVector3& c, const LLVector3& r); +void drawBoxOutline(const LLVector3& pos, const LLVector3& size); + U32 nhpo2(U32 v) { U32 r = 1; @@ -277,11 +280,11 @@ static const U32 gl_cube_face[] = void validate_framebuffer_object(); + void addDeferredAttachments(LLRenderTarget& target) { - target.addColorAttachment(GL_RGBA16F_ARB); //specular - target.addColorAttachment(GL_RGBA16F_ARB); //normal+z - target.addColorAttachment(GL_RGBA16F_ARB); //position + target.addColorAttachment(GL_RGBA); //specular + target.addColorAttachment(GL_RGBA); //normal+z } LLPipeline::LLPipeline() : @@ -322,6 +325,8 @@ LLPipeline::LLPipeline() : mLightingDetail(0) { mNoiseMap = 0; + mTrueNoiseMap = 0; + mLightFunc = 0; } void LLPipeline::init() @@ -377,6 +382,11 @@ void LLPipeline::init() LLViewerShaderMgr::instance()->setShaders(); stop_glerror(); + + for (U32 i = 0; i < 2; ++i) + { + mSpotLightFade[i] = 1.f; + } setLightingDetail(-1); } @@ -504,22 +514,47 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) if (LLPipeline::sRenderDeferred) { //allocate deferred rendering color buffers - mDeferredScreen.allocate(resX, resY, GL_RGBA16F_ARB, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + const GLuint format = GL_RGBA; //GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later + mDeferredScreen.allocate(resX, resY, format, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); addDeferredAttachments(mDeferredScreen); - mScreen.allocate(resX, resY, GL_RGBA16F_ARB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); - + + mScreen.allocate(resX, resY, format, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + + for (U32 i = 0; i < 3; i++) + { + mDeferredLight[i].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); + } + for (U32 i = 0; i < 2; i++) { - mDeferredLight[i].allocate(resX, resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); + mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); } - + + F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale"); + //HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug) - U32 shadow_fmt = 0;/*gGLManager.mIsATI ? GL_ALPHA : 0;*/ + //TO-DO: Test if this is actually needed. + U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0; for (U32 i = 0; i < 4; i++) { - mSunShadow[i].allocate(1024,1024, shadow_fmt, TRUE, FALSE); + mShadow[i].allocate(U32(resX*scale),U32(resY*scale), shadow_fmt, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE); } + + + U32 width = nhpo2(U32(resX*scale))/2; + U32 height = width; + + for (U32 i = 4; i < 6; i++) + { + mShadow[i].allocate(width, height, shadow_fmt, TRUE, FALSE); + } + + width = nhpo2(resX)/2; + height = nhpo2(resY)/2; + mLuminanceMap.allocate(width,height, GL_RGBA, FALSE, FALSE); } else { @@ -531,7 +566,8 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) { if (LLPipeline::sRenderDeferred) { - mSampleBuffer.allocate(resX,resY,GL_RGBA16F_ARB,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples); + const GLuint format = GL_RGBA; //GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later + mSampleBuffer.allocate(resX,resY,format,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples); addDeferredAttachments(mSampleBuffer); mDeferredScreen.setSampleBuffer(&mSampleBuffer); } @@ -544,11 +580,12 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) stop_glerror(); } + if (LLPipeline::sRenderDeferred) { //share depth buffer between deferred targets mDeferredScreen.shareDepthBuffer(mScreen); - for (U32 i = 0; i < 2; i++) - { + for (U32 i = 0; i < 3; i++) + { //share stencil buffer with screen space lightmap to stencil out sky mDeferredScreen.shareDepthBuffer(mDeferredLight[i]); } } @@ -564,6 +601,7 @@ void LLPipeline::updateRenderDeferred() { sRenderDeferred = (gSavedSettings.getBOOL("RenderDeferred") && LLRenderTarget::sUseFBO && + LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && gSavedSettings.getBOOL("VertexShaderEnable") && gSavedSettings.getBOOL("RenderAvatarVP") && gSavedSettings.getBOOL("WindLightUseAtmosShaders") && @@ -580,21 +618,40 @@ void LLPipeline::releaseGLBuffers() mNoiseMap = 0; } + if (mTrueNoiseMap) + { + LLImageGL::deleteTextures(1, &mTrueNoiseMap); + mTrueNoiseMap = 0; + } + + if (mLightFunc) + { + LLImageGL::deleteTextures(1, &mLightFunc); + mLightFunc = 0; + } + mWaterRef.release(); mWaterDis.release(); mScreen.release(); mSampleBuffer.releaseSampleBuffer(); mDeferredScreen.release(); - - - for (U32 i = 0; i < 2; i++) + mDeferredDepth.release(); + for (U32 i = 0; i < 3; i++) { mDeferredLight[i].release(); } - for (U32 i = 0; i < 4; i++) + + mEdgeMap.release(); + mGIMap.release(); + mGIMapPost[0].release(); + mGIMapPost[1].release(); + mLuminanceMap.release(); + + for (U32 i = 0; i < 6; i++) { - mSunShadow[i].release(); + mShadow[i].release(); } + for (U32 i = 0; i < 3; i++) { mGlow[i].release(); @@ -634,11 +691,11 @@ void LLPipeline::createGLBuffers() } allocateScreenBuffer(resX,resY); + } if (sRenderDeferred) { - if (!mNoiseMap) { const U32 noiseRes = 128; @@ -658,6 +715,66 @@ void LLPipeline::createGLBuffers() LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } + + if (!mTrueNoiseMap) + { + const U32 noiseRes = 128; + F32 noise[noiseRes*noiseRes*3]; + for (U32 i = 0; i < noiseRes*noiseRes*3; i++) + { + noise[i] = ll_frand()*2.0-1.0; + } + + LLImageGL::generateTextures(1, &mTrueNoiseMap); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + if (!mLightFunc) + { + U32 lightResX = gSavedSettings.getU32("RenderSpecularResX"); + U32 lightResY = gSavedSettings.getU32("RenderSpecularResY"); + U8* lg = new U8[lightResX*lightResY]; + + for (U32 y = 0; y < lightResY; ++y) + { + for (U32 x = 0; x < lightResX; ++x) + { + //spec func + F32 sa = (F32) x/(lightResX-1); + F32 spec = (F32) y/(lightResY-1); + //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255); + + //F32 sp = acosf(sa)/(1.f-spec); + + sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent")); + F32 a = acosf(sa*0.25f+0.75f); + F32 m = llmax(0.5f-spec*0.5f, 0.001f); + F32 t2 = tanf(a)/m; + t2 *= t2; + + F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f; + F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2); + + lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255); + } + } + + LLImageGL::generateTextures(1, &mLightFunc); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_ALPHA, lightResX, lightResY, GL_ALPHA, GL_UNSIGNED_BYTE, lg); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); + + delete [] lg; + } + + if (gSavedSettings.getBOOL("RenderDeferredGI")) + { + mGIMap.allocate(512,512,GL_RGBA, TRUE, FALSE); + addDeferredAttachments(mGIMap); + } } } @@ -752,13 +869,18 @@ S32 LLPipeline::setLightingDetail(S32 level) if (level < 0) { - level = gSavedSettings.getS32("RenderLightingDetail"); + if (gSavedSettings.getBOOL("VertexShaderEnable")) + { + level = 1; + } + else + { + level = 0; + } } level = llclamp(level, 0, getMaxLightingDetail()); if (level != mLightingDetail) { - gSavedSettings.setS32("RenderLightingDetail", level); - mLightingDetail = level; if (mVertexShadersLoaded == 1) @@ -1035,6 +1157,21 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) break; } } + + for (U32 i = 0; i < 2; ++i) + { + if (mShadowSpotLight[i] == drawablep) + { + mShadowSpotLight[i] = NULL; + } + + if (mTargetShadowSpotLight[i] == drawablep) + { + mTargetShadowSpotLight[i] = NULL; + } + } + + } U32 LLPipeline::addObject(LLViewerObject *vobj) @@ -1335,8 +1472,10 @@ BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera) BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max) { - min = LLVector3(F32_MAX, F32_MAX, F32_MAX); - max = LLVector3(-F32_MAX, -F32_MAX, -F32_MAX); + const F32 X = 65536.f; + + min = LLVector3(X,X,X); + max = LLVector3(-X,-X,-X); U32 saved_camera_id = LLViewerCamera::sCurCameraID; LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; @@ -1390,10 +1529,10 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl mScreen.bindTarget(); } - /*glMatrixMode(GL_PROJECTION); + glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadMatrixd(gGLLastProjection); - glMatrixMode(GL_MODELVIEW);*/ + glMatrixMode(GL_MODELVIEW); glPushMatrix(); gGLLastMatrix = NULL; glLoadMatrixd(gGLLastModelView); @@ -1462,9 +1601,9 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl } - /*glMatrixMode(GL_PROJECTION); + glMatrixMode(GL_PROJECTION); glPopMatrix(); - glMatrixMode(GL_MODELVIEW);*/ + glMatrixMode(GL_MODELVIEW); glPopMatrix(); if (sUseOcclusion > 1) @@ -1476,10 +1615,10 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl { mScreen.flush(); } - else if (LLPipeline::sUseOcclusion > 1) + /*else if (LLPipeline::sUseOcclusion > 1) { glFlush(); - } + }*/ } void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) @@ -1773,41 +1912,39 @@ void LLPipeline::updateGeom(F32 max_dtime) void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) { LLMemType mt(LLMemType::MTYPE_PIPELINE); - if(!drawablep || drawablep->isDead()) + + if(drawablep && !drawablep->isDead()) { - return; - } - - if (drawablep->isSpatialBridge()) - { - const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable; - llassert(root); // trying to catch a bad assumption - if (root && // // this test may not be needed, see above - root->getVObj()->isAttachment()) + if (drawablep->isSpatialBridge()) { - LLDrawable* rootparent = root->getParent(); - if (rootparent) // this IS sometimes NULL + const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable; + llassert(root); // trying to catch a bad assumption + if (root && // // this test may not be needed, see above + root->getVObj()->isAttachment()) { - LLViewerObject *vobj = rootparent->getVObj(); - llassert(vobj); // trying to catch a bad assumption - if (vobj) // this test may not be needed, see above + LLDrawable* rootparent = root->getParent(); + if (rootparent) // this IS sometimes NULL { - if (vobj->isAvatar() && ((LLVOAvatar*)vobj)->isImpostor()) + LLViewerObject *vobj = rootparent->getVObj(); + llassert(vobj); // trying to catch a bad assumption + if (vobj) // this test may not be needed, see above { - return; + if (vobj->isAvatar() && ((LLVOAvatar*)vobj)->isImpostor()) + { + return; + } } } } + sCull->pushBridge((LLSpatialBridge*) drawablep); + } + else + { + sCull->pushDrawable(drawablep); } - - sCull->pushBridge((LLSpatialBridge*) drawablep); - } - else - { - sCull->pushDrawable(drawablep); - } - drawablep->setVisible(camera); + drawablep->setVisible(camera); + } } void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) @@ -2257,7 +2394,8 @@ void renderScriptedBeacons(LLDrawable* drawablep) { if (gPipeline.sRenderBeacons) { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + static const LLCachedControl debug_beacon_line_width("DebugBeaconLineWidth",1); + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), debug_beacon_line_width); } if (gPipeline.sRenderHighlight) @@ -2283,7 +2421,8 @@ void renderScriptedTouchBeacons(LLDrawable* drawablep) { if (gPipeline.sRenderBeacons) { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + static const LLCachedControl debug_beacon_line_width("DebugBeaconLineWidth",1); + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), debug_beacon_line_width); } if (gPipeline.sRenderHighlight) @@ -2308,7 +2447,8 @@ void renderPhysicalBeacons(LLDrawable* drawablep) { if (gPipeline.sRenderBeacons) { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + static const LLCachedControl debug_beacon_line_width("DebugBeaconLineWidth",1); + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), debug_beacon_line_width); } if (gPipeline.sRenderHighlight) @@ -2333,7 +2473,8 @@ void renderParticleBeacons(LLDrawable* drawablep) if (gPipeline.sRenderBeacons) { LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f); - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + static const LLCachedControl debug_beacon_line_width("DebugBeaconLineWidth",1); + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), debug_beacon_line_width); } if (gPipeline.sRenderHighlight) @@ -2548,7 +2689,8 @@ void LLPipeline::postSort(LLCamera& camera) if (gPipeline.sRenderBeacons) { //pos += LLVector3(0.f, 0.f, 0.2f); - gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + static const LLCachedControl debug_beacon_line_width("DebugBeaconLineWidth",1); + gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), debug_beacon_line_width); } } // now deal with highlights for all those seeable sound sources @@ -2616,15 +2758,8 @@ void render_hud_elements() LLViewerParcelMgr::getInstance()->render(); LLViewerParcelMgr::getInstance()->renderParcelCollision(); - // Render debugging beacons. - //gObjectList.renderObjectBeacons(); - - //TO-DO: - //V2 moved this line from LLPipeline::renderGeom - //Uncomment once multisample z-buffer issues are figured out on ati cards. - LLHUDObject::renderAll(); - - //gObjectList.resetObjectBeacons(); + // Render name tags. + LLHUDObject::renderAll(); } else if (gForceRenderLandFence) { @@ -2946,10 +3081,6 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) { // Render debugging beacons. gObjectList.renderObjectBeacons(); - //TO-DO: - //V2 moved this line to LLPipeline::render_hud_elements - //Migrate once multisample z-buffer issues are figured out on ati cards. - //LLHUDObject::renderAll(); gObjectList.resetObjectBeacons(); } else @@ -3178,33 +3309,6 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) gGLLastMatrix = NULL; glLoadMatrixd(gGLModelView); - //TO-DO: - //V2 moved block to LLPipeline::renderDeferredLighting - //Migrate once multisample z-buffer issues are figured out on ati cards. - /*if(!sImpostorRender) - { - renderHighlights(); - mHighlightFaces.clear(); - - renderDebug(); - - LLVertexBuffer::unbind(); - - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - // Render debugging beacons. - gObjectList.renderObjectBeacons(); - LLHUDObject::renderAll(); - gObjectList.resetObjectBeacons(); - } - else - { - // Make sure particle effects disappear - LLHUDObject::renderAllForTimer(); - } - }*/ - //END - if (occlude) { occlude = FALSE; @@ -3332,7 +3436,7 @@ void LLPipeline::renderDebug() for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) { LLSpatialBridge* bridge = *i; - if (!bridge->isDead() && !bridge->isState(LLSpatialGroup::OCCLUDED) && hasRenderType(bridge->mDrawableType)) + if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) { glPushMatrix(); glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); @@ -3343,79 +3447,113 @@ void LLPipeline::renderDebug() if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) { + LLGLEnable blend(GL_BLEND); + LLGLDepthTest depth(TRUE, FALSE); + LLGLDisable cull(GL_CULL_FACE); + gGL.color4f(1,1,1,1); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + F32 a = 0.1f; + F32 col[] = { - 1,1,0, - 0,1,1, - 1,0,1, - 1,1,1, - 1,0,0, - 0,1,0, - 0,0,1, - 0,0,0 + 1,0,0,a, + 0,1,0,a, + 0,0,1,a, + 1,0,1,a, + + 1,1,0,a, + 0,1,1,a, + 1,1,1,a, + 1,0,1,a, }; for (U32 i = 0; i < 8; i++) { - gGL.color3fv(col+i*3); - - gGL.begin(LLRender::LINES); - LLVector3* frust = mShadowCamera[i].mAgentFrustum; - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV); - gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV); - gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV); - gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV); - - gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV); - gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV); - gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV); - - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); - gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); - gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); - - if (i < 4) + if (i > 3) + { //render shadow frusta as volumes + if (mShadowFrustPoints[i-4].empty()) { - LLVector3* ext = mShadowExtents[i]; - - LLVector3 box[] = - { - LLVector3(ext[0][0], ext[0][1], ext[0][2]), - LLVector3(ext[1][0], ext[0][1], ext[0][2]), - LLVector3(ext[1][0], ext[1][1], ext[0][2]), - LLVector3(ext[0][0], ext[1][1], ext[0][2]), - LLVector3(ext[0][0], ext[0][1], ext[1][2]), - LLVector3(ext[1][0], ext[0][1], ext[1][2]), - LLVector3(ext[1][0], ext[1][1], ext[1][2]), - LLVector3(ext[0][0], ext[1][1], ext[1][2]), - }; - - gGL.vertex3fv(box[0].mV); gGL.vertex3fv(box[1].mV); - gGL.vertex3fv(box[1].mV); gGL.vertex3fv(box[2].mV); - gGL.vertex3fv(box[2].mV); gGL.vertex3fv(box[3].mV); - gGL.vertex3fv(box[3].mV); gGL.vertex3fv(box[0].mV); + continue; + } - gGL.vertex3fv(box[4].mV); gGL.vertex3fv(box[5].mV); - gGL.vertex3fv(box[5].mV); gGL.vertex3fv(box[6].mV); - gGL.vertex3fv(box[6].mV); gGL.vertex3fv(box[7].mV); - gGL.vertex3fv(box[7].mV); gGL.vertex3fv(box[4].mV); + gGL.color4fv(col+(i-4)*4); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); + gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); + gGL.end(); - gGL.vertex3fv(box[0].mV); gGL.vertex3fv(box[4].mV); - gGL.vertex3fv(box[1].mV); gGL.vertex3fv(box[5].mV); - gGL.vertex3fv(box[2].mV); gGL.vertex3fv(box[6].mV); - gGL.vertex3fv(box[3].mV); gGL.vertex3fv(box[7].mV); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(frust[0].mV); + gGL.vertex3fv(frust[1].mV); + gGL.vertex3fv(frust[3].mV); + gGL.vertex3fv(frust[2].mV); + gGL.end(); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[7].mV); + gGL.vertex3fv(frust[6].mV); + gGL.end(); } - gGL.end(); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + + if (i < 4) + { + + if (i == 0 || !mShadowFrustPoints[i].empty()) + { + //render visible point cloud + gGL.flush(); + glPointSize(8.f); + gGL.begin(LLRender::POINTS); + + F32* c = col+i*4; + gGL.color3fv(c); + + for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j) + { + gGL.vertex3fv(mShadowFrustPoints[i][j].mV); + } + gGL.end(); + + gGL.flush(); + glPointSize(1.f); + + LLVector3* ext = mShadowExtents[i]; + LLVector3 pos = (ext[0]+ext[1])*0.5f; + LLVector3 size = (ext[1]-ext[0])*0.5f; + drawBoxOutline(pos, size); + + //render camera frustum splits as outlines + gGL.begin(LLRender::LINES); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV); + gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV); + gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV); + gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV); + gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV); + gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV); + gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); + gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); + gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); + gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); + gGL.end(); + } + + } + + /*for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { LLViewerRegion* region = *iter; @@ -3430,7 +3568,7 @@ void LLPipeline::renderDebug() } } } - } + }*/ } } @@ -3732,7 +3870,7 @@ void LLPipeline::rebuildPools() max_count--; } - if (gAgent.getAvatarObject()) + if (isAgentAvatarValid()) { gAgent.getAvatarObject()->rebuildHUD(); } @@ -4271,8 +4409,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) glLightfv(GL_LIGHT0, GL_AMBIENT, LLColor4::black.mV); glLightfv(GL_LIGHT0, GL_SPECULAR, LLColor4::black.mV); glLightf (GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f); - glLightf (GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0f); - glLightf (GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0f); glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 0.0f); glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 180.0f); } @@ -4337,9 +4473,34 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) glLightfv(gllight, GL_DIFFUSE, light_color.mV); glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV); glLightf (gllight, GL_CONSTANT_ATTENUATION, 0.0f); - glLightf (gllight, GL_LINEAR_ATTENUATION, linatten); - glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f); - //Point lights + if(sRenderDeferred) + { + glLightf (gllight, GL_LINEAR_ATTENUATION, light_radius*1.5f); + glLightf (gllight, GL_QUADRATIC_ATTENUATION, light->getLightFalloff()*0.5f+1.f); + } + else + { + glLightf (gllight, GL_LINEAR_ATTENUATION, linatten); + glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f); + } + + + static const LLCachedControl render_spot_lights_in_nondeferred("RenderSpotLightsInNondeferred",false); + if (light->isLightSpotlight() // directional (spot-)light + && (LLPipeline::sRenderDeferred || render_spot_lights_in_nondeferred)) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on + { + LLVector3 spotparams = light->getSpotLightParams(); + LLQuaternion quat = light->getRenderRotation(); + LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction + at_axis *= quat; + //llinfos << "SPOT!!!!!!! fov: " << spotparams.mV[0] << " focus: " << spotparams.mV[1] << " dir: " << at_axis << llendl; + glLightfv(gllight, GL_SPOT_DIRECTION, at_axis.mV); + glLightf (gllight, GL_SPOT_EXPONENT, 2.0f); // 2.0 = good old dot product ^ 2 + glLightf (gllight, GL_SPOT_CUTOFF, 90.0f); // hemisphere + const float specular[] = {0.f, 0.f, 0.f, 0.f}; + glLightfv(gllight, GL_SPECULAR, specular); + } + else // omnidirectional (point) light { glLightf (gllight, GL_SPOT_EXPONENT, 0.0f); glLightf (gllight, GL_SPOT_CUTOFF, 180.0f); @@ -5058,7 +5219,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, ++iter) { LLVOAvatar* av = (LLVOAvatar*) *iter; - if (av->mNameText.notNull() && av->mNameText->lineSegmentIntersect(start, local_end, position)) + if (av->mNameText.notNull() + && av->mNameText->lineSegmentIntersect(start, local_end, position)) { drawable = av->mDrawable; local_end = position; @@ -5325,7 +5487,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b if (res_mod > 1) { - tc2 /= (F32) res_mod; + tc2 /= (F32) res_mod.get(); } gGL.setColorMask(true, true); @@ -5411,8 +5573,8 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGlowExtractProgram.bind(); static const LLCachedControl minLum("RenderGlowMinLuminance",2.5); - static const LLCachedControl maxAlpha("RenderGlowMaxExtractAlpha",0.065f); - static const LLCachedControl warmthAmount("RenderGlowWarmthAmount",0.0f); + static const LLCachedControl maxAlpha("RenderGlowMaxExtractAlpha",0.065f); + static const LLCachedControl warmthAmount("RenderGlowWarmthAmount",0.0f); static const LLCachedControl lumWeights("RenderGlowLumWeights",LLVector3(.299f,.587f,.114f)); static const LLCachedControl warmthWeights("RenderGlowWarmthWeights",LLVector3(1.f,.5f,.7f)); gGlowExtractProgram.uniform1f("minLuminance", llmax(minLum.get(),0.0f)); @@ -5452,8 +5614,6 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b tc1.setVec(0,0); tc2.setVec(2,2); - - // power of two between 1 and 1024 static const LLCachedControl glowResPow("RenderGlowResolutionPow",9); const U32 glow_res = llmax(1, @@ -5504,7 +5664,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); gGL.vertex2f(-1,-1); - + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); gGL.vertex2f(-1,3); @@ -5526,15 +5686,40 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gViewerWindow->setupViewport(); + tc2.setVec((F32) gViewerWindow->getWindowDisplayWidth(), + (F32) gViewerWindow->getWindowDisplayHeight()); + gGL.flush(); - { - LLVertexBuffer::unbind(); + LLVertexBuffer::unbind(); + if (LLPipeline::sRenderDeferred && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + LLGLDisable blend(GL_BLEND); + bindDeferredShader(gDeferredGIFinalProgram); + + S32 channel = gDeferredGIFinalProgram.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mScreen.bindTexture(0, channel); + } + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1,-1); + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1,3); - tc2.setVec((F32) gViewerWindow->getWindowDisplayWidth(), - (F32) gViewerWindow->getWindowDisplayHeight()); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3,-1); + + gGL.end(); + + unbindDeferredShader(gDeferredGIFinalProgram); + } + else + { if (res_mod > 1) { @@ -5575,7 +5760,8 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGL.getTexUnit(0)->bind(&mGlow[1]); gGL.getTexUnit(1)->activate(); gGL.getTexUnit(1)->enable(LLTexUnit::TT_RECT_TEXTURE); - + + //tex unit 1 gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); @@ -5593,9 +5779,6 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - //TO-DO: - //V2 requires this for hover text and such since they have been pulled out of geom render. - //Do this when multisample z-buffer issues are figured out if (LLRenderTarget::sUseFBO) { //copy depth buffer from mScreen to framebuffer LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), @@ -5617,8 +5800,17 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b } -void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index) +void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRenderTarget* gi_source, LLRenderTarget* last_gi_post, U32 noise_map) { + //LLFastTimer t(FTM_BIND_DEFERRED); + + if (noise_map == 0xFFFFFFFF) + { + noise_map = mNoiseMap; + } + + LLGLState::checkTextureChannels(); + shader.bind(); S32 channel = 0; channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE); @@ -5626,7 +5818,6 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index) { mDeferredScreen.bindTexture(0,channel); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE); @@ -5643,26 +5834,164 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index) gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } - channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE); + if (gi_source) + { + BOOL has_gi = FALSE; + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(1, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(2, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(1, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS); + if (channel > -1) + { + has_gi = TRUE; + gi_source->bindTexture(3, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE); + if (channel > -1) + { + has_gi = TRUE; + last_gi_post->bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL); + if (channel > -1) + { + has_gi = TRUE; + last_gi_post->bindTexture(2, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS); + if (channel > -1) + { + has_gi = TRUE; + last_gi_post->bindTexture(1, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS); + if (channel > -1) + { + has_gi = TRUE; + last_gi_post->bindTexture(3, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH); + if (channel > -1) + { + has_gi = TRUE; + gGL.getTexUnit(channel)->bind(gi_source, TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + stop_glerror(); + + glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); + + stop_glerror(); + } + + if (has_gi) + { + F32 range_x = llmin(mGIRange.mV[0], 1.f); + F32 range_y = llmin(mGIRange.mV[1], 1.f); + + LLVector2 scale(range_x,range_y); + + LLVector2 kern[25]; + + for (S32 i = 0; i < 5; ++i) + { + for (S32 j = 0; j < 5; ++j) + { + S32 idx = i*5+j; + kern[idx].mV[0] = (i-2)*0.5f; + kern[idx].mV[1] = (j-2)*0.5f; + kern[idx].scaleVec(scale); + } + } + + shader.uniform2fv("gi_kern", 25, (F32*) kern); + shader.uniformMatrix4fv("gi_mat", 1, FALSE, mGIMatrix.m); + shader.uniformMatrix4fv("gi_mat_proj", 1, FALSE, mGIMatrixProj.m); + shader.uniformMatrix4fv("gi_inv_proj", 1, FALSE, mGIInvProj.m); + shader.uniformMatrix4fv("gi_norm_mat", 1, FALSE, mGINormalMatrix.m); + } + } + + /*channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE); if (channel > -1) { mDeferredScreen.bindTexture(3, channel); - } + }*/ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE); if (channel > -1) { - gGL.getTexUnit(channel)->bind(&mDeferredScreen, TRUE); + gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + stop_glerror(); + + glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); + + stop_glerror(); + + glh::matrix4f projection = glh_get_current_projection(); + glh::matrix4f inv_proj = projection.inverse(); + + shader.uniformMatrix4fv("inv_proj", 1, FALSE, inv_proj.m); + shader.uniform4f("viewport", (F32) gGLViewport[0], + (F32) gGLViewport[1], + (F32) gGLViewport[2], + (F32) gGLViewport[3]); } channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE); if (channel > -1) { - gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap); + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC); + if (channel > -1) + { + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); + } + stop_glerror(); channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE); @@ -5672,16 +6001,76 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index) gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE); + if (channel > -1) + { + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_BLOOM); + if (channel > -1) + { + mGlow[1].bindTexture(0, channel); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + gi_source->bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mEdgeMap.bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mDeferredLight[1].bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + if (channel > -1) + { + mDeferredLight[2].bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + stop_glerror(); for (U32 i = 0; i < 4; i++) + { + channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE); + stop_glerror(); + if (channel > -1) + { + stop_glerror(); + gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); + + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + stop_glerror(); + } + } + + for (U32 i = 4; i < 6; i++) { channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i); stop_glerror(); if (channel > -1) { stop_glerror(); - gGL.getTexUnit(channel)->bind(&mSunShadow[i], TRUE); + gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); stop_glerror(); @@ -5694,17 +6083,19 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index) stop_glerror(); - F32 mat[64]; + F32 mat[16*6]; for (U32 i = 0; i < 16; i++) { mat[i] = mSunShadowMatrix[0].m[i]; mat[i+16] = mSunShadowMatrix[1].m[i]; mat[i+32] = mSunShadowMatrix[2].m[i]; mat[i+48] = mSunShadowMatrix[3].m[i]; + mat[i+64] = mSunShadowMatrix[4].m[i]; + mat[i+80] = mSunShadowMatrix[5].m[i]; } - shader.uniformMatrix4fv("shadow_matrix[0]", 4, FALSE, mat); - shader.uniformMatrix4fv("shadow_matrix", 4, FALSE, mat); + shader.uniformMatrix4fv("shadow_matrix[0]", 6, FALSE, mat); + shader.uniformMatrix4fv("shadow_matrix", 6, FALSE, mat); stop_glerror(); @@ -5733,11 +6124,33 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index) static const LLCachedControl render_shadow_noise("RenderShadowNoise",-.0001f); static const LLCachedControl render_shadow_blur_size("RenderShadowBlurSize",.7f); static const LLCachedControl render_ssao_scale("RenderSSAOScale",500); - static const LLCachedControl render_ssao_max_scale("RenderSSAOMaxScale",60); + static const LLCachedControl render_ssao_max_scale("RenderSSAOMaxScale",200); static const LLCachedControl render_ssao_factor("RenderSSAOFactor",.3f); - static const LLCachedControl render_ssao_effect("RenderSSAOEffect",LLVector3(.4f,1,0)); + static const LLCachedControl render_ssao_effect("RenderSSAOEffect",LLVector3(.4f,1.f,0.f)); static const LLCachedControl render_deferred_alpha_soft("RenderDeferredAlphaSoften",.75f); - + static const LLCachedControl render_shadow_offset_error("RenderShadowOffsetError",0.f); + static const LLCachedControl render_shadow_bias_error("RenderShadowBiasError",0.f); + static const LLCachedControl render_shadow_offset("RenderShadowOffset",.1f); + static const LLCachedControl render_shadow_bias("RenderShadowBias",0.f); + static const LLCachedControl render_spot_shadow_offset("RenderSpotShadowOffset",.4f); + static const LLCachedControl render_spot_shadow_bias("RenderSpotShadowBias",0.f); + + static const LLCachedControl render_luminance_scale("RenderLuminanceScale",1.f); + static const LLCachedControl render_sun_luminance_scale("RenderSunLuminanceScale",1.f); + static const LLCachedControl render_sun_luminance_offset("RenderSunLuminanceOffset",0.f); + static const LLCachedControl render_luminance_detail("RenderLuminanceDetail",16.f); + static const LLCachedControl render_gi_range("RenderGIRange",96.f); + static const LLCachedControl render_gi_brightness("RenderGIBrightness",.3f); + static const LLCachedControl render_gi_luminance("RenderGILuminance",.075f); + static const LLCachedControl render_gi_blur_edge_weight("RenderGIBlurEdgeWeight",.8f); + static const LLCachedControl render_gi_blur_brightness("RenderGIBlurBrightness",1.025f); + static const LLCachedControl render_gi_render_gi_noise("RenderGINoise",.7); + static const LLCachedControl render_gi_attenuation("RenderGIAttenuation",.1f); + static const LLCachedControl render_gi_ambiance("RenderGIAmbiance",.5f); + static const LLCachedControl render_edge_depth_cutoff("RenderEdgeDepthCutoff",.01f); + static const LLCachedControl render_edge_norm_cutoff("RenderEdgeNormCutoff",.25f); + + shader.uniform1f("sun_wash", render_deferred_sun_wash); shader.uniform1f("shadow_noise", render_shadow_noise); shader.uniform1f("blur_size", render_shadow_blur_size); @@ -5759,9 +6172,34 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index) matrix_nondiag, matrix_nondiag, matrix_diag}; shader.uniformMatrix3fv("ssao_effect_mat", 1, GL_FALSE, ssao_effect_mat); + F32 shadow_offset_error = 1.f + render_shadow_offset_error * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); + F32 shadow_bias_error = 1.f + render_shadow_bias_error * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); + shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f); - shader.uniform1f("alpha_soften", render_deferred_alpha_soft); + shader.uniform1f ("shadow_offset", render_shadow_offset*shadow_offset_error); + shader.uniform1f("shadow_bias", render_shadow_bias*shadow_bias_error); + shader.uniform1f ("spot_shadow_offset", render_spot_shadow_offset); + shader.uniform1f("spot_shadow_bias", render_spot_shadow_bias); + + shader.uniform1f("lum_scale", render_luminance_scale); + shader.uniform1f("sun_lum_scale", render_sun_luminance_scale); + shader.uniform1f("sun_lum_offset", render_sun_luminance_offset); + shader.uniform1f("lum_lod", render_luminance_detail); + shader.uniform1f("gi_range", render_gi_range); + shader.uniform1f("gi_brightness", render_gi_brightness); + shader.uniform1f("gi_luminance", render_gi_luminance); + shader.uniform1f("gi_edge_weight", render_gi_blur_edge_weight); + shader.uniform1f("gi_blur_brightness", render_gi_blur_brightness); + shader.uniform1f("gi_sample_width", mGILightRadius); + shader.uniform1f("gi_noise", render_gi_render_gi_noise); + shader.uniform1f("gi_attenuation", render_gi_attenuation); + shader.uniform1f("gi_ambiance", render_gi_ambiance); + shader.uniform2f("shadow_res", mShadow[0].getWidth(), mShadow[0].getHeight()); + shader.uniform2f("proj_shadow_res", mShadow[4].getWidth(), mShadow[4].getHeight()); + shader.uniform1f("depth_cutoff", render_edge_depth_cutoff); + shader.uniform1f("norm_cutoff", render_edge_norm_cutoff); + if (shader.getUniformLocation("norm_mat") >= 0) { glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose(); @@ -5776,131 +6214,245 @@ void LLPipeline::renderDeferredLighting() return; } - LLViewerCamera* camera = LLViewerCamera::getInstance(); - /*{ + { + + LLViewerCamera* camera = LLViewerCamera::getInstance(); + { LLGLDepthTest depth(GL_TRUE); mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); - }*/ + } - LLGLEnable multisample(GL_MULTISAMPLE_ARB); + LLGLEnable multisample(GL_MULTISAMPLE_ARB); - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); - } - - //ati doesn't seem to love actually using the stencil buffer on FBO's - LLGLEnable stencil(GL_STENCIL_TEST); - glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - - gGL.setColorMask(true, true); - - //mDeferredLight[0].copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), - // 0, 0, mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - - //draw a cube around every light - LLVertexBuffer::unbind(); - - //glBlendFunc(GL_ONE, GL_ONE); - LLGLEnable cull(GL_CULL_FACE); - LLGLEnable blend(GL_BLEND); - - glh::matrix4f mat = glh_copy_matrix(gGLModelView); - - F32 vert[] = - { - -1,1, - -1,-3, - 3,1, - }; - glVertexPointer(2, GL_FLOAT, 0, vert); - glColor3f(1,1,1); - - { - setupHWLights(NULL); //to set mSunDir; - LLVector4 dir(mSunDir, 0.f); - glh::vec4f tc(dir.mV); - mat.mult_matrix_vec(tc); - glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0); - } - - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - mDeferredLight[0].bindTarget(); - - //Sun shadows. - { - bindDeferredShader(gDeferredSunProgram); - - glClearColor(1,1,1,1); - mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT); - glClearColor(0,0,0,0); - - glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); - - const U32 slice = 32; - F32 offset[slice*3]; - for (U32 i = 0; i < 4; i++) + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) { - for (U32 j = 0; j < 8; j++) + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } + + //ati doesn't seem to love actually using the stencil buffer on FBO's + LLGLEnable stencil(GL_STENCIL_TEST); + glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + gGL.setColorMask(true, true); + + //draw a cube around every light + LLVertexBuffer::unbind(); + + LLGLEnable cull(GL_CULL_FACE); + LLGLEnable blend(GL_BLEND); + + glh::matrix4f mat = glh_copy_matrix(gGLModelView); + + F32 vert[] = + { + -1,1, + -1,-3, + 3,1, + }; + glVertexPointer(2, GL_FLOAT, 0, vert); + glColor3f(1,1,1); + + { + setupHWLights(NULL); //to set mSunDir; + LLVector4 dir(mSunDir, 0.f); + glh::vec4f tc(dir.mV); + mat.mult_matrix_vec(tc); + glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0); + } + + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + mDeferredLight[0].bindTarget(); + + static const LLCachedControl render_deferred_ssao("RenderDeferredSSAO",false); + static const LLCachedControl render_shadow_detail("RenderShadowDetail",0); + if (render_deferred_ssao || render_shadow_detail > 0) + { + { //paint shadow/SSAO light map (direct lighting lightmap) + //LLFastTimer ftm(FTM_SUN_SHADOW); + bindDeferredShader(gDeferredSunProgram, 0); + + glClearColor(1,1,1,1); + mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + + glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); + + const U32 slice = 32; + F32 offset[slice*3]; + for (U32 i = 0; i < 4; i++) + { + for (U32 j = 0; j < 8; j++) + { + glh::vec3f v; + v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i); + v.normalize(); + inv_trans.mult_matrix_vec(v); + v.normalize(); + offset[(i*8+j)*3+0] = v.v[0]; + offset[(i*8+j)*3+1] = v.v[2]; + offset[(i*8+j)*3+2] = v.v[1]; + } + } + + gDeferredSunProgram.uniform3fv("offset", slice, offset); + gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight()); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + stop_glerror(); + } + + unbindDeferredShader(gDeferredSunProgram); + } + } + else { - glh::vec3f v; - v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i); - v.normalize(); - inv_trans.mult_matrix_vec(v); - v.normalize(); - offset[(i*8+j)*3+0] = v.v[0]; - offset[(i*8+j)*3+1] = v.v[2]; - offset[(i*8+j)*3+2] = v.v[1]; + glClearColor(1,1,1,1); + mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + } + + mDeferredLight[0].flush(); + + static const LLCachedControl render_deferred_blur_light("RenderDeferredBlurLight",false); + static const LLCachedControl render_shadow_gi("RenderDeferredGI",false); + { //global illumination specific block (still experimental) + if (render_deferred_blur_light && + render_shadow_gi) + { + //LLFastTimer ftm(FTM_EDGE_DETECTION); + //generate edge map + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable stencil(GL_STENCIL_TEST); + + { + gDeferredEdgeProgram.bind(); + mEdgeMap.bindTarget(); + bindDeferredShader(gDeferredEdgeProgram); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + unbindDeferredShader(gDeferredEdgeProgram); + mEdgeMap.flush(); + } + } + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + { //get luminance map from previous frame's light map + LLGLEnable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable stencil(GL_STENCIL_TEST); + + //static F32 fade = 1.f; + + { + gGL.setSceneBlendType(LLRender::BT_ALPHA); + gLuminanceGatherProgram.bind(); + gLuminanceGatherProgram.uniform2f("screen_res", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight()); + mLuminanceMap.bindTarget(); + bindDeferredShader(gLuminanceGatherProgram); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + unbindDeferredShader(gLuminanceGatherProgram); + mLuminanceMap.flush(); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); + glGenerateMipmapEXT(GL_TEXTURE_2D); + } + } + + { //paint noisy GI map (bounce lighting lightmap) + //LLFastTimer ftm(FTM_GI_TRACE); + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable test(GL_ALPHA_TEST); + + mGIMapPost[0].bindTarget(); + + bindDeferredShader(gDeferredGIProgram, 0, &mGIMap, 0, mTrueNoiseMap); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + unbindDeferredShader(gDeferredGIProgram); + mGIMapPost[0].flush(); + } + + U32 pass_count = 0; + if (render_deferred_blur_light) + { + static const LLCachedControl render_gui_blur_passes("RenderGIBlurPasses",(U32)1); + pass_count = llclamp(render_gui_blur_passes.get(), (U32) 1, (U32) 128); + } + + static const LLCachedControl render_gui_blur_size("RenderGIBlurSize",4.f); + static const LLCachedControl render_gui_blur_increment("RenderGIBlurIncrement",.8f); + static const LLCachedControl render_gui_blur_brightness("RenderGIBlurBrightness",1.025f); + for (U32 i = 0; i < pass_count; ++i) + { //gather/soften indirect lighting map + //LLFastTimer ftm(FTM_GI_GATHER); + bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[0], NULL, mTrueNoiseMap); + F32 blur_size = render_gui_blur_size/((F32) i * render_gui_blur_increment+1.f); + gDeferredPostGIProgram.uniform2f("delta", 1.f, 0.f); + gDeferredPostGIProgram.uniform1f("kern_scale", blur_size); + gDeferredPostGIProgram.uniform1f("gi_blur_brightness", render_gui_blur_brightness); + + mGIMapPost[1].bindTarget(); + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_FALSE); + stop_glerror(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + stop_glerror(); + } + + mGIMapPost[1].flush(); + unbindDeferredShader(gDeferredPostGIProgram); + bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[1], NULL, mTrueNoiseMap); + mGIMapPost[0].bindTarget(); + + gDeferredPostGIProgram.uniform2f("delta", 0.f, 1.f); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_FALSE); + stop_glerror(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + stop_glerror(); + } + mGIMapPost[0].flush(); + unbindDeferredShader(gDeferredPostGIProgram); + } } } - gDeferredSunProgram.uniform3fv("offset", slice, offset); - gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight()); + if(render_deferred_ssao) + { //soften direct lighting lightmap + //LLFastTimer ftm(FTM_SOFTEN_SHADOW); + //blur lightmap + mDeferredLight[1].bindTarget(); - { - LLGLDisable blend(GL_BLEND); - //TO-DO: - //V2 changed to LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - //Do this when multisample z-buffer issues are figured out - //LLGLDepthTest depth(GL_FALSE); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - stop_glerror(); - } - - unbindDeferredShader(gDeferredSunProgram); - } - - mDeferredLight[0].flush(); - - //SSAO - { - //blur lightmap - mDeferredLight[1].bindTarget(); - - //mDeferredLight[1].copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), - // 0, 0, mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - glClearColor(1,1,1,1); - mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT); + glClearColor(1,1,1,1); + mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT); glClearColor(0,0,0,0); bindDeferredShader(gDeferredBlurLightProgram); - static const LLCachedControl go("RenderShadowGaussian",LLVector3(2.f,2.f,0.f)); - static const LLCachedControl blur_size("RenderShadowBlurSize",.7f); - static const LLCachedControl blur_samples("RenderShadowBlurSamples",(U32)5); - U32 kern_length = llclamp(blur_samples.get(), (U32) 1, (U32) 16)*2 - 1; + static const LLCachedControl go("RenderShadowGaussian",LLVector3(3.f,2.f,0.f)); + const U32 kern_length = 4; + static const LLCachedControl blur_size("RenderShadowBlurSize",1.4f); + static const LLCachedControl shadow_blur_dist_factor("RenderShadowBlurDistFactor",.1f); // sample symmetrically with the middle sample falling exactly on 0.0 - F32 x = -(kern_length/2.0f) + 0.5f; + F32 x = 0.f; LLVector3 gauss[32]; // xweight, yweight, offset @@ -5911,26 +6463,15 @@ void LLPipeline::renderDeferredLighting() gauss[i].mV[2] = x; x += 1.f; } - /* swap the x=0 position to the start of gauss[] so we can - treat it specially as an optimization. */ - LLVector3 swap; - swap = gauss[kern_length/2]; - gauss[kern_length/2] = gauss[0]; - gauss[0] = swap; - llassert(gauss[0].mV[2] == 0.0f); gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f); + gDeferredBlurLightProgram.uniform1f("dist_factor", shadow_blur_dist_factor); gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV); gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV); - gDeferredBlurLightProgram.uniform1i("kern_length", kern_length); gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f)); { LLGLDisable blend(GL_BLEND); - //TO-DO: - //V2 changed to LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - //Do this when multisample z-buffer issues are figured out - //LLGLDepthTest depth(GL_FALSE); LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); stop_glerror(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); @@ -5947,13 +6488,9 @@ void LLPipeline::renderDeferredLighting() { LLGLDisable blend(GL_BLEND); - //TO-DO: - //V2 changed to LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - //Do this when multisample z-buffer issues are figured out - //LLGLDepthTest depth(GL_FALSE); LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); stop_glerror(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); stop_glerror(); } mDeferredLight[0].flush(); @@ -5972,12 +6509,26 @@ void LLPipeline::renderDeferredLighting() //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - mScreen.bindTarget(); - // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky - glClearColor(0,0,0,0); - mScreen.clear(GL_COLOR_BUFFER_BIT); - - bindDeferredShader(gDeferredSoftenProgram); + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + mDeferredLight[1].bindTarget(); + // clear color buffer here (GI) - zeroing alpha (glow) is important or it will accumulate against sky + glClearColor(0,0,0,0); + mScreen.clear(GL_COLOR_BUFFER_BIT); + } + else + { + mScreen.bindTarget(); + // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky + glClearColor(0,0,0,0); + mScreen.clear(GL_COLOR_BUFFER_BIT); + } + + static const LLCachedControl render_deferred_atmospheric("RenderDeferredAtmospheric",false); + if (render_deferred_atmospheric) + { //apply sunlight contribution + //LLFastTimer ftm(FTM_ATMOSPHERICS); + bindDeferredShader(gDeferredSoftenProgram, 0, &mGIMapPost[0]); { LLGLDepthTest depth(GL_FALSE); LLGLDisable blend(GL_BLEND); @@ -5993,14 +6544,14 @@ void LLPipeline::renderDeferredLighting() glVertexPointer(2, GL_FLOAT, 0, vert); glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - + glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } unbindDeferredShader(gDeferredSoftenProgram); - + } { //render sky LLGLDisable blend(GL_BLEND); @@ -6008,7 +6559,7 @@ void LLPipeline::renderDeferredLighting() gGL.setSceneBlendType(LLRender::BT_ALPHA); gPipeline.pushRenderTypeMask(); - + gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_CLOUDS, LLPipeline::RENDER_TYPE_WL_SKY, @@ -6019,12 +6570,33 @@ void LLPipeline::renderDeferredLighting() gPipeline.popRenderTypeMask(); } - gGL.setSceneBlendType(LLRender::BT_ADD); - std::list fullscreen_lights; + static const LLCachedControl render_local("RenderDeferredLocalLights",false); + static const LLCachedControl render_fullscreen("RenderDeferredFullscreenLights",false); + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + mDeferredLight[1].flush(); + mDeferredLight[2].bindTarget(); + mDeferredLight[2].clear(GL_COLOR_BUFFER_BIT); + } + + if (render_local || render_fullscreen) + { + gGL.setSceneBlendType(LLRender::BT_ADD); + std::list fullscreen_lights; + LLDrawable::drawable_list_t spot_lights; + LLDrawable::drawable_list_t fullscreen_spot_lights; + + for (U32 i = 0; i < 2; i++) + { + mTargetShadowSpotLight[i] = NULL; + } + std::list light_colors; F32 v[24]; glVertexPointer(3, GL_FLOAT, 0, v); + static const LLCachedControl render_local("RenderDeferredLocalLights",false); { bindDeferredShader(gDeferredLightProgram); LLGLDepthTest depth(GL_TRUE, GL_FALSE); @@ -6073,7 +6645,7 @@ void LLPipeline::renderDeferredLighting() glh::vec3f tc(c); mat.mult_matrix_vec(tc); - + //vertex positions are encoded so the 3 bits of their vertex index //correspond to their axis facing, with bit position 3,2,1 matching //axis facing x,y,z, bit set meaning positive facing, bit clear @@ -6082,7 +6654,7 @@ void LLPipeline::renderDeferredLighting() v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001 v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010 v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011 - + v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100 v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101 v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110 @@ -6095,25 +6667,91 @@ void LLPipeline::renderDeferredLighting() camera->getOrigin().mV[2] > c[2] + s + 0.2f || camera->getOrigin().mV[2] < c[2] - s - 0.2f) { //draw box if camera is outside box - glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); - glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); - glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, - GL_UNSIGNED_BYTE, get_box_fan_indices(camera, center)); + if (render_local) + { + if (volume->isLightSpotlight()) + { + drawablep->getVOVolume()->updateSpotLightPriority(); + spot_lights.push_back(drawablep); + continue; + } + + glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); + glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); + glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, + GL_UNSIGNED_BYTE, get_box_fan_indices(camera, center)); + } } - else + else if (render_fullscreen) { + if (volume->isLightSpotlight()) + { + drawablep->getVOVolume()->updateSpotLightPriority(); + fullscreen_spot_lights.push_back(drawablep); + continue; + } + fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s)); light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); } } unbindDeferredShader(gDeferredLightProgram); - } + } + if (!spot_lights.empty()) + { + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + bindDeferredShader(gDeferredSpotLightProgram); + gDeferredSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + + for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) + { + //LLFastTimer ftm(FTM_PROJECTORS); + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + + LLVector3 center = drawablep->getPositionAgent(); + F32* c = center.mV; + F32 s = volume->getLightRadius()*1.5f; + + sVisibleLightCount++; + + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + + setupSpotLight(gDeferredSpotLightProgram, drawablep); + + LLColor3 col = volume->getLightColor(); + col *= volume->getLightIntensity(); + + //vertex positions are encoded so the 3 bits of their vertex index + //correspond to their axis facing, with bit position 3,2,1 matching + //axis facing x,y,z, bit set meaning positive facing, bit clear + //meaning negative facing + v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000 + v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001 + v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010 + v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011 + + v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100 + v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101 + v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110 + v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111 + + glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); + glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); + glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, + GL_UNSIGNED_BYTE, get_box_fan_indices(camera, center)); + } + gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredSpotLightProgram); + } + + { + bindDeferredShader(gDeferredMultiLightProgram); - if (!fullscreen_lights.empty()) - { - bindDeferredShader(gDeferredMultiLightProgram); LLGLDepthTest depth(GL_FALSE); //full screen blit @@ -6125,20 +6763,24 @@ void LLPipeline::renderDeferredLighting() U32 count = 0; - const U32 max_count = 16; - LLVector4 light[max_count]; - LLVector4 col[max_count]; + const U32 max_count = 8; + LLVector4 light[max_count]; + LLVector4 col[max_count]; glVertexPointer(2, GL_FLOAT, 0, vert); + F32 far_z = 0.f; + while (!fullscreen_lights.empty()) { light[count] = fullscreen_lights.front(); fullscreen_lights.pop_front(); col[count] = light_colors.front(); light_colors.pop_front(); - count++; + far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z); + + count++; if (count == max_count || fullscreen_lights.empty()) { gDeferredMultiLightProgram.uniform1i("light_count", count); @@ -6146,20 +6788,98 @@ void LLPipeline::renderDeferredLighting() gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light); gDeferredMultiLightProgram.uniform4fv("light_col[0]", count, (GLfloat*) col); gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col); + gDeferredMultiLightProgram.uniform1f("far_z", far_z); + far_z = 0.f; count = 0; - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + } + } + unbindDeferredShader(gDeferredMultiLightProgram); + + bindDeferredShader(gDeferredMultiSpotLightProgram); + + gDeferredMultiSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + + for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) + { + //LLFastTimer ftm(FTM_PROJECTORS); + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + + LLVector3 center = drawablep->getPositionAgent(); + F32* c = center.mV; + F32 s = volume->getLightRadius()*1.5f; + + sVisibleLightCount++; + + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + + setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); + + LLColor3 col = volume->getLightColor(); + col *= volume->getLightIntensity(); + + glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); + glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + } + + gDeferredMultiSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredMultiSpotLightProgram); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); } } + + gGL.setColorMask(true, true); + + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2) + { + mDeferredLight[2].flush(); + + mScreen.bindTarget(); + mScreen.clear(GL_COLOR_BUFFER_BIT); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); - unbindDeferredShader(gDeferredMultiLightProgram); + { //mix various light maps (local, sun, gi) + //LLFastTimer ftm(FTM_POST); + LLGLDisable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable stencil(GL_STENCIL_TEST); + + bindDeferredShader(gDeferredPostProgram, 0, &mGIMapPost[0]); + + gDeferredPostProgram.bind(); + + LLVertexBuffer::unbind(); + + glVertexPointer(2, GL_FLOAT, 0, vert); + glColor3f(1,1,1); + + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + unbindDeferredShader(gDeferredPostProgram); + } + } } - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - { //render non-deferred geometry + { //render non-deferred geometry (alpha, fullbright, glow) LLGLDisable blend(GL_BLEND); LLGLDisable stencil(GL_STENCIL_TEST); @@ -6189,9 +6909,6 @@ void LLPipeline::renderDeferredLighting() popRenderTypeMask(); } - //TO-DO: - //V2 moved block from LLPipeline::renderGeomPostDeferred - //Migrate once multisample z-buffer issues are figured out on ati cards. { //render highlights, etc. renderHighlights(); @@ -6213,6 +6930,136 @@ void LLPipeline::renderDeferredLighting() } +void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) +{ + //construct frustum + LLVOVolume* volume = drawablep->getVOVolume(); + LLVector3 params = volume->getSpotLightParams(); + + F32 fov = params.mV[0]; + F32 focus = params.mV[1]; + + LLVector3 pos = drawablep->getPositionAgent(); + LLQuaternion quat = volume->getRenderRotation(); + LLVector3 scale = volume->getScale(); + + //get near clip plane + LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); + at_axis *= quat; + + LLVector3 np = pos+at_axis; + at_axis.normVec(); + + //get origin that has given fov for plane np, at_axis, and given scale + F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); + + LLVector3 origin = np - at_axis*dist; + + //matrix from volume space to agent space + LLMatrix4 light_mat(quat, LLVector4(origin,1.f)); + + glh::matrix4f light_to_agent((F32*) light_mat.mMatrix); + glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent; + + glh::matrix4f screen_to_light = light_to_screen.inverse(); + + F32 s = volume->getLightRadius()*1.5f; + F32 near_clip = dist; + F32 width = scale.mV[VX]; + F32 height = scale.mV[VY]; + F32 far_clip = s+dist-scale.mV[VZ]; + + F32 fovy = fov * RAD_TO_DEG; + F32 aspect = width/height; + + glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); + + glh::vec3f p1(0, 0, -(near_clip+0.01f)); + glh::vec3f p2(0, 0, -(near_clip+1.f)); + + glh::vec3f screen_origin(0, 0, 0); + + light_to_screen.mult_matrix_vec(p1); + light_to_screen.mult_matrix_vec(p2); + light_to_screen.mult_matrix_vec(screen_origin); + + glh::vec3f n = p2-p1; + n.normalize(); + + F32 proj_range = far_clip - near_clip; + glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip); + screen_to_light = trans * light_proj * screen_to_light; + shader.uniformMatrix4fv("proj_mat", 1, FALSE, screen_to_light.m); + shader.uniform1f("proj_near", near_clip); + shader.uniform3fv("proj_p", 1, p1.v); + shader.uniform3fv("proj_n", 1, n.v); + shader.uniform3fv("proj_origin", 1, screen_origin.v); + shader.uniform1f("proj_range", proj_range); + shader.uniform1f("proj_ambiance", params.mV[2]); + S32 s_idx = -1; + + for (U32 i = 0; i < 2; i++) + { + if (mShadowSpotLight[i] == drawablep) + { + s_idx = i; + } + } + + shader.uniform1i("proj_shadow_idx", s_idx); + + if (s_idx >= 0) + { + shader.uniform1f("shadow_fade", 1.f-mSpotLightFade[s_idx]); + } + else + { + shader.uniform1f("shadow_fade", 1.f); + } + + { + LLDrawable* potential = drawablep; + //determine if this is a good light for casting shadows + F32 m_pri = volume->getSpotLightPriority(); + + for (U32 i = 0; i < 2; i++) + { + F32 pri = 0.f; + + if (mTargetShadowSpotLight[i].notNull()) + { + pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority(); + } + + if (m_pri > pri) + { + LLDrawable* temp = mTargetShadowSpotLight[i]; + mTargetShadowSpotLight[i] = potential; + potential = temp; + m_pri = pri; + } + } + } + + LLViewerTexture* img = volume->getLightTexture(); + + S32 channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION); + + if (channel > -1 && img) + { + gGL.getTexUnit(channel)->bind(img); + + F32 lod_range = logf(img->getWidth())/logf(2.f); + + shader.uniform1f("proj_focus", focus); + shader.uniform1f("proj_lod", lod_range); + shader.uniform1f("proj_ambient_lod", llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f)); + } +} + void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) { stop_glerror(); @@ -6222,14 +7069,43 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) shader.disableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE); shader.disableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE); shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE); + shader.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIP); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_BLOOM); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS); + for (U32 i = 0; i < 4; i++) + { + if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1) + { + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + } + } + + for (U32 i = 4; i < 6; i++) { if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i) > -1) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); } } + shader.disableTexture(LLViewerShaderMgr::DEFERRED_NOISE); + shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC); S32 channel = shader.disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); if (channel > -1) @@ -6243,6 +7119,8 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(0)->activate(); shader.unbind(); + + LLGLState::checkTextureChannels(); } inline float sgn(float a) @@ -6372,53 +7250,45 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) gPipeline.popRenderTypeMask(); } - - static const LLCachedControl water_reflections("RenderWaterReflections",false); - if (water_reflections) + static const LLCachedControl detail("RenderReflectionDetail",0); + if (detail > 0) { //mask out selected geometry based on reflection detail - static const LLCachedControl detail("RenderReflectionDetail",0); - //if (detail > 0) - { //mask out selected geometry based on reflection detail + gPipeline.pushRenderTypeMask(); + if (detail < 4) + { + clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); + if (detail < 3) { - gPipeline.pushRenderTypeMask(); - if (detail < 3) + clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); + if (detail < 2) { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); - if (detail < 2) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); - if (detail < 1) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); - } - } + clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); } - - clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_GROUND, - LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, - LLPipeline::RENDER_TYPE_WL_CLOUDS, - LLPipeline::END_RENDER_TYPES); - static const LLCachedControl skip_distortion_updates("SkipReflectOcclusionUpdates",false); - LLPipeline::sSkipUpdate = skip_distortion_updates; - LLGLUserClipPlane clip_plane(plane, mat, projection); - LLGLDisable cull(GL_CULL_FACE); - updateCull(camera, ref_result, 1); - stateSort(camera, ref_result); - gPipeline.grabReferences(ref_result); - renderGeom(camera); - LLPipeline::sSkipUpdate = FALSE; - gPipeline.popRenderTypeMask(); } - } + } + + clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_GROUND, + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, + LLPipeline::RENDER_TYPE_WL_CLOUDS, + LLPipeline::END_RENDER_TYPES); + static const LLCachedControl skip_distortion_updates("SkipReflectOcclusionUpdates",false); + LLPipeline::sSkipUpdate = skip_distortion_updates; + LLGLUserClipPlane clip_plane(plane, mat, projection); + LLGLDisable cull(GL_CULL_FACE); + updateCull(camera, ref_result, 1); + stateSort(camera, ref_result); + gPipeline.grabReferences(ref_result); + renderGeom(camera); + LLPipeline::sSkipUpdate = FALSE; + gPipeline.popRenderTypeMask(); } - } + } glCullFace(GL_BACK); glPopMatrix(); mWaterRef.flush(); - glh_set_current_modelview(current); } @@ -6569,31 +7439,479 @@ glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max) return ret; } -void LLPipeline::generateSunShadow(LLCamera& camera) +void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion) { - if (!sRenderDeferred) + LLFastTimer t(LLFastTimer::FTM_SHADOW_RENDER); + + //clip out geometry on the same side of water as the camera + S32 occlude = LLPipeline::sUseOcclusion; + if (!use_occlusion) + { + LLPipeline::sUseOcclusion = 0; + } + LLPipeline::sShadowRender = TRUE; + + U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, LLRenderPass::PASS_FULLBRIGHT_SHINY }; + LLGLEnable cull(GL_CULL_FACE); + + if (use_shader) + { + gDeferredShadowProgram.bind(); + } + + updateCull(shadow_cam, result); + stateSort(shadow_cam, result); + + //generate shadow map + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixf(proj.m); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixf(view.m); + + stop_glerror(); + gGLLastMatrix = NULL; + + { + LLGLDepthTest depth(GL_TRUE); + glClear(GL_DEPTH_BUFFER_BIT); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + glColor4f(1,1,1,1); + + stop_glerror(); + + gGL.setColorMask(false, false); + + //glCullFace(GL_FRONT); + + { + //LLFastTimer ftm(FTM_SHADOW_SIMPLE); + LLGLDisable test(GL_ALPHA_TEST); + gGL.getTexUnit(0)->disable(); + for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) + { + renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); + } + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + } + + if (use_shader) + { + gDeferredShadowProgram.unbind(); + renderGeomShadow(shadow_cam); + gDeferredShadowProgram.bind(); + } + else + { + renderGeomShadow(shadow_cam); + } + + { + //LLFastTimer ftm(FTM_SHADOW_ALPHA); + LLGLEnable test(GL_ALPHA_TEST); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f); + renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE); + glColor4f(1,1,1,1); + renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + } + + //glCullFace(GL_BACK); + + gGLLastMatrix = NULL; + glLoadMatrixd(gGLModelView); + doOcclusion(shadow_cam); + + if (use_shader) + { + gDeferredShadowProgram.unbind(); + } + + gGL.setColorMask(true, true); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + gGLLastMatrix = NULL; + + LLPipeline::sUseOcclusion = occlude; + LLPipeline::sShadowRender = FALSE; +} + +BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector& fp, LLVector3 light_dir) +{ + //LLFastTimer t(FTM_VISIBLE_CLOUD); + //get point cloud of intersection of frust and min, max + + if (getVisibleExtents(camera, min, max)) + { + return FALSE; + } + + //get set of planes on bounding box + std::vector bp; + + bp.push_back(LLPlane(min, LLVector3(-1,0,0))); + bp.push_back(LLPlane(min, LLVector3(0,-1,0))); + bp.push_back(LLPlane(min, LLVector3(0,0,-1))); + bp.push_back(LLPlane(max, LLVector3(1,0,0))); + bp.push_back(LLPlane(max, LLVector3(0,1,0))); + bp.push_back(LLPlane(max, LLVector3(0,0,1))); + + //potential points + std::vector pp; + + //add corners of AABB + pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2])); + pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2])); + pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2])); + pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2])); + pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2])); + pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2])); + pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2])); + pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2])); + + //add corners of camera frustum + for (U32 i = 0; i < 8; i++) + { + pp.push_back(camera.mAgentFrustum[i]); + } + + + //bounding box line segments + U32 bs[] = + { + 0,1, + 1,3, + 3,2, + 2,0, + + 4,5, + 5,7, + 7,6, + 6,4, + + 0,4, + 1,5, + 3,7, + 2,6 + }; + + for (U32 i = 0; i < 12; i++) + { //for each line segment in bounding box + for (U32 j = 0; j < 6; j++) + { //for each plane in camera frustum + const LLPlane& cp = camera.getAgentPlane(j); + const LLVector3& v1 = pp[bs[i*2+0]]; + const LLVector3& v2 = pp[bs[i*2+1]]; + const LLVector3 n(cp.mV); + + LLVector3 line = v1-v2; + + F32 d1 = line*n; + F32 d2 = -cp.dist(v2); + + F32 t = d2/d1; + + if (t > 0.f && t < 1.f) + { + LLVector3 intersect = v2+line*t; + pp.push_back(intersect); + } + } + } + + //camera frustum line segments + const U32 fs[] = + { + 0,1, + 1,2, + 2,3, + 3,1, + + 4,5, + 5,6, + 6,7, + 7,4, + + 0,4, + 1,5, + 2,6, + 3,7 + }; + + LLVector3 center = (max+min)*0.5f; + LLVector3 size = (max-min)*0.5f; + + for (U32 i = 0; i < 12; i++) + { + for (U32 j = 0; j < 6; ++j) + { + const LLVector3& v1 = pp[fs[i*2+0]+8]; + const LLVector3& v2 = pp[fs[i*2+1]+8]; + const LLPlane& cp = bp[j]; + const LLVector3 n(cp.mV); + + LLVector3 line = v1-v2; + + F32 d1 = line*n; + F32 d2 = -cp.dist(v2); + + F32 t = d2/d1; + + if (t > 0.f && t < 1.f) + { + LLVector3 intersect = v2+line*t; + pp.push_back(intersect); + } + } + } + + LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f), + max+LLVector3(0.05f,0.05f,0.05f) }; + + for (U32 i = 0; i < pp.size(); ++i) + { + bool found = true; + + const F32* p = pp[i].mV; + + for (U32 j = 0; j < 3; ++j) + { + if (p[j] < ext[0].mV[j] || + p[j] > ext[1].mV[j]) + { + found = false; + break; + } + } + + for (U32 j = 0; j < 6; ++j) + { + const LLPlane& cp = camera.getAgentPlane(j); + F32 dist = cp.dist(pp[i]); + if (dist > 0.05f) //point is above some plane, not contained + { + found = false; + break; + } + } + + if (found) + { + fp.push_back(pp[i]); + } + } + + if (fp.empty()) + { + return FALSE; + } + + return TRUE; +} + +void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector& vpc) +{ + if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) < 3) { return; } - //temporary hack to disable shadows but keep local lights - static BOOL clear = TRUE; - static const LLCachedControl gen_shadow("RenderDeferredSunShadow",false); - if (!gen_shadow) + LLVector3 up; + + //LLGLEnable depth_clamp(GL_DEPTH_CLAMP_NV); + + if (lightDir.mV[2] > 0.5f) + { + up = LLVector3(1,0,0); + } + else + { + up = LLVector3(0, 0, 1); + } + + + static const LLCachedControl gi_range("RenderGIRange",96.f); + + U32 res = mGIMap.getWidth(); + + static const LLCachedControl render_gi_attenuation("RenderGIAttenuation",.1f); + F32 atten = llmax(render_gi_attenuation.get(), 0.001f); + + //set radius to range at which distance attenuation of incoming photons is near 0 + + F32 lrad = sqrtf(1.f/(atten*0.01f)); + + F32 lrange = lrad+gi_range*0.5f; + + LLVector3 pad(lrange,lrange,lrange); + + glh::matrix4f view = look(LLVector3(128.f,128.f,128.f), lightDir, up); + + LLVector3 cp = camera.getOrigin()+camera.getAtAxis()*(gi_range*0.5f); + + glh::vec3f scp(cp.mV); + view.mult_matrix_vec(scp); + cp.setVec(scp.v); + + F32 pix_width = lrange/(res*0.5f); + + //move cp to the nearest pix_width + for (U32 i = 0; i < 3; i++) + { + cp.mV[i] = llround(cp.mV[i], pix_width); + } + + LLVector3 min = cp-pad; + LLVector3 max = cp+pad; + + //set mGIRange to range in tc space[0,1] that covers texture block of intersecting lights around a point + mGIRange.mV[0] = (max.mV[0]-min.mV[0])/res; + mGIRange.mV[1] = (max.mV[1]-min.mV[1])/res; + mGILightRadius = lrad/lrange*0.5f; + + glh::matrix4f proj = gl_ortho(min.mV[0], max.mV[0], + min.mV[1], max.mV[1], + -max.mV[2], -min.mV[2]); + + LLCamera sun_cam = camera; + + glh::matrix4f eye_view = glh_get_current_modelview(); + + //get eye space to camera space matrix + mGIMatrix = view*eye_view.inverse(); + mGINormalMatrix = mGIMatrix.inverse().transpose(); + mGIInvProj = proj.inverse(); + mGIMatrixProj = proj*mGIMatrix; + + //translate and scale to [0,1] + glh::matrix4f trans(.5f, 0.f, 0.f, .5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); + + mGIMatrixProj = trans*mGIMatrixProj; + + glh_set_current_modelview(view); + glh_set_current_projection(proj); + + LLViewerCamera::updateFrustumPlanes(sun_cam, TRUE, FALSE, TRUE); + + sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); + static LLCullResult result; + + pushRenderTypeMask(); + + andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_BUMP, + LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_TREE, + LLPipeline::RENDER_TYPE_TERRAIN, + LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_VOIDWATER, + LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW, + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_PASS_SIMPLE, + LLPipeline::RENDER_TYPE_PASS_BUMP, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, + LLPipeline::RENDER_TYPE_PASS_SHINY, + END_RENDER_TYPES); + + + + S32 occlude = LLPipeline::sUseOcclusion; + //LLPipeline::sUseOcclusion = 0; + LLPipeline::sShadowRender = TRUE; + + //only render large objects into GI map + static const LLCachedControl render_gi_min_render_size("RenderGIMinRenderSize",.5f); + sMinRenderSize = render_gi_min_render_size; + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_GI_SOURCE; + mGIMap.bindTarget(); + + F64 last_modelview[16]; + F64 last_projection[16]; + for (U32 i = 0; i < 16; i++) + { + last_modelview[i] = gGLLastModelView[i]; + last_projection[i] = gGLLastProjection[i]; + gGLLastModelView[i] = mGIModelview.m[i]; + gGLLastProjection[i] = mGIProjection.m[i]; + } + + sun_cam.setOrigin(0.f, 0.f, 0.f); + updateCull(sun_cam, result); + stateSort(sun_cam, result); + + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = last_modelview[i]; + gGLLastProjection[i] = last_projection[i]; + } + + mGIProjection = proj; + mGIModelview = view; + + LLGLEnable cull(GL_CULL_FACE); + + //generate GI map + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixf(proj.m); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixf(view.m); + + stop_glerror(); + gGLLastMatrix = NULL; + + mGIMap.clear(); + + { + //LLGLEnable enable(GL_DEPTH_CLAMP_NV); + renderGeomDeferred(camera); + } + + mGIMap.flush(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + gGLLastMatrix = NULL; + + LLPipeline::sUseOcclusion = occlude; + LLPipeline::sShadowRender = FALSE; + sMinRenderSize = 0.f; + + popRenderTypeMask(); + +} + +void LLPipeline::generateSunShadow(LLCamera& camera) +{ + static const LLCachedControl shadow_detial("RenderShadowDetail",0); + if (!sRenderDeferred || shadow_detial <= 0) { - if (clear) - { - clear = FALSE; - for (U32 i = 0; i < 4; i++) - { - mSunShadow[i].bindTarget(); - mSunShadow[i].clear(); - mSunShadow[i].flush(); - } - } return; } - clear = TRUE; + + F64 last_modelview[16]; + F64 last_projection[16]; + for (U32 i = 0; i < 16; i++) + { //store last_modelview of world camera + last_modelview[i] = gGLLastModelView[i]; + last_projection[i] = gGLLastProjection[i]; + } + pushRenderTypeMask(); andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE, LLPipeline::RENDER_TYPE_ALPHA, @@ -6618,40 +7936,137 @@ void LLPipeline::generateSunShadow(LLCamera& camera) //get sun view matrix - F32 range = 128.f; - //store current projection/modelview matrix glh::matrix4f saved_proj = glh_get_current_projection(); glh::matrix4f saved_view = glh_get_current_modelview(); glh::matrix4f inv_view = saved_view.inverse(); - glh::matrix4f view[4]; - glh::matrix4f proj[4]; - LLVector3 up; - + glh::matrix4f view[6]; + glh::matrix4f proj[6]; + //clip contains parallel split distances for 3 splits - static const LLCachedControl clip("RenderShadowClipPlanes",LLVector3(4.f,8.f,24.f)); - - //far clip on last split is minimum of camera view distance and 128 - mSunClipPlanes = LLVector4(clip, clip.get().mV[2] * clip.get().mV[2]/clip.get().mV[1]); - - const LLPickInfo& pick_info = gViewerWindow->getLastPick(); - - if (!pick_info.mPosGlobal.isExactlyZero()) - { //squish nearest frustum based on alt-zoom (tighten up nearest frustum when focusing on tiny object - F32 focus_dist = (F32) (pick_info.mPosGlobal + LLVector3d(pick_info.mObjectOffset) - gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin())).magVec(); - mSunClipPlanes.mV[0] = llclamp(focus_dist*focus_dist, 2.f, mSunClipPlanes.mV[0]); - } + static const LLCachedControl normal_clip_planes("RenderShadowClipPlanes",LLVector3(1.f,12.f,32.f)); + static const LLCachedControl ortho_clip_planes("RenderShadowOrthoClipPlanes",LLVector3(4.f,8.f,24.f)); + const LLVector3 &sun_clip = normal_clip_planes.get(); + const LLVector3 &ortho_clip = ortho_clip_planes.get(); - // convenience array of 4 near clip plane distances - F32 dist[] = { 0.1f, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] }; + //far clip on last split is minimum of camera view distance and 128 + mSunClipPlanes = LLVector4(sun_clip, sun_clip.mV[2] * sun_clip.mV[2]/sun_clip.mV[1]); + + mSunOrthoClipPlanes = LLVector4(ortho_clip, ortho_clip.mV[2]*ortho_clip.mV[2]/ortho_clip.mV[1]); //currently used for amount to extrude frusta corners for constructing shadow frusta - static const LLCachedControl n("RenderShadowNearDist",LLVector3(256,256,256)); - F32 nearDist[] = { n.get().mV[0], n.get().mV[1], n.get().mV[2], n.get().mV[2] }; + //staic const LLCachedControl shadow_near_dist("RenderShadowNearDist"); + //LLVector3 &n = shadow_near_dist.get(); + //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] }; + + LLVector3 lightDir = -mSunDir; + lightDir.normVec(); + + glh::vec3f light_dir(lightDir.mV); + + //create light space camera matrix + + LLVector3 at = lightDir; + + LLVector3 up = camera.getAtAxis(); + + if (fabsf(up*lightDir) > 0.75f) + { + up = camera.getUpAxis(); + } + + /*LLVector3 left = up%at; + up = at%left;*/ + + up.normVec(); + at.normVec(); + + + LLCamera main_camera = camera; + + F32 near_clip = 0.f; + { + //get visible point cloud + std::vector fp; + + main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum); + + LLVector3 min,max; + getVisiblePointCloud(main_camera,min,max,fp); + + if (fp.empty()) + { + if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowCamera[0] = main_camera; + mShadowExtents[0][0] = min; + mShadowExtents[0][1] = max; + + mShadowFrustPoints[0].clear(); + mShadowFrustPoints[1].clear(); + mShadowFrustPoints[2].clear(); + mShadowFrustPoints[3].clear(); + } + popRenderTypeMask(); + return; + } + + generateGI(camera, lightDir, fp); + + //get good split distances for frustum + for (U32 i = 0; i < fp.size(); ++i) + { + glh::vec3f v(fp[i].mV); + saved_view.mult_matrix_vec(v); + fp[i].setVec(v.v); + } + + min = fp[0]; + max = fp[0]; + + //get camera space bounding box + for (U32 i = 1; i < fp.size(); ++i) + { + update_min_max(min, max, fp[i]); + } + + near_clip = -max.mV[2]; + F32 far_clip = -min.mV[2]*2.f; + + far_clip = llmin(far_clip, 128.f); + far_clip = llmin(far_clip, camera.getFar()); + + F32 range = far_clip-near_clip; + + static const LLCachedControl shadow_split_exponent("RenderShadowSplitExponent",LLVector3(3.f,3.f,2.f)); + const LLVector3 &split_exp = shadow_split_exponent.get(); + + F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) ); + + da = powf(da, split_exp.mV[2]); + + + F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da; + + + for (U32 i = 0; i < 4; ++i) + { + F32 x = (F32)(i+1)/4.f; + x = powf(x, sxp); + mSunClipPlanes.mV[i] = near_clip+range*x; + } + } + + // convenience array of 4 near clip plane distances + F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] }; for (S32 j = 0; j < 4; j++) { + if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowFrustPoints[j].clear(); + } LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j; @@ -6659,83 +8074,45 @@ void LLPipeline::generateSunShadow(LLCamera& camera) glh_set_current_modelview(saved_view); glh_set_current_projection(saved_proj); - //get center of far clip plane (for point of interest later) - LLVector3 center = camera.getOrigin() + camera.getAtAxis() * range; - LLVector3 eye = camera.getOrigin(); //camera used for shadow cull/render LLCamera shadow_cam; - // perspective shadow map - glh::vec3f p[16]; //point cloud to be contained by shadow projection (light camera space) - glh::vec3f wp[16]; //point cloud to be contained by shadow projection (world space) - - LLVector3 lightDir = -mSunDir; - glh::vec3f light_dir(lightDir.mV); - - //create light space camera matrix - LLVector3 at; - F32 dl = camera.getLeftAxis() * lightDir; - F32 du = camera.getUpAxis() * lightDir; - - //choose an at axis such that up will be most aligned with lightDir - if (dl*dl < du*du) - { - at = lightDir%camera.getLeftAxis(); - } - else - { - at = lightDir%camera.getUpAxis(); - } - - if (at * camera.getAtAxis() < 0) - { - at = -at; - } - - - LLVector3 left = lightDir%at; - up = left%lightDir; - up.normVec(); - //create world space camera frustum for this split shadow_cam = camera; shadow_cam.setFar(16.f); - LLViewerCamera::updateFrustumPlanes(shadow_cam); + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); LLVector3* frust = shadow_cam.mAgentFrustum; LLVector3 pn = shadow_cam.getAtAxis(); - LLVector3 frust_center; - LLVector3 min, max; //construct 8 corners of split frustum section for (U32 i = 0; i < 4; i++) { LLVector3 delta = frust[i+4]-eye; + delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f; delta.normVec(); F32 dp = delta*pn; - frust[i] = eye + (delta*dist[j])/dp; - frust[i+4] = eye + (delta*dist[j+1])/dp; - frust_center += frust[i] + frust[i+4]; + frust[i] = eye + (delta*dist[j]*0.95f)/dp; + frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp; } - - //get frustum center - frust_center /= 8.f; shadow_cam.calcAgentFrustumPlanes(frust); - + shadow_cam.mFrustumCornerDist = 0.f; if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) { mShadowCamera[j] = shadow_cam; } - if (gPipeline.getVisibleExtents(shadow_cam, min, max)) + std::vector fp; + + if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir)) { //no possible shadow receivers if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) @@ -6745,6 +8122,16 @@ void LLPipeline::generateSunShadow(LLCamera& camera) mShadowCamera[j+4] = shadow_cam; } + mShadow[j].bindTarget(); + { + LLGLDepthTest depth(GL_TRUE); + mShadow[j].clear(); + } + mShadow[j].flush(); + + mShadowError.mV[j] = 0.f; + mShadowFOV.mV[j] = 0.f; + continue; } @@ -6752,53 +8139,265 @@ void LLPipeline::generateSunShadow(LLCamera& camera) { mShadowExtents[j][0] = min; mShadowExtents[j][1] = max; + mShadowFrustPoints[j] = fp; } - view[j] = look(frust_center-lightDir*nearDist[j], lightDir, up); - F32 shadow_dist = nearDist[j]; - for (U32 i = 0; i < 8; i++) + //find a good origin for shadow projection + LLVector3 origin; + + //get a temporary view projection + view[j] = look(camera.getOrigin(), lightDir, -up); + + std::vector wpf; + + for (U32 i = 0; i < fp.size(); i++) { - //points in worldspace (wp) and light camera space (p) - //that must be included in shadow generation - wp[i] = glh::vec3f(frust[i].mV); - wp[i+8] = wp[i] - light_dir*shadow_dist; - view[j].mult_matrix_vec(wp[i], p[i]); - view[j].mult_matrix_vec(wp[i+8], p[i+8]); + glh::vec3f p = glh::vec3f(fp[i].mV); + view[j].mult_matrix_vec(p); + wpf.push_back(LLVector3(p.v)); } - - min = LLVector3(p[0].v); - max = LLVector3(p[0].v); - LLVector3 fmin = min; - LLVector3 fmax = max; + min = wpf[0]; + max = wpf[0]; - for (U32 i = 1; i < 16; i++) - { //find camera space AABB of frustum in light camera space - update_min_max(min, max, LLVector3(p[i].v)); - if (i < 8) + for (U32 i = 0; i < fp.size(); ++i) + { //get AABB in camera space + update_min_max(min, max, wpf[i]); + } + + // Construct a perspective transform with perspective along y-axis that contains + // points in wpf + //Known: + // - far clip plane + // - near clip plane + // - points in frustum + //Find: + // - origin + + //get some "interesting" points of reference + LLVector3 center = (min+max)*0.5f; + LLVector3 size = (max-min)*0.5f; + LLVector3 near_center = center; + near_center.mV[1] += size.mV[1]*2.f; + + + //put all points in wpf in quadrant 0, reletive to center of min/max + //get the best fit line using least squares + F32 bfm = 0.f; + F32 bfb = 0.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + wpf[i] -= center; + wpf[i].mV[0] = fabsf(wpf[i].mV[0]); + wpf[i].mV[2] = fabsf(wpf[i].mV[2]); + } + + if (!wpf.empty()) + { + F32 sx = 0.f; + F32 sx2 = 0.f; + F32 sy = 0.f; + F32 sxy = 0.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + sx += wpf[i].mV[0]; + sx2 += wpf[i].mV[0]*wpf[i].mV[0]; + sy += wpf[i].mV[1]; + sxy += wpf[i].mV[0]*wpf[i].mV[1]; + } + + bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2); + bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2); + } + + { + // best fit line is y=bfm*x+bfb + + //find point that is furthest to the right of line + F32 off_x = -1.f; + LLVector3 lp; + + for (U32 i = 0; i < wpf.size(); ++i) { - update_min_max(fmin, fmax, LLVector3(p[i].v)); + //y = bfm*x+bfb + //x = (y-bfb)/bfm + F32 lx = (wpf[i].mV[1]-bfb)/bfm; + + lx = wpf[i].mV[0]-lx; + + if (off_x < lx) + { + off_x = lx; + lp = wpf[i]; + } + } + + //get line with slope bfm through lp + // bfb = y-bfm*x + bfb = lp.mV[1]-bfm*lp.mV[0]; + + //calculate error + mShadowError.mV[j] = 0.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + F32 lx = (wpf[i].mV[1]-bfb)/bfm; + mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx); + } + + mShadowError.mV[j] /= wpf.size(); + mShadowError.mV[j] /= size.mV[0]; + + static const LLCachedControl render_shadow_error_cutoff("RenderShadowErrorCutoff",5.f); + if (mShadowError.mV[j] > render_shadow_error_cutoff) + { //just use ortho projection + mShadowFOV.mV[j] = -1.f; + origin.clearVec(); + proj[j] = gl_ortho(min.mV[0], max.mV[0], + min.mV[1], max.mV[1], + -max.mV[2], -min.mV[2]); + } + else + { + //origin is where line x = 0; + origin.setVec(0,bfb,0); + + F32 fovz = 1.f; + F32 fovx = 1.f; + + LLVector3 zp; + LLVector3 xp; + + for (U32 i = 0; i < wpf.size(); ++i) + { + LLVector3 atz = wpf[i]-origin; + atz.mV[0] = 0.f; + atz.normVec(); + if (fovz > -atz.mV[1]) + { + zp = wpf[i]; + fovz = -atz.mV[1]; + } + + LLVector3 atx = wpf[i]-origin; + atx.mV[2] = 0.f; + atx.normVec(); + if (fovx > -atx.mV[1]) + { + fovx = -atx.mV[1]; + xp = wpf[i]; + } + } + + fovx = acos(fovx); + fovz = acos(fovz); + + static const LLCachedControl render_shadow_fov_cutoff("RenderShadowFOVCutoff",1.1f); + F32 cutoff = llmin(render_shadow_fov_cutoff.get(), 1.4f); + + mShadowFOV.mV[j] = fovx; + + if (fovx < cutoff && fovz > cutoff) + { + //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff + F32 d = zp.mV[2]/tan(cutoff); + F32 ny = zp.mV[1] + fabsf(d); + + origin.mV[1] = ny; + + fovz = 1.f; + fovx = 1.f; + + for (U32 i = 0; i < wpf.size(); ++i) + { + LLVector3 atz = wpf[i]-origin; + atz.mV[0] = 0.f; + atz.normVec(); + fovz = llmin(fovz, -atz.mV[1]); + + LLVector3 atx = wpf[i]-origin; + atx.mV[2] = 0.f; + atx.normVec(); + fovx = llmin(fovx, -atx.mV[1]); + } + + fovx = acos(fovx); + fovz = acos(fovz); + + if (fovx > cutoff || llround(fovz, 0.01f) > cutoff) + { + // llerrs << "WTF?" << llendl; + } + + mShadowFOV.mV[j] = cutoff; + } + + + origin += center; + + F32 ynear = -(max.mV[1]-origin.mV[1]); + F32 yfar = -(min.mV[1]-origin.mV[1]); + + if (ynear < 0.1f) //keep a sensible near clip plane + { + F32 diff = 0.1f-ynear; + origin.mV[1] += diff; + ynear += diff; + yfar += diff; + } + + if (fovx > cutoff) + { //just use ortho projection + origin.clearVec(); + mShadowError.mV[j] = -1.f; + proj[j] = gl_ortho(min.mV[0], max.mV[0], + min.mV[1], max.mV[1], + -max.mV[2], -min.mV[2]); + } + else + { + //get perspective projection + view[j] = view[j].inverse(); + + glh::vec3f origin_agent(origin.mV); + + //translate view to origin + view[j].mult_matrix_vec(origin_agent); + + eye = LLVector3(origin_agent.v); + + if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + { + mShadowFrustOrigin[j] = eye; + } + + view[j] = look(LLVector3(origin_agent.v), lightDir, -up); + + F32 fx = 1.f/tanf(fovx); + F32 fz = 1.f/tanf(fovz); + + proj[j] = glh::matrix4f(-fx, 0, 0, 0, + 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar), + 0, 0, -fz, 0, + 0, -1.f, 0, 0); + } } } - //generate perspective matrix that contains frustum - //proj[j] = matrix_perspective(min, max); - proj[j] = gl_ortho(min.mV[0], max.mV[0], - min.mV[1], max.mV[1], - -max.mV[2], -min.mV[2]); - shadow_cam.setFar(128.f); shadow_cam.setOriginAndLookAt(eye, up, center); + shadow_cam.setOrigin(0,0,0); + glh_set_current_modelview(view[j]); glh_set_current_projection(proj[j]); LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - proj[j] = gl_ortho(fmin.mV[0], fmax.mV[0], - fmin.mV[1], fmax.mV[1], - -fmax.mV[2], -fmin.mV[2]); + shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); //translate and scale to from [-1, 1] to [0, 1] glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, @@ -6809,101 +8408,187 @@ void LLPipeline::generateSunShadow(LLCamera& camera) glh_set_current_modelview(view[j]); glh_set_current_projection(proj[j]); + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = mShadowModelview[j].m[i]; + gGLLastProjection[i] = mShadowProjection[j].m[i]; + } + + mShadowModelview[j] = view[j]; + mShadowProjection[j] = proj[j]; + + mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view; + stop_glerror(); - //clip out geometry on the same side of water as the camera - static LLCullResult result; - S32 occlude = LLPipeline::sUseOcclusion; - LLPipeline::sUseOcclusion = 1; - LLPipeline::sShadowRender = TRUE; - //hack to prevent LOD updates from using sun camera origin - shadow_cam.setOrigin(camera.getOrigin()); - updateCull(shadow_cam, result); - stateSort(shadow_cam, result); - + mShadow[j].bindTarget(); + mShadow[j].getViewport(gGLViewport); + + { + static LLCullResult result[4]; + + //LLGLEnable enable(GL_DEPTH_CLAMP_NV); + renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE); + } + + mShadow[j].flush(); + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) { LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); mShadowCamera[j+4] = shadow_cam; } + } - LLFastTimer t(LLFastTimer::FTM_SHADOW_RENDER); + + //hack to disable projector shadows + static bool clear = true; + static const LLCachedControl gen_shadow("RenderShadowDetail",0); - stop_glerror(); + if (gen_shadow > 1) + { + clear = true; + F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f); - mSunShadow[j].bindTarget(); - mSunShadow[j].getViewport(gGLViewport); + //update shadow targets + for (U32 i = 0; i < 2; i++) + { //for each current shadow + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i; - { - LLGLDepthTest depth(GL_TRUE); - mSunShadow[j].clear(); + if (mShadowSpotLight[i].notNull() && + (mShadowSpotLight[i] == mTargetShadowSpotLight[0] || + mShadowSpotLight[i] == mTargetShadowSpotLight[1])) + { //keep this spotlight + mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f); } - - U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP }; - LLGLEnable cull(GL_CULL_FACE); - - //generate sun shadow map - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadMatrixf(proj[j].m); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadMatrixf(view[j].m); - - stop_glerror(); - gGLLastMatrix = NULL; - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - glColor4f(1,1,1,1); - - glCullFace(GL_FRONT); - - stop_glerror(); - - gGL.setColorMask(false, false); - - gDeferredShadowProgram.bind(); - { - LLFastTimer ftm(LLFastTimer::FTM_SHADOW_SIMPLE); - LLGLDisable test(GL_ALPHA_TEST); - gGL.getTexUnit(0)->disable(); - for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) - { - renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); + else + { //fade out this light + mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f); + + if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull()) + { //faded out, grab one of the pending spots (whichever one isn't already taken) + if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2]) + { + mShadowSpotLight[i] = mTargetShadowSpotLight[0]; + } + else + { + mShadowSpotLight[i] = mTargetShadowSpotLight[1]; + } } - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); } - + } + + for (S32 i = 0; i < 2; i++) + { + glh_set_current_modelview(saved_view); + glh_set_current_projection(saved_proj); + + if (mShadowSpotLight[i].isNull()) { - LLFastTimer ftm(LLFastTimer::FTM_SHADOW_ALPHA); - LLGLEnable test(GL_ALPHA_TEST); - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f); - renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE); - glColor4f(1,1,1,1); - renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + continue; } + + LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume(); + + if (!volume) + { + mShadowSpotLight[i] = NULL; + continue; + } + + LLDrawable* drawable = mShadowSpotLight[i]; + + LLVector3 params = volume->getSpotLightParams(); + F32 fov = params.mV[0]; + + //get agent->light space matrix (modelview) + LLVector3 center = drawable->getPositionAgent(); + LLQuaternion quat = volume->getRenderRotation(); + + //get near clip plane + LLVector3 scale = volume->getScale(); + LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); + at_axis *= quat; + + LLVector3 np = center+at_axis; + at_axis.normVec(); + + //get origin that has given fov for plane np, at_axis, and given scale + F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); + + LLVector3 origin = np - at_axis*dist; + + LLMatrix4 mat(quat, LLVector4(origin, 1.f)); + + view[i+4] = glh::matrix4f((F32*) mat.mMatrix); + + view[i+4] = view[i+4].inverse(); + + //get perspective matrix + F32 near_clip = dist+0.01f; + F32 width = scale.mV[VX]; + F32 height = scale.mV[VY]; + F32 far_clip = dist+volume->getLightRadius()*1.5f; + + F32 fovy = fov * RAD_TO_DEG; + F32 aspect = width/height; - gDeferredShadowProgram.unbind(); + proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip); - renderGeomShadow(shadow_cam); + //translate and scale to from [-1, 1] to [0, 1] + glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); - gGL.setColorMask(true, true); + glh_set_current_modelview(view[i+4]); + glh_set_current_projection(proj[i+4]); - glCullFace(GL_BACK); - LLPipeline::sUseOcclusion = occlude; - LLPipeline::sShadowRender = FALSE; + mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view; - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - gGLLastMatrix = NULL; + for (U32 j = 0; j < 16; j++) + { + gGLLastModelView[j] = mShadowModelview[i+4].m[j]; + gGLLastProjection[j] = mShadowProjection[i+4].m[j]; + } - sMinRenderSize = 0.f; - mSunShadow[j].flush(); + mShadowModelview[i+4] = view[i+4]; + mShadowProjection[i+4] = proj[i+4]; + + LLCamera shadow_cam = camera; + shadow_cam.setFar(far_clip); + shadow_cam.setOrigin(origin); + + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + + stop_glerror(); + + mShadow[i+4].bindTarget(); + mShadow[i+4].getViewport(gGLViewport); + + static LLCullResult result[2]; + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4; + + renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE); + + mShadow[i+4].flush(); + } + } + else + { + if (clear) + { + clear = false; + for (U32 i = 4; i < 6; i++) + { + mShadow[i].bindTarget(); + mShadow[i].clear(); + mShadow[i].flush(); + } + } } static const LLCachedControl camera_offset("CameraOffset",false); @@ -6922,6 +8607,13 @@ void LLPipeline::generateSunShadow(LLCamera& camera) glMatrixMode(GL_MODELVIEW); } gGL.setColorMask(true, false); + + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = last_modelview[i]; + gGLLastProjection[i] = last_projection[i]; + } + popRenderTypeMask(); } @@ -7075,7 +8767,8 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) { if (LLPipeline::sRenderDeferred) { - avatar->mImpostor.allocate(resX,resY,GL_RGBA16F_ARB,TRUE,TRUE); + const GLuint format = GL_RGBA; //GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later + avatar->mImpostor.allocate(resX,resY,format,TRUE,TRUE); addDeferredAttachments(avatar->mImpostor); } else @@ -7091,6 +8784,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) glStencilMask(0xFFFFFFFF); glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + { LLGLEnable scissor(GL_SCISSOR_TEST); glScissor(0, 0, resX, resY); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 436d73726..4f28b2a06 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -212,12 +212,18 @@ public: void renderGeomDeferred(LLCamera& camera); void renderGeomPostDeferred(LLCamera& camera); void renderGeomShadow(LLCamera& camera); - void bindDeferredShader(LLGLSLShader& shader, U32 light_index = 0); + void bindDeferredShader(LLGLSLShader& shader, U32 light_index = 0, LLRenderTarget* gi_source = NULL, LLRenderTarget* last_gi_post = NULL, U32 noise_map = 0xFFFFFFFF); + void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep); + void unbindDeferredShader(LLGLSLShader& shader); void renderDeferredLighting(); void generateWaterReflection(LLCamera& camera); void generateSunShadow(LLCamera& camera); + + + void renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& camera, LLCullResult& result, BOOL use_shader = TRUE, BOOL use_occlusion = TRUE); + void generateGI(LLCamera& camera, LLVector3& lightDir, std::vector& vpc); void renderHighlights(); void renderDebug(); @@ -254,6 +260,9 @@ public: BOOL hasRenderDebugFeatureMask(const U32 mask) const { return (mRenderDebugFeatureMask & mask) ? TRUE : FALSE; } BOOL hasRenderDebugMask(const U32 mask) const { return (mRenderDebugMask & mask) ? TRUE : FALSE; } + + + BOOL hasRenderType(const U32 type) const; BOOL hasAnyRenderType(const U32 type, ...) const; @@ -459,17 +468,43 @@ public: static F32 sMinRenderSize; //screen texture + LLRenderTarget mScreen; LLRenderTarget mDeferredScreen; - LLRenderTarget mDeferredLight[2]; + LLRenderTarget mEdgeMap; + LLRenderTarget mDeferredDepth; + LLRenderTarget mDeferredLight[3]; LLMultisampleBuffer mSampleBuffer; + LLRenderTarget mGIMap; + LLRenderTarget mGIMapPost[2]; + LLRenderTarget mLuminanceMap; //sun shadow map - LLRenderTarget mSunShadow[4]; + LLRenderTarget mShadow[6]; + std::vector mShadowFrustPoints[4]; + LLVector4 mShadowError; + LLVector4 mShadowFOV; + LLVector3 mShadowFrustOrigin[4]; LLCamera mShadowCamera[8]; LLVector3 mShadowExtents[4][2]; - glh::matrix4f mSunShadowMatrix[4]; + glh::matrix4f mSunShadowMatrix[6]; + glh::matrix4f mShadowModelview[6]; + glh::matrix4f mShadowProjection[6]; + glh::matrix4f mGIMatrix; + glh::matrix4f mGIMatrixProj; + glh::matrix4f mGIModelview; + glh::matrix4f mGIProjection; + glh::matrix4f mGINormalMatrix; + glh::matrix4f mGIInvProj; + LLVector2 mGIRange; + F32 mGILightRadius; + + LLPointer mShadowSpotLight[2]; + F32 mSpotLightFade[2]; + LLPointer mTargetShadowSpotLight[2]; + LLVector4 mSunClipPlanes; + LLVector4 mSunOrthoClipPlanes; LLVector2 mScreenScale; @@ -484,6 +519,8 @@ public: //noise map U32 mNoiseMap; + U32 mTrueNoiseMap; + U32 mLightFunc; LLColor4 mSunDiffuse; LLVector3 mSunDir; From ba8e62841f55ed4090227dcc0efc469a16ee1b1c Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 11 May 2011 23:55:06 -0500 Subject: [PATCH 16/87] Deferred class2 alpha shader should actually compile now. --- .../newview/app_settings/shaders/class1/deferred/alphaF.glsl | 4 ---- .../newview/app_settings/shaders/class1/deferred/alphaV.glsl | 1 - .../newview/app_settings/shaders/class2/deferred/alphaF.glsl | 3 --- .../newview/app_settings/shaders/class2/deferred/alphaV.glsl | 3 +-- indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl | 2 -- 5 files changed, 1 insertion(+), 12 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl index 9f98f9266..de3af484b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl @@ -8,7 +8,6 @@ #extension GL_ARB_texture_rectangle : enable uniform sampler2D diffuseMap; -uniform sampler2D noiseMap; uniform sampler2DRect depthMap; uniform mat4 shadow_matrix[6]; @@ -22,7 +21,6 @@ varying vec3 vary_ambient; varying vec3 vary_directional; varying vec3 vary_fragcoord; varying vec3 vary_position; -varying vec3 vary_light; varying vec3 vary_pointlight_col; uniform mat4 inv_proj; @@ -46,8 +44,6 @@ void main() vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; frag *= screen_res; - vec3 samp_pos = getPosition(frag).xyz; - vec4 pos = vec4(vary_position, 1.0); vec4 diff= texture2D(diffuseMap, gl_TexCoord[0].xy); diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl index 5200f4d64..64e2f6ee8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl @@ -9,7 +9,6 @@ vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); void calcAtmospherics(vec3 inPositionEye); float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 4e16e87d8..22c8b4c06 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -12,7 +12,6 @@ uniform sampler2DRectShadow shadowMap0; uniform sampler2DRectShadow shadowMap1; uniform sampler2DRectShadow shadowMap2; uniform sampler2DRectShadow shadowMap3; -uniform sampler2D noiseMap; uniform sampler2DRect depthMap; uniform mat4 shadow_matrix[6]; @@ -69,8 +68,6 @@ void main() vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; frag *= screen_res; - vec3 samp_pos = getPosition(frag).xyz; - float shadow = 1.0; vec4 pos = vec4(vary_position, 1.0); diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl index da25c42e4..0f037dafd 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl @@ -9,7 +9,6 @@ vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); void calcAtmospherics(vec3 inPositionEye); float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); @@ -41,7 +40,7 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //distance attenuation float dist2 = d*d/(la*la); float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - 45 + // spotlight coefficient. float spot = max(dot(-ln, lv), is_pointlight); da *= spot*spot; // GL_SPOT_EXPONENT=2 diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl index ff32a15c5..a86f67a5a 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl @@ -10,8 +10,6 @@ uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; -uniform float gi_dist_cutoff; - varying vec2 vary_fragcoord; uniform float depth_cutoff; From 5f72cbb10319db5e68ca210013cfddaf3d83d770 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 12 May 2011 18:22:51 +0200 Subject: [PATCH 17/87] Add support for flushing messages from plugin to viewer. Actually flush messages before terminating a plugin (upon the shutdown message) and flush messages in the file- and dirpicker before opening the blocking dialog. Flush debug messages too (deeper into the code, just prior to the actual blocking call). Also, fix the context folder map to be a thread-safe singleton and *attempt* to add support for default folders to windows and Mac. The latter might even not compile yet and definitely have to be tested (and fixed): Opening a DirPicker in preferences --> Network and Set the directory location of the cache. It should open a Dialog window where you are already in the folder that is the current cache directory setting (you can click Cancel after verifying that this worked). And, start to upload an image, select a file is some directory (other than what it starts in). You can omit the actual upload by clicking cancel in the preview. Then upload again and now it should start in the same folder as that you were just in. Possibly you need to first open a file picker elsewhere with a different context though, or windows might choose to open in the last folder anyway while the code doesn't really work. Uploading a sound before the second texture upload should do the trick. --- indra/llplugin/llpluginmessagepipe.cpp | 49 +++++-- indra/llplugin/llpluginmessagepipe.h | 6 +- indra/llplugin/llpluginprocesschild.cpp | 11 ++ indra/llplugin/llpluginprocessparent.cpp | 4 + indra/llplugin/llpluginprocessparent.h | 3 +- indra/newview/statemachine/aifilepicker.cpp | 24 +++- indra/newview/statemachine/aifilepicker.h | 7 +- .../plugins/base_basic/basic_plugin_base.cpp | 17 +++ indra/plugins/base_basic/basic_plugin_base.h | 13 +- .../filepicker/basic_plugin_filepicker.cpp | 6 +- indra/plugins/filepicker/legacy.cpp | 2 +- indra/plugins/filepicker/lldirpicker.cpp | 72 ++++++---- indra/plugins/filepicker/lldirpicker.h | 2 +- indra/plugins/filepicker/llfilepicker.cpp | 124 +++++++++++++----- indra/plugins/filepicker/llfilepicker.h | 9 +- 15 files changed, 258 insertions(+), 91 deletions(-) diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index ebac3c52b..7aaa09372 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -89,6 +89,16 @@ bool LLPluginMessagePipeOwner::writeMessageRaw(const std::string &message) return result; } +bool LLPluginMessagePipeOwner::flushMessages(void) +{ + bool result = true; + if (mMessagePipe != NULL) + { + result = mMessagePipe->flushMessages(); + } + return result; +} + void LLPluginMessagePipeOwner::killMessagePipe(void) { if(mMessagePipe != NULL) @@ -163,26 +173,32 @@ bool LLPluginMessagePipe::pump(F64 timeout) return result; } -bool LLPluginMessagePipe::pumpOutput() +static apr_interval_time_t const flush_max_block_time = 10000000; // Even when flushing, give up after 10 seconds. +static apr_interval_time_t const flush_min_timeout = 1000; // When flushing, initially timeout after 1 ms. +static apr_interval_time_t const flush_max_timeout = 50000; // Never wait longer than 50 ms. + +// DO NOT SET 'flush' TO TRUE WHEN CALLED ON THE VIEWER SIDE! +// flush is only intended for plugin-side. +bool LLPluginMessagePipe::pumpOutput(bool flush) { bool result = true; if(mSocket) { - apr_status_t status; - apr_size_t size; + apr_interval_time_t flush_time_left_usec = flush_max_block_time; + apr_interval_time_t timeout_usec = flush ? flush_min_timeout : 0; LLMutexLock lock(&mOutputMutex); - if(!mOutput.empty()) + while(result && !mOutput.empty()) { // write any outgoing messages - size = (apr_size_t)mOutput.size(); + apr_size_t size = (apr_size_t)mOutput.size(); - setSocketTimeout(0); + setSocketTimeout(timeout_usec); // LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL; - status = apr_socket_send( + apr_status_t status = apr_socket_send( mSocket->getSocket(), (const char*)mOutput.data(), &size); @@ -193,12 +209,29 @@ bool LLPluginMessagePipe::pumpOutput() { // success mOutput = mOutput.substr(size); + break; } - else if(APR_STATUS_IS_EAGAIN(status)) + else if(APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) { // Socket buffer is full... // remove the written part from the buffer and try again later. mOutput = mOutput.substr(size); + if (!flush) + break; + flush_time_left_usec -= timeout_usec; + if (flush_time_left_usec <= 0) + { + result = false; + } + else if (size == 0) + { + // Nothing at all was written. Increment wait time. + timeout_usec = std::min(flush_max_timeout, 2 * timeout_usec); + } + else + { + timeout_usec = std::max(flush_min_timeout, timeout_usec / 2); + } } else if(APR_STATUS_IS_EOF(status)) { diff --git a/indra/llplugin/llpluginmessagepipe.h b/indra/llplugin/llpluginmessagepipe.h index 6eedca27f..1e71caf42 100644 --- a/indra/llplugin/llpluginmessagepipe.h +++ b/indra/llplugin/llpluginmessagepipe.h @@ -61,6 +61,8 @@ protected: bool canSendMessage(void); // call this to send a message over the pipe bool writeMessageRaw(const std::string &message); + // call this to attempt to flush all messages for 10 seconds long. + bool flushMessages(void); // call this to close the pipe void killMessagePipe(void); @@ -79,8 +81,10 @@ public: void clearOwner(void); bool pump(F64 timeout = 0.0f); - bool pumpOutput(); + bool pumpOutput(bool flush = false); bool pumpInput(F64 timeout = 0.0f); + + bool flushMessages(void) { return pumpOutput(true); } protected: void processInput(void); diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index 3ba765bf6..fdcb4f6a8 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -556,11 +556,22 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message) } else if (message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) { + bool flush = false; std::string message_name = parsed.getName(); if(message_name == "shutdown") { // The plugin is finished. setState(STATE_UNLOADING); + flush = true; + } + else if (message_name == "flush") + { + flush = true; + passMessage = false; + } + if (flush) + { + flushMessages(); } } } diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index fc94ee849..0d361324e 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -104,6 +104,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner) mDebug = false; mBlocked = false; mPolledInput = false; + mReceivedShutdown = false; mPollFD.client_data = NULL; mPollFDPool.create(); @@ -165,6 +166,8 @@ void LLPluginProcessParent::errorState(void) { if(mState < STATE_RUNNING) setState(STATE_LAUNCH_FAILURE); + else if (mReceivedShutdown) + setState(STATE_EXITING); else setState(STATE_ERROR); } @@ -1012,6 +1015,7 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) else if(message_name == "shutdown") { LL_INFOS("Plugin") << "received shutdown message" << LL_ENDL; + mReceivedShutdown = true; mOwner->receivedShutdown(); } else if(message_name == "shm_add_response") diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 1ec5ef4c3..65455950f 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -145,8 +145,8 @@ private: STATE_RUNNING, // STATE_LAUNCH_FAILURE, // Failure before plugin loaded STATE_ERROR, // generic bailout state - STATE_CLEANUP, // clean everything up STATE_EXITING, // Tried to kill process, waiting for it to exit + STATE_CLEANUP, // clean everything up STATE_DONE // }; @@ -183,6 +183,7 @@ private: bool mDebug; bool mBlocked; bool mPolledInput; + bool mReceivedShutdown; LLProcessLauncher mDebugger; diff --git a/indra/newview/statemachine/aifilepicker.cpp b/indra/newview/statemachine/aifilepicker.cpp index e3a09009d..f8da4da86 100644 --- a/indra/newview/statemachine/aifilepicker.cpp +++ b/indra/newview/statemachine/aifilepicker.cpp @@ -64,31 +64,41 @@ AIFilePicker::AIFilePicker(void) : mPluginManager(NULL), mCanceled(false) { } +// static +AITHREADSAFESIMPLE(AIFilePicker::context_map_type, AIFilePicker::sContextMap, ); + +// static void AIFilePicker::store_folder(std::string const& context, std::string const& folder) { if (!folder.empty()) { - mContextMap[context] = folder; + LL_DEBUGS("Plugin") << "AIFilePicker::mContextMap[\"" << context << "\"] = \"" << folder << '"' << LL_ENDL; + AIAccess(sContextMap)->operator[](context) = folder; } } +// static std::string AIFilePicker::get_folder(std::string const& default_path, std::string const& context) { - context_map_type::iterator iter = mContextMap.find(context); - if (iter != mContextMap.end()) + AIAccess wContextMap(sContextMap); + context_map_type::iterator iter = wContextMap->find(context); + if (iter != wContextMap->end()) { return iter->second; } else if (!default_path.empty()) { + LL_DEBUGS("Plugin") << "context \"" << context << "\" not found. Returning default_path \"" << default_path << "\"." << LL_ENDL; return default_path; } - else if ((iter = mContextMap.find("savefile")) != mContextMap.end()) + else if ((iter = wContextMap->find("savefile")) != wContextMap->end()) { + LL_DEBUGS("Plugin") << "context \"" << context << "\" not found and default_path empty. Returning context \"savefile\": \"" << iter->second << "\"." << LL_ENDL; return iter->second; } else { + LL_DEBUGS("Plugin") << "context \"" << context << "\" not found, default_path empty and context \"savefile\" not found. Returning \"$HOME\"." << LL_ENDL; // This is the last resort when all else failed. Open the file chooser in directory 'home'. char const* home = NULL; #if LL_WINDOWS @@ -103,7 +113,7 @@ std::string AIFilePicker::get_folder(std::string const& default_path, std::strin void AIFilePicker::open(ELoadFilter filter, std::string const& default_path, std::string const& context, bool multiple) { mContext = context; - mFolder = get_folder(default_path, context); + mFolder = AIFilePicker::get_folder(default_path, context); mOpenType = multiple ? load_multiple : load; switch(filter) { @@ -152,7 +162,7 @@ void AIFilePicker::open(std::string const& filename, ESaveFilter filter, std::st { mFilename = filename; mContext = context; - mFolder = get_folder(default_path, context); + mFolder = AIFilePicker::get_folder(default_path, context); mOpenType = save; switch(filter) { @@ -372,7 +382,7 @@ void AIFilePicker::multiplex_impl(void) case AIFilePicker_done: { // Store folder of first filename as context. - store_folder(mContext, getFolder()); + AIFilePicker::store_folder(mContext, getFolder()); finish(); } } diff --git a/indra/newview/statemachine/aifilepicker.h b/indra/newview/statemachine/aifilepicker.h index a1709eeb8..91a7bc819 100644 --- a/indra/newview/statemachine/aifilepicker.h +++ b/indra/newview/statemachine/aifilepicker.h @@ -176,9 +176,8 @@ public: private: LLPointer mPluginManager; //!< Pointer to the plugin manager. - // AIFIXME: this should be a separate, thread-safe singleton. typedef std::map context_map_type; //!< Type of mContextMap. - context_map_type mContextMap; //!< Map context (ie, "snapshot" or "image") to last used folder. + static AIThreadSafeSimple sContextMap; //!< Map context (ie, "snapshot" or "image") to last used folder. std::string mContext; //!< Some key to indicate the context (remembers the folder per key). // Input variables (cache variable between call to open and run). @@ -191,9 +190,9 @@ private: std::vector mFilenames; //!< Filesnames. // Store a folder for the given context. - void store_folder(std::string const& context, std::string const& folder); + static void store_folder(std::string const& context, std::string const& folder); // Return the last folder stored for 'context', or default_path if none, or context "savefile" if empty, or $HOME if none. - std::string get_folder(std::string const& default_path, std::string const& context); + static std::string get_folder(std::string const& default_path, std::string const& context); protected: // Call finish() (or abort()), not delete. diff --git a/indra/plugins/base_basic/basic_plugin_base.cpp b/indra/plugins/base_basic/basic_plugin_base.cpp index f791b5887..d1a656391 100755 --- a/indra/plugins/base_basic/basic_plugin_base.cpp +++ b/indra/plugins/base_basic/basic_plugin_base.cpp @@ -115,6 +115,20 @@ void BasicPluginBase::sendLogMessage(std::string const& message, LLPluginMessage logmessage.setValue("message", message); logmessage.setValueS32("log_level",level); mSendMessageFunction(logmessage.generate().c_str(), &mPluginInstance); + // Theoretically we should flush here (that's what PLS_ENDL means), but we don't because + // that interfers with how the code would act without debug messages. Instead, the developer + // is responsible to call flushMessages themselves at the appropriate places. +} + +/** + * Flush all messages to the viewer. + * + * This blocks if necessary, up till 10 seconds, before it gives up. + */ +void BasicPluginBase::flushMessages(void) +{ + LLPluginMessage logmessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "flush"); + mSendMessageFunction(logmessage.generate().c_str(), &mPluginInstance); } /** @@ -124,6 +138,9 @@ void BasicPluginBase::sendLogMessage(std::string const& message, LLPluginMessage */ void BasicPluginBase::sendShutdownMessage(void) { + // Do a double flush. First flush all messages so far, then send the shutdown message, + // which also will try to flush itself before terminating the process. + flushMessages(); LLPluginMessage shutdownmessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shutdown"); sendMessage(shutdownmessage); } diff --git a/indra/plugins/base_basic/basic_plugin_base.h b/indra/plugins/base_basic/basic_plugin_base.h index 492b408e7..042a27b63 100755 --- a/indra/plugins/base_basic/basic_plugin_base.h +++ b/indra/plugins/base_basic/basic_plugin_base.h @@ -36,16 +36,13 @@ #ifndef BASIC_PLUGIN_BASE_H #define BASIC_PLUGIN_BASE_H -#include - -#include - #include "linden_common.h" - #include "llplugininstance.h" #include "llpluginmessage.h" #include "llpluginmessageclasses.h" +#include + class BasicPluginBase { public: @@ -65,7 +62,10 @@ public: // Used for log messages. Use macros below. void sendLogMessage(std::string const& message, LLPluginMessage::LLPLUGIN_LOG_LEVEL level); - // Shoot down the whole process. + // Flush all messages to the viewer. + void flushMessages(void); + + // Flush all messages and then shoot down the whole process. void sendShutdownMessage(void); protected: @@ -127,6 +127,7 @@ int create_plugin( #define PLS_INFOS PLS_LOG_MESSAGE(LLPluginMessage::LOG_LEVEL_INFO, LL_DEBUG_PLUGIN_MESSAGES) #define PLS_WARNS PLS_LOG_MESSAGE(LLPluginMessage::LOG_LEVEL_WARN, 1) #define PLS_ERRS PLS_LOG_MESSAGE(LLPluginMessage::LOG_LEVEL_ERR, 1) +#define PLS_FLUSH do { BasicPluginBase::sPluginBase->flushMessages(); } while(0) #endif // BASIC_PLUGIN_BASE diff --git a/indra/plugins/filepicker/basic_plugin_filepicker.cpp b/indra/plugins/filepicker/basic_plugin_filepicker.cpp index 1201c3f71..7e3a4f0b0 100644 --- a/indra/plugins/filepicker/basic_plugin_filepicker.cpp +++ b/indra/plugins/filepicker/basic_plugin_filepicker.cpp @@ -232,10 +232,13 @@ void FilepickerPlugin::receiveMessage(char const* message_string) std::string folder = message_in.getValue("folder"); bool get_directory = (filter == "directory"); + // We about to completely block on running the modal File/Dir picker window, so flush any pending messages to the viewer. + flushMessages(); + bool canceled; if (get_directory) { - canceled = !LLDirPicker::instance().getDir(&folder); + canceled = !LLDirPicker::instance().getDir(folder); } else if (type == "save") { @@ -275,6 +278,7 @@ void FilepickerPlugin::receiveMessage(char const* message_string) sendMessage(message); } // We're done. Exit the whole application. + // This first flushes any messages before terminating the plugin. sendShutdownMessage(); } else diff --git a/indra/plugins/filepicker/legacy.cpp b/indra/plugins/filepicker/legacy.cpp index f89862061..e106923bf 100644 --- a/indra/plugins/filepicker/legacy.cpp +++ b/indra/plugins/filepicker/legacy.cpp @@ -28,8 +28,8 @@ * - Initial version, written by Aleric Inglewood @ SL */ -#include "legacy.h" #include "basic_plugin_base.h" // For PLS_INFOS etc. +#include "legacy.h" // Translation map. translation_map_type translation_map; diff --git a/indra/plugins/filepicker/lldirpicker.cpp b/indra/plugins/filepicker/lldirpicker.cpp index 39dff05e9..7ddcda6df 100644 --- a/indra/plugins/filepicker/lldirpicker.cpp +++ b/indra/plugins/filepicker/lldirpicker.cpp @@ -65,7 +65,15 @@ LLDirPicker::~LLDirPicker() // nothing } -BOOL LLDirPicker::getDir(std::string* filename) +static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + if (uMsg == BFFM_INITIALIZED) + { + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); + } +} + +BOOL LLDirPicker::getDir(std::string const& folder) { if( mLocked ) { @@ -73,34 +81,38 @@ BOOL LLDirPicker::getDir(std::string* filename) } BOOL success = FALSE; - BROWSEINFO bi; - memset(&bi, 0, sizeof(bi)); + BROWSEINFO bi; + memset(&bi, 0, sizeof(bi)); - bi.ulFlags = BIF_USENEWUI; - bi.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); - bi.lpszTitle = NULL; + bi.ulFlags = BIF_USENEWUI; + bi.hwndOwner = (HWND)gViewerWindow->getPlatformWindow(); + bi.lpszTitle = NULL; + llutf16string tstring = utf8str_to_utf16str(folder); + bi.lParam = (LPARAM)tstring.c_str(); + bi.lpfn = &BrowseCallbackProc; - ::OleInitialize(NULL); + ::OleInitialize(NULL); - LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi); + PLS_FLUSH; + LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi); - if(pIDL != NULL) - { - WCHAR buffer[_MAX_PATH] = {'\0'}; + if(pIDL != NULL) + { + WCHAR buffer[_MAX_PATH] = {'\0'}; - if(::SHGetPathFromIDList(pIDL, buffer) != 0) - { - // Set the string value. + if(::SHGetPathFromIDList(pIDL, buffer) != 0) + { + // Set the string value. - mDir = utf16str_to_utf8str(llutf16string(buffer)); - success = TRUE; - } + mDir = utf16str_to_utf8str(llutf16string(buffer)); + success = TRUE; + } - // free the item id list - CoTaskMemFree(pIDL); - } + // free the item id list + CoTaskMemFree(pIDL); + } - ::OleUninitialize(); + ::OleUninitialize(); return success; } @@ -147,9 +159,9 @@ pascal void LLDirPicker::doNavCallbackEvent(NavEventCallbackMessage callBackSele //Convert string to a FSSpec FSRef myFSRef; - const char* filename=sInstance.mFileName->c_str(); + const char* folder = sInstance.mFileName->c_str(); - error = FSPathMakeRef ((UInt8*)filename, &myFSRef, NULL); + error = FSPathMakeRef ((UInt8*)folder, &myFSRef, NULL); if (error != noErr) break; @@ -185,7 +197,10 @@ OSStatus LLDirPicker::doNavChooseDialog() gViewerWindow->mWindow->beforeDialog(); if (error == noErr) + { + PLS_FLUSH; error = NavDialogRun(navRef); + } gViewerWindow->mWindow->afterDialog(); @@ -216,13 +231,13 @@ OSStatus LLDirPicker::doNavChooseDialog() return error; } -BOOL LLDirPicker::getDir(std::string* filename) +BOOL LLDirPicker::getDir(std::string const& folder) { if( mLocked ) return FALSE; BOOL success = FALSE; OSStatus error = noErr; - mFileName = filename; + mFileName = folder; // mNavOptions.saveFileName @@ -266,14 +281,15 @@ void LLDirPicker::reset() LLFilePickerBase::reset(); } -BOOL LLDirPicker::getDir(std::string* filename) +BOOL LLDirPicker::getDir(std::string const& folder) { reset(); - GtkWindow* picker = buildFilePicker(false, true, "dirpicker"); + GtkWindow* picker = buildFilePicker(false, true, folder); if (picker) { gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("choose_the_directory").c_str()); gtk_widget_show_all(GTK_WIDGET(picker)); + PLS_FLUSH; gtk_main(); return (!getFirstFile().empty()); } @@ -301,7 +317,7 @@ void LLDirPicker::reset() { } -BOOL LLDirPicker::getDir(std::string* filename) +BOOL LLDirPicker::getDir(std::string* folder) { return FALSE; } diff --git a/indra/plugins/filepicker/lldirpicker.h b/indra/plugins/filepicker/lldirpicker.h index cdee1d094..034bcdf91 100644 --- a/indra/plugins/filepicker/lldirpicker.h +++ b/indra/plugins/filepicker/lldirpicker.h @@ -71,7 +71,7 @@ public: // calling this before main() is undefined static LLDirPicker& instance( void ) { return sInstance; } - BOOL getDir(std::string* filename); + BOOL getDir(std::string const& filename); std::string getDirName(); // clear any lists of buffers or whatever, and make sure the dir diff --git a/indra/plugins/filepicker/llfilepicker.cpp b/indra/plugins/filepicker/llfilepicker.cpp index 48069e88c..066a8340c 100644 --- a/indra/plugins/filepicker/llfilepicker.cpp +++ b/indra/plugins/filepicker/llfilepicker.cpp @@ -205,7 +205,6 @@ bool LLFilePickerBase::setupFilter(ELoadFilter filter) return res; } -// AIFIXME: Use folder bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { if( mLocked ) @@ -214,9 +213,9 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder } bool success = FALSE; - // don't provide default file selection + llutf16string tstring = utf8str_to_utf16str(folder); + mOFN.lpstrInitialDir = (LPCTSTR)tstring.data(); mFilesW[0] = '\0'; - mOFN.lpstrFile = mFilesW; mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; mOFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ; @@ -237,7 +236,6 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder return success; } -// AIFIXME: Use folder bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) { if( mLocked ) @@ -246,9 +244,9 @@ bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string cons } bool success = FALSE; - // don't provide default file selection + llutf16string tstring = utf8str_to_utf16str(folder); + mOFN.lpstrInitialDir = (LPCTSTR)tstring.data(); mFilesW[0] = '\0'; - mOFN.lpstrFile = mFilesW; mOFN.nFilterIndex = 1; mOFN.nMaxFile = FILENAME_BUFFER_SIZE; @@ -295,7 +293,6 @@ bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string cons return success; } -// AIFIXME: Use folder bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) { if( mLocked ) @@ -304,11 +301,13 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena } bool success = FALSE; + llutf16string tstring = utf8str_to_utf16str(folder); + mOFN.lpstrInitialDir = (LPCTSTR)tstring.data(); mOFN.lpstrFile = mFilesW; if (!filename.empty()) { llutf16string tstring = utf8str_to_utf16str(filename); - wcsncpy(mFilesW, tstring.c_str(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ + wcsncpy(mFilesW, tstring.data(), FILENAME_BUFFER_SIZE); } /*Flawfinder: ignore*/ else { mFilesW[0] = '\0'; @@ -705,8 +704,9 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode) { + LLFilePickerBase* picker = (LLFilePickerBase*)callBackUD; Boolean result = true; - ELoadFilter filter = *((ELoadFilter*) callBackUD); + ELoadFilter filter = picker->getLoadFilter(); OSStatus error = noErr; if (filterMode == kNavFilteringBrowserList && filter != FFLOAD_ALL && (theItem->descriptorType == typeFSRef || theItem->descriptorType == typeFSS)) @@ -788,7 +788,7 @@ Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *c } else if (filter == FFLOAD_RAW) { - if (fileInfo.filetype != '\?\?\?\?' && + if (fileInfo.filetype != L'\?\?\?\?' && (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("raw"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) ) { @@ -809,23 +809,70 @@ Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *c return result; } -OSStatus LLFilePickerBase::doNavChooseDialog(ELoadFilter filter) +//static +pascal void LLFilePickerBase::doNavCallbackEvent(NavEventCallbackMessage callBackSelector, + NavCBRecPtr callBackParms, void* callBackUD) +{ + switch(callBackSelector) + { + case kNavCBStart: + { + LLFilePickerBase* picker = reinterpret_cast(callBackUD); + if (picker->getFolder().empty()) break; + + OSStatus error = noErr; + AEDesc theLocation = {typeNull, NULL}; + FSSpec outFSSpec; + + //Convert string to a FSSpec + FSRef myFSRef; + + const char* folder = picker->getFolder().c_str(); + + error = FSPathMakeRef ((UInt8*)folder, &myFSRef, NULL); + + if (error != noErr) break; + + error = FSGetCatalogInfo (&myFSRef, kFSCatInfoNone, NULL, NULL, &outFSSpec, NULL); + + if (error != noErr) break; + + error = AECreateDesc(typeFSS, &outFSSpec, sizeof(FSSpec), &theLocation); + + if (error != noErr) break; + + error = NavCustomControl(callBackParms->context, + kNavCtlSetLocation, (void*)&theLocation); + + } + } +} + +OSStatus LLFilePickerBase::doNavChooseDialog(ELoadFilter filter, std::string const& folder) { OSStatus error = noErr; NavDialogRef navRef = NULL; NavReplyRecord navReply; memset(&navReply, 0, sizeof(navReply)); + + mLoadFilter = filter; + mFolder = folder; + + NavEventUPP eventProc = NewNavEventUPP(doNavCallbackEvent); // NOTE: we are passing the address of a local variable here. // This is fine, because the object this call creates will exist for less than the lifetime of this function. // (It is destroyed by NavDialogDispose() below.) - error = NavCreateChooseFileDialog(&mNavOptions, NULL, NULL, NULL, navOpenFilterProc, (void*)(&filter), &navRef); + error = NavCreateChooseFileDialog(&mNavOptions, NULL, eventProc, NULL, navOpenFilterProc, (void*)this, &navRef); //gViewerWindow->mWindow->beforeDialog(); if (error == noErr) + { + PLS_FLUSH; error = NavDialogRun(navRef); + } //gViewerWindow->mWindow->afterDialog(); @@ -860,11 +907,14 @@ OSStatus LLFilePickerBase::doNavChooseDialog(ELoadFilter filter) mFiles.push_back(std::string(path)); } } + + if (eventProc) + DisposeNavEventUPP(eventProc); return error; } -OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, const std::string& filename) +OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, std::string const& filename, std::string const& folder) { OSStatus error = noErr; NavDialogRef navRef = NULL; @@ -905,46 +955,49 @@ OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, const std::string extension = CFSTR(".png"); break; case FFSAVE_AVI: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; + type = L'\?\?\?\?'; + creator = L'\?\?\?\?'; extension = CFSTR(".mov"); break; case FFSAVE_ANIM: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; + type = L'\?\?\?\?'; + creator = L'\?\?\?\?'; extension = CFSTR(".xaf"); break; #ifdef _CORY_TESTING case FFSAVE_GEOMETRY: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; + type = L'\?\?\?\?'; + creator = L'\?\?\?\?'; extension = CFSTR(".slg"); break; #endif case FFSAVE_RAW: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; + type = L'\?\?\?\?'; + creator = L'\?\?\?\?'; extension = CFSTR(".raw"); break; case FFSAVE_J2C: - type = '\?\?\?\?'; + type = L'\?\?\?\?'; creator = 'prvw'; extension = CFSTR(".j2c"); break; case FFSAVE_ALL: default: - type = '\?\?\?\?'; - creator = '\?\?\?\?'; + type = L'\?\?\?\?'; + creator = L'\?\?\?\?'; extension = CFSTR(""); break; } + + NavEventUPP eventUPP = NewNavEventUPP(navSetDefaultFolderProc); + mFolder = folder; // Create the dialog - error = NavCreatePutFileDialog(&mNavOptions, type, creator, NULL, NULL, &navRef); + error = NavCreatePutFileDialog(&mNavOptions, type, creator, eventUPP, (void*)this, &navRef); if (error == noErr) { CFStringRef nameString = NULL; @@ -981,7 +1034,10 @@ OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, const std::string // Run the dialog if (error == noErr) + { + PLS_FLUSH; error = NavDialogRun(navRef); + } //gViewerWindow->mWindow->afterDialog(); @@ -1033,10 +1089,12 @@ OSStatus LLFilePickerBase::doNavSaveDialog(ESaveFilter filter, const std::string } } + if (eventUPP) + DisposeNavEventUPP(eventUPP); + return error; } -// AIFIXME: Use folder bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { if( mLocked ) @@ -1050,7 +1108,7 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; { - error = doNavChooseDialog(filter); + error = doNavChooseDialog(filter, folder); } if (error == noErr) { @@ -1061,7 +1119,6 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder return success; } -// AIFIXME: Use folder bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string const& folder) { if( mLocked ) @@ -1075,7 +1132,7 @@ bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string cons mNavOptions.optionFlags |= kNavAllowMultipleFiles; { - error = doNavChooseDialog(filter); + error = doNavChooseDialog(filter, folder); } if (error == noErr) { @@ -1088,7 +1145,6 @@ bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string cons return success; } -// AIFIXME: Use folder bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filename, std::string const& folder) { if( mLocked ) @@ -1101,7 +1157,7 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; { - error = doNavSaveDialog(filter, filename); + error = doNavSaveDialog(filter, filename, folder); } if (error == noErr) { @@ -1203,6 +1259,7 @@ GtkWindow* LLFilePickerBase::buildFilePicker(bool is_save, bool is_folder, std:: if (!folder.empty()) { + PLS_DEBUGS << "Calling gtk_file_chooser_set_current_folder(\"" << folder << "\")." << PLS_ENDL; gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(win), folder.c_str()); @@ -1225,6 +1282,7 @@ GtkWindow* LLFilePickerBase::buildFilePicker(bool is_save, bool is_folder, std:: G_CALLBACK(LLFilePickerBase::chooser_responder), this); + PLS_FLUSH; gtk_window_set_modal(GTK_WINDOW(win), TRUE); /* GTK 2.6: if (is_folder) @@ -1383,6 +1441,7 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena } gtk_widget_show_all(GTK_WIDGET(picker)); + PLS_FLUSH; gtk_main(); rtn = (getFileCount() == 1); @@ -1430,6 +1489,7 @@ bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); gtk_widget_show_all(GTK_WIDGET(picker)); + PLS_FLUSH; gtk_main(); rtn = (getFileCount() == 1); @@ -1458,6 +1518,7 @@ bool LLFilePickerBase::getMultipleLoadFiles(ELoadFilter filter, std::string cons gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); gtk_widget_show_all(GTK_WIDGET(picker)); + PLS_FLUSH; gtk_main(); rtn = !mFiles.empty(); } @@ -1485,7 +1546,6 @@ bool LLFilePickerBase::getSaveFile(ESaveFilter filter, std::string const& filena return FALSE; } -// AIFIXME: Use folder bool LLFilePickerBase::getLoadFile(ELoadFilter filter, std::string const& folder) { reset(); diff --git a/indra/plugins/filepicker/llfilepicker.h b/indra/plugins/filepicker/llfilepicker.h index f8e17719e..9c8db8e8a 100644 --- a/indra/plugins/filepicker/llfilepicker.h +++ b/indra/plugins/filepicker/llfilepicker.h @@ -166,6 +166,9 @@ private: OSStatus doNavChooseDialog(ELoadFilter filter); OSStatus doNavSaveDialog(ESaveFilter filter, const std::string& filename); static Boolean navOpenFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode); + static pascal void LLFilePickerBase::doNavCallbackEvent(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, void* callBackUD); + ELoadFilter getLoadFilter(void) const { return mLoadFilter; } + std::string const& getFolder(void) const { return mFolder; } #endif // LL_DARWIN #if LL_GTK @@ -194,7 +197,11 @@ private: S32 mCurrentFile; bool mLocked; bool mMultiFile; - +#if LL_DARWIN + ELoadFilter mLoadFilter; + std::string mFolder; +#endif + protected: #if LL_GTK GtkWindow* buildFilePicker(bool is_save, bool is_folder, std::string const& folder); From b6446cad10508dfee32e68e47cbaed0d93cf6dbd Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 12 May 2011 16:13:04 -0500 Subject: [PATCH 18/87] A stability and leak fix regarding editing physics wearables. Thanks Henri! --- indra/newview/llfloatercustomize.cpp | 14 +++++++++----- indra/newview/llfloatercustomize.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 6a313c2bd..3d1413c60 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -1386,14 +1386,18 @@ LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, else { //Kill everything that isn't the slider... - for(child_list_t::const_iterator it = getChildList()->begin();it!=getChildList()->end();) + child_list_t to_remove; + child_list_t::const_iterator it; + for (it = getChildList()->begin(); it != getChildList()->end(); it++) { - if((*it)!=slider && (*it)->getName() != "panel border") + if ((*it) != slider && (*it)->getName() != "panel border") { - llinfos << "removing: " << (*it)->getName() << llendl; - removeChild((*(it++)),TRUE); + to_remove.push_back(*it); } - else ++it; + } + for (it = to_remove.begin(); it != to_remove.end(); it++) + { + removeChild(*it, TRUE); } slider->translate(0,PARAM_HINT_HEIGHT); reshape(getRect().getWidth(),getRect().getHeight()-PARAM_HINT_HEIGHT); diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index ceb49af01..1b4bed74d 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -128,7 +128,7 @@ protected: LLScrollingPanelList* mScrollingPanelList; LLScrollableContainerView* mScrollContainer; - LLVisualParamReset* mResetParams; + LLPointer mResetParams; LLInventoryObserver* mInventoryObserver; From f45c3e2b1f9dab7b5c1c0a29997bd28dd8c7b880 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 12 May 2011 17:53:41 -0500 Subject: [PATCH 19/87] Setting the correct variable on Physics LOD setting change sounds like a good idea. --- indra/newview/llviewercontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index f52e1703a..e7b6e535c 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -224,7 +224,7 @@ static bool handleAvatarLODChanged(const LLSD& newvalue) static bool handleAvatarPhysicsLODChanged(const LLSD& newvalue) { - LLVOAvatar::sLODFactor = (F32) newvalue.asReal(); + LLVOAvatar::sPhysicsLODFactor = (F32) newvalue.asReal(); return true; } From 9e2db6bc400c36933c747b6b7219359e740244fb Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 12 May 2011 18:55:26 -0500 Subject: [PATCH 20/87] General cleanup --- indra/newview/llflexibleobject.cpp | 1 - indra/newview/llhudobject.h | 1 - indra/newview/llhudrender.cpp | 1 - indra/newview/llhudtext.cpp | 1 - indra/newview/llselectmgr.cpp | 12 ++++++------ 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 091c2b82b..a385b6f5f 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -39,7 +39,6 @@ #include "llglheaders.h" #include "llrendersphere.h" #include "llviewerobject.h" -#include "llimagegl.h" #include "llagent.h" #include "llsky.h" #include "llviewercamera.h" diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h index 84c2f84ac..5306f9a00 100644 --- a/indra/newview/llhudobject.h +++ b/indra/newview/llhudobject.h @@ -106,7 +106,6 @@ protected: ~LLHUDObject(); virtual void render() = 0; - virtual void renderForSelect() {}; virtual void renderForTimer() {}; protected: diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp index 62ac19671..56fb13c87 100644 --- a/indra/newview/llhudrender.cpp +++ b/indra/newview/llhudrender.cpp @@ -40,7 +40,6 @@ #include "v3math.h" #include "llquaternion.h" #include "llfontgl.h" -#include "llimagegl.h" #include "llglheaders.h" #include "llviewerwindow.h" diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 0d4bca83d..f824939ec 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -45,7 +45,6 @@ #include "llfontgl.h" #include "llglheaders.h" #include "llhudrender.h" -#include "llimagegl.h" #include "llui.h" #include "llviewercamera.h" #include "llviewertexturelist.h" diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index bbfd90177..0ca376345 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -4917,13 +4917,13 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) // set up transform to encompass bounding box of HUD glMatrixMode(GL_PROJECTION); - glPushMatrix(); + gGL.pushMatrix(); glLoadIdentity(); F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); glOrtho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth); glMatrixMode(GL_MODELVIEW); - glPushMatrix(); + gGL.pushMatrix(); glLoadIdentity(); glLoadMatrixf(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f); @@ -5007,10 +5007,10 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) if (isAgentAvatarValid() && for_hud) { glMatrixMode(GL_PROJECTION); - glPopMatrix(); + gGL.popMatrix(); glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + gGL.popMatrix(); stop_glerror(); } @@ -5349,7 +5349,7 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) } glMatrixMode(GL_MODELVIEW); - glPushMatrix(); + gGL.pushMatrix(); if (!is_hud_object) { glLoadIdentity(); @@ -5468,7 +5468,7 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) gGL.end(); gGL.flush(); } - glPopMatrix(); + gGL.popMatrix(); } // From 534e1ae7330d7c33a3940bcce56739047ee31392 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 12 May 2011 18:59:05 -0500 Subject: [PATCH 21/87] DeferredHighPrecision test setting to test 16bit framebuffers vs 32bit --- indra/newview/pipeline.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 66d459501..1be71fbe2 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -514,7 +514,8 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) if (LLPipeline::sRenderDeferred) { //allocate deferred rendering color buffers - const GLuint format = GL_RGBA; //GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later + static const LLCachedControl shadow_precision("DeferredHighPrecision",true); + const GLuint format = shadow_precision ? GL_RGBA : GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later mDeferredScreen.allocate(resX, resY, format, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE); mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); addDeferredAttachments(mDeferredScreen); @@ -566,7 +567,8 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) { if (LLPipeline::sRenderDeferred) { - const GLuint format = GL_RGBA; //GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later + static const LLCachedControl shadow_precision("DeferredHighPrecision",true); + const GLuint format = shadow_precision ? GL_RGBA : GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later mSampleBuffer.allocate(resX,resY,format,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples); addDeferredAttachments(mSampleBuffer); mDeferredScreen.setSampleBuffer(&mSampleBuffer); @@ -8767,7 +8769,8 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) { if (LLPipeline::sRenderDeferred) { - const GLuint format = GL_RGBA; //GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later + static const LLCachedControl shadow_precision("DeferredHighPrecision",true); + const GLuint format = shadow_precision ? GL_RGBA : GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later avatar->mImpostor.allocate(resX,resY,format,TRUE,TRUE); addDeferredAttachments(avatar->mImpostor); } From ea2cc3e0dedc262b0ff760495c7de44092963b58 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 13 May 2011 23:50:56 +0200 Subject: [PATCH 22/87] Make FilePicker context sensitive default paths persistent over logins. Also, make newview/statemachine a separate project. --- indra/CMakeLists.txt | 1 + indra/cmake/AIStateMachine.cmake | 4 ++ indra/llcommon/llstl.h | 1 + indra/llplugin/llpluginclassmedia.h | 7 +- indra/newview/CMakeLists.txt | 15 +---- indra/newview/llappviewer.cpp | 4 ++ indra/newview/llstartup.cpp | 7 ++ indra/newview/llviewercontrol.cpp | 10 +++ indra/newview/llviewercontrol.h | 7 +- indra/newview/llviewerpluginmanager.cpp | 10 +++ indra/newview/llviewerpluginmanager.h | 11 ++- indra/newview/statemachine/CMakeLists.txt | 41 ++++++++++++ indra/newview/statemachine/aifilepicker.cpp | 67 +++++++++++++++++-- indra/newview/statemachine/aifilepicker.h | 7 +- indra/newview/statemachine/aistatemachine.cpp | 9 +-- indra/newview/statemachine/aistatemachine.h | 1 + 16 files changed, 168 insertions(+), 34 deletions(-) create mode 100644 indra/cmake/AIStateMachine.cmake create mode 100644 indra/newview/statemachine/CMakeLists.txt diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 55e2c1e87..c0e8dc408 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -106,6 +106,7 @@ if (VIEWER) add_dependencies(viewer solaris-crash-logger) endif (LINUX) + add_subdirectory(${VIEWER_PREFIX}newview/statemachine) add_subdirectory(${VIEWER_PREFIX}newview) add_dependencies(viewer secondlife-bin) endif (VIEWER) diff --git a/indra/cmake/AIStateMachine.cmake b/indra/cmake/AIStateMachine.cmake new file mode 100644 index 000000000..c1bda40c4 --- /dev/null +++ b/indra/cmake/AIStateMachine.cmake @@ -0,0 +1,4 @@ +# -*- cmake -*- + +set(AISTATEMACHINE_INCLUDE_DIRS statemachine) +set(AISTATEMACHINE_LIBRARIES statemachine) diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 788617953..18842f276 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -39,6 +39,7 @@ #include #include #include +#include "stdtypes.h" // llcommon/stdtypes.h, needed for S32 and U32. // Use to compare the first element only of a pair // e.g. typedef std::set, compare_pair > some_pair_set_t; diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 1996c6588..2882de180 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -37,7 +37,6 @@ #define LL_LLPLUGINCLASSMEDIA_H #include "llpluginclassbasic.h" -#include "llgltypes.h" #include "llrect.h" #include "v4color.h" @@ -232,9 +231,9 @@ protected: bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true S32 mRequestedTextureDepth; - LLGLenum mRequestedTextureInternalFormat; - LLGLenum mRequestedTextureFormat; - LLGLenum mRequestedTextureType; + U32 mRequestedTextureInternalFormat; + U32 mRequestedTextureFormat; + U32 mRequestedTextureType; bool mRequestedTextureSwapBytes; bool mRequestedTextureCoordsOpenGL; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 340989a05..2b4a4ca31 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -22,6 +22,7 @@ include(LLInventory) include(LLMath) include(LLMessage) include(LLPlugin) +include(AIStateMachine) include(LLPrimitive) include(LLRender) include(LLUI) @@ -43,6 +44,7 @@ if (WINDOWS) endif (WINDOWS) include_directories( + ${CMAKE_SOURCE_DIR}/newview ${DBUSGLIB_INCLUDE_DIRS} ${HUNSPELL_INCLUDE_DIR} ${ELFIO_INCLUDE_DIR} @@ -1006,18 +1008,6 @@ set(viewer_HEADER_FILES source_group("CMake Rules" FILES ViewerInstall.cmake) -set(statemachine_SOURCE_FILES - statemachine/aistatemachine.cpp - statemachine/aifilepicker.cpp - ) -set(statemachine_HEADER_FILES - statemachine/aistatemachine.h - statemachine/aifilepicker.h - statemachine/aidirpicker.h - ) -list(APPEND viewer_SOURCE_FILES ${statemachine_SOURCE_FILES}) -list(APPEND viewer_HEADER_FILES ${statemachine_HEADER_FILES}) - if (DARWIN) LIST(APPEND viewer_SOURCE_FILES llappviewermacosx.cpp) @@ -1434,6 +1424,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLINVENTORY_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${LLPLUGIN_LIBRARIES} + ${AISTATEMACHINE_LIBRARIES} ${LLPRIMITIVE_LIBRARIES} ${LLRENDER_LIBRARIES} ${FREETYPE_LIBRARIES} diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 420a9ae67..a2a4ed386 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -72,6 +72,7 @@ #include "llmutelist.h" #include "llurldispatcher.h" #include "llurlhistory.h" +#include "statemachine/aifilepicker.h" #include "llfirstuse.h" #include "llrender.h" #include "llfont.h" @@ -1353,6 +1354,9 @@ bool LLAppViewer::cleanup() // Save URL history file LLURLHistory::saveFile("url_history.xml"); + // Save file- and dirpicker {context, default paths} map. + AIFilePicker::saveFile("filepicker_contexts.xml"); + // save mute list. gMuteList used to also be deleted here too. LLMuteList::getInstance()->cache(gAgent.getID()); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index e08bc301a..07c8de068 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -54,6 +54,7 @@ #include "hippogridmanager.h" #include "hippolimits.h" #include "floaterao.h" +#include "statemachine/aifilepicker.h" #include "llares.h" #include "llcachename.h" @@ -636,6 +637,12 @@ bool idle_startup() LLStartUp::handleSocksProxy(false); + //------------------------------------------------- + // Load file- and dirpicker {context, default path} map. + //------------------------------------------------- + + AIFilePicker::loadFile("filepicker_contexts.xml"); + //------------------------------------------------- // Init audio, which may be needed for prefs dialog // or audio cues in connection UI. diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index de65b97af..c5889106f 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -810,6 +810,16 @@ template <> eControlType get_control_type(const LLSD& in, LLSD& out) return TYPE_LLSD; } +void onCommitControlSetting_gSavedSettings(LLUICtrl* ctrl, void* name) +{ + gSavedSettings.setValue((const char*)name,ctrl->getValue()); +} + +void onCommitControlSetting_gSavedPerAccountSettings(LLUICtrl* ctrl, void* name) +{ + gSavedPerAccountSettings.setValue((const char*)name,ctrl->getValue()); +} + #if TEST_CACHED_CONTROL #define DECL_LLCC(T, V) static LLCachedControl mySetting_##T("TestCachedControl"#T, V) diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h index 8835146ad..f22f96f27 100644 --- a/indra/newview/llviewercontrol.h +++ b/indra/newview/llviewercontrol.h @@ -35,9 +35,10 @@ #include #include "llcontrol.h" -#include "lluictrl.h" #include "aithreadsafe.h" +class LLUICtrl; + // Enabled this definition to compile a 'hacked' viewer that // allows a hacked godmode to be toggled on and off. #define TOGGLE_HACKED_GODLIKE_VIEWER @@ -75,8 +76,8 @@ bool handleCloudSettingsChanged(const LLSD& newvalue); //A template would be a little awkward to use here.. so.. a preprocessor macro. Alas. onCommitControlSetting(gSavedSettings) etc. -inline void onCommitControlSetting_gSavedSettings(LLUICtrl* ctrl, void* name) {gSavedSettings.setValue((const char*)name,ctrl->getValue());} -inline void onCommitControlSetting_gSavedPerAccountSettings(LLUICtrl* ctrl, void* name) {gSavedPerAccountSettings.setValue((const char*)name,ctrl->getValue());} +void onCommitControlSetting_gSavedSettings(LLUICtrl* ctrl, void* name); +void onCommitControlSetting_gSavedPerAccountSettings(LLUICtrl* ctrl, void* name); #define onCommitControlSetting(controlgroup) onCommitControlSetting_##controlgroup //#define TEST_CACHED_CONTROL 1 diff --git a/indra/newview/llviewerpluginmanager.cpp b/indra/newview/llviewerpluginmanager.cpp index 58ee33585..fdd48736e 100644 --- a/indra/newview/llviewerpluginmanager.cpp +++ b/indra/newview/llviewerpluginmanager.cpp @@ -32,6 +32,7 @@ #include "llviewerprecompiledheaders.h" #include "llviewerpluginmanager.h" +#include "llnotifications.h" void LLViewerPluginManager::destroyPlugin() { @@ -54,3 +55,12 @@ void LLViewerPluginManager::update() return; } } + +void LLViewerPluginManager::send_plugin_failure_warning(std::string const& plugin_basename) +{ + LL_WARNS("Plugin") << "plugin intialization failed for plugin: " << plugin_basename << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = plugin_basename; // FIXME: Use different notification. + LLNotifications::instance().add("NoPlugin", args); +} + diff --git a/indra/newview/llviewerpluginmanager.h b/indra/newview/llviewerpluginmanager.h index b56d11eee..6525a5403 100644 --- a/indra/newview/llviewerpluginmanager.h +++ b/indra/newview/llviewerpluginmanager.h @@ -39,7 +39,6 @@ #include "lldir.h" #include "llfile.h" #include "llviewercontrol.h" -#include "llnotifications.h" #include "llpluginclassbasic.h" class LLViewerPluginManager : public LLRefCount @@ -65,6 +64,10 @@ public: // Return pointer to plugin. LLPluginClassBasic* getPlugin(void) const { return mPluginBase; } +private: + // Called from createPlugin. + void send_plugin_failure_warning(std::string const& plugin_basename); + protected: LLPluginClassBasic* mPluginBase; //!< Pointer to the base class of the underlaying plugin. }; @@ -104,11 +107,7 @@ LLPluginClassBasic* LLViewerPluginManager::createPlugin(T* user_data) if (mPluginBase) return mPluginBase; - LL_WARNS("Plugin") << "plugin intialization failed for plugin: " << PLUGIN_TYPE::plugin_basename() << LL_ENDL; - LLSD args; - args["MIME_TYPE"] = PLUGIN_TYPE::plugin_basename(); // FIXME: Use different notification. - LLNotifications::instance().add("NoPlugin", args); - + send_plugin_failure_warning(PLUGIN_TYPE::plugin_basename()); return NULL; } diff --git a/indra/newview/statemachine/CMakeLists.txt b/indra/newview/statemachine/CMakeLists.txt new file mode 100644 index 000000000..a7738290a --- /dev/null +++ b/indra/newview/statemachine/CMakeLists.txt @@ -0,0 +1,41 @@ +# -*- cmake -*- + +project(statemachine) + +include(00-Common) +include(LLCommon) +include(LLPlugin) +include(LLMessage) # This is needed by LLPlugin. +include(LLMath) +include(LLVFS) +include(LLXML) + +include_directories( + ${CMAKE_SOURCE_DIR}/newview + ${LLCOMMON_INCLUDE_DIRS} + ${LLPLUGIN_INCLUDE_DIRS} + ${LLMESSAGE_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLVFS_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} + ) + +set(statemachine_SOURCE_FILES + aistatemachine.cpp + aifilepicker.cpp + ) + +set(statemachine_HEADER_FILES + CMakeLists.txt + aistatemachine.h + aifilepicker.h + aidirpicker.h + ) + +set_source_files_properties(${statemachine_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND statemachine_SOURCE_FILES ${statemachine_HEADER_FILES}) + +add_library (statemachine ${statemachine_SOURCE_FILES}) +add_dependencies(statemachine prepare) diff --git a/indra/newview/statemachine/aifilepicker.cpp b/indra/newview/statemachine/aifilepicker.cpp index f8da4da86..29f83c782 100644 --- a/indra/newview/statemachine/aifilepicker.cpp +++ b/indra/newview/statemachine/aifilepicker.cpp @@ -28,14 +28,14 @@ * Initial version, written by Aleric Inglewood @ SL */ -#include "../llviewerprecompiledheaders.h" -#include "../llviewermedia.h" -#include "../lltrans.h" +#include "linden_common.h" +#include "lltrans.h" #include "llpluginclassmedia.h" #include "llpluginmessageclasses.h" +#include "llsdserialize.h" #include "aifilepicker.h" #if LL_WINDOWS -#include "../llviewerwindow.h" +#include "llviewerwindow.h" #endif #if LL_GTK && LL_X11 #include "llwindowsdl.h" @@ -456,3 +456,62 @@ std::string AIFilePicker::getFolder(void) const return gDirUtilp->getDirName(getFilename()); } +// static +bool AIFilePicker::loadFile(std::string const& filename) +{ + LLSD data; + std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); + llifstream file(filepath); + if (file.is_open()) + { + llinfos << "Loading filepicker context file at \"" << filepath << "\"." << llendl; + LLSDSerialize::fromXML(data, file); + } + + if (!data.isMap()) + { + llinfos << "File missing, ill-formed, or simply undefined; not changing the file (" << filepath << ")." << llendl; + return false; + } + + AIAccess wContextMap(sContextMap); + + for (LLSD::map_const_iterator iter = data.beginMap(); iter != data.endMap(); ++iter) + { + wContextMap->insert(context_map_type::value_type(iter->first, iter->second.asString())); + } + + return true; +} + +// static +bool AIFilePicker::saveFile(std::string const& filename) +{ + AIAccess wContextMap(sContextMap); + if (wContextMap->empty()) + return false; + + LLSD context; + + for (context_map_type::iterator iter = wContextMap->begin(); iter != wContextMap->end(); ++iter) + { + context[iter->first] = iter->second; + } + + std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); + llofstream file; + file.open(filepath.c_str()); + if (!file.is_open()) + { + llwarns << "Unable to open filepicker context file for save: \"" << filepath << "\"." << llendl; + return false; + } + + LLSDSerialize::toPrettyXML(context, file); + + file.close(); + llinfos << "Saved default paths to \"" << filepath << "\"." << llendl; + + return true; +} + diff --git a/indra/newview/statemachine/aifilepicker.h b/indra/newview/statemachine/aifilepicker.h index 91a7bc819..ee2013306 100644 --- a/indra/newview/statemachine/aifilepicker.h +++ b/indra/newview/statemachine/aifilepicker.h @@ -33,7 +33,7 @@ #include "aistatemachine.h" #include "llpluginclassmedia.h" -#include "../llviewermedia.h" +#include "llviewerpluginmanager.h" #include enum ELoadFilter @@ -165,6 +165,11 @@ public: std::string getFolder(void) const; std::vector const& getFilenames(void) const { return mFilenames; } + // Load the sContextMap from disk. + static bool loadFile(std::string const& filename); + // Save the sContextMap to disk. + static bool saveFile(std::string const& filename); + private: friend class AIPluginFilePicker; diff --git a/indra/newview/statemachine/aistatemachine.cpp b/indra/newview/statemachine/aistatemachine.cpp index ce1a4149e..2136d0eb4 100644 --- a/indra/newview/statemachine/aistatemachine.cpp +++ b/indra/newview/statemachine/aistatemachine.cpp @@ -28,17 +28,18 @@ * Initial version, written by Aleric Inglewood @ SL */ -#include "../llviewerprecompiledheaders.h" +#include "linden_common.h" #include -#include "../llcallbacklist.h" -#include "../llviewercontrol.h" - +#include "llcallbacklist.h" +#include "llcontrol.h" #include "llfasttimer.h" #include "aithreadsafe.h" #include "aistatemachine.h" +extern LLControlGroup gSavedSettings; + // Local variables. namespace { struct QueueElementComp; diff --git a/indra/newview/statemachine/aistatemachine.h b/indra/newview/statemachine/aistatemachine.h index 4b25b957d..fe3010d14 100644 --- a/indra/newview/statemachine/aistatemachine.h +++ b/indra/newview/statemachine/aistatemachine.h @@ -33,6 +33,7 @@ #include "aithreadsafe.h" #include "llfasttimer.h" +#include //! // A AIStateMachine is a base class that allows derived classes to From 4c9d9d44a45bb77a9c32671c880189bc4ea2f4eb Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 14 May 2011 01:34:27 +0200 Subject: [PATCH 23/87] Add 'Save As...' back to snapshot floater. --- indra/newview/llfloatersnapshot.cpp | 2 +- indra/newview/skins/default/xui/en-us/floater_snapshot.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 2d4ed9939..2f9539fd1 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -1404,7 +1404,7 @@ void LLFloaterSnapshot::Impl::onClickDiscard(void* data) // static void LLFloaterSnapshot::Impl::onCommitSave(LLUICtrl* ctrl, void* data) { - if (ctrl->getValue().asString() == "save as") + if (ctrl->getValue().asString() == "saveas") { gViewerWindow->resetSnapshotLoc(); } diff --git a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml index 65e7d0fae..5b86ce319 100644 --- a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml @@ -32,6 +32,7 @@ list_position="below" mouse_opaque="true" name="save_btn" tool_tip="Save image to a file" width="105"> Save + Save As...