diff --git a/.circleci/config.yml b/.circleci/config.yml index ca9105685..c3674a9e5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,12 +36,15 @@ jobs: - v1-SRB2-APT - run: name: Install SDK - command: apt-get -qq -y install git build-essential nasm libpng12-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 gettext ccache wget gcc-multilib upx + command: apt-get -qq -y --no-install-recommends install git build-essential nasm libpng12-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 gettext ccache wget gcc-multilib upx openssh-client - save_cache: key: v1-SRB2-APT paths: - /var/cache/apt/archives - checkout + - run: + name: Compile without network support + command: make -C src LINUX=1 ERRORMODE=1 -k NONET=1 - run: name: Clean build command: make -C src LINUX=1 clean diff --git a/.travis.yml b/.travis.yml index 1131bff3a..4bfc58860 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ matrix: - p7zip-full - gcc-4.4 compiler: gcc-4.4 + env: GCC44=1 #gcc-4.4 (Ubuntu/Linaro 4.4.7-8ubuntu1) 4.4.7 - os: linux addons: @@ -27,6 +28,7 @@ matrix: - p7zip-full - gcc-4.6 compiler: gcc-4.6 + env: GCC46=1 #gcc-4.6 (Ubuntu/Linaro 4.6.4-6ubuntu2) 4.6.4 - os: linux addons: @@ -39,9 +41,11 @@ matrix: - p7zip-full - gcc-4.7 compiler: gcc-4.7 + env: GCC47=1 #gcc-4.7 - os: linux compiler: gcc + env: GCC48=1 #gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 - os: linux addons: @@ -56,6 +60,7 @@ matrix: - p7zip-full - gcc-4.8 compiler: gcc-4.8 + env: GCC48=1 #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5 - os: linux addons: @@ -70,7 +75,7 @@ matrix: - p7zip-full - gcc-7 compiler: gcc-7 - env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough" + env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough" GCC72=1 #gcc-7 (Ubuntu 7.2.0-1ubuntu1~14.04) 7.2.0 20170802 - os: linux addons: @@ -85,7 +90,7 @@ matrix: - p7zip-full - gcc-8 compiler: gcc-8 - env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough -Wno-error=format-overflow" + env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough -Wno-error=format-overflow" GCC81=1 #gcc-8 (Ubuntu 7.2.0-1ubuntu1~14.04) 8.1.0 - os: linux compiler: clang diff --git a/libs/dll-binaries/i686/libgme.dll b/libs/dll-binaries/i686/libgme.dll index ddf8b0d82..9a31bc4d2 100644 Binary files a/libs/dll-binaries/i686/libgme.dll and b/libs/dll-binaries/i686/libgme.dll differ diff --git a/libs/dll-binaries/x86_64/libgme.dll b/libs/dll-binaries/x86_64/libgme.dll index 2ba99450f..598c2d71c 100644 Binary files a/libs/dll-binaries/x86_64/libgme.dll and b/libs/dll-binaries/x86_64/libgme.dll differ diff --git a/libs/gme/CMakeLists.txt b/libs/gme/CMakeLists.txt index 8beee872f..392b01856 100644 --- a/libs/gme/CMakeLists.txt +++ b/libs/gme/CMakeLists.txt @@ -4,7 +4,7 @@ project(libgme) include (CheckCXXCompilerFlag) # When version is changed, also change the one in gme/gme.h to match -set(GME_VERSION 0.6.0 CACHE INTERNAL "libgme Version") +set(GME_VERSION 0.6.2 CACHE INTERNAL "libgme Version") # 2.6+ always assumes FATAL_ERROR, but 2.4 and below don't. # Of course, 2.4 might work, in which case you're welcome to drop @@ -57,6 +57,8 @@ if (USE_GME_NSFE AND NOT USE_GME_NSF) SET(USE_GME_NSF 1 CACHE BOOL "Enable NES NSF music emulation" FORCE) endif() +option(BUILD_SHARED_LIBS "Build shared library (set to OFF for static library)" ON) + # Check for GCC "visibility" support. if (CMAKE_COMPILER_IS_GNUCXX) check_cxx_compiler_flag (-fvisibility=hidden __LIBGME_TEST_VISIBILITY) @@ -79,10 +81,10 @@ if (CMAKE_COMPILER_IS_GNUCXX) endif() endif() endif() # test visibility -endif (CMAKE_COMPILER_IS_GNUCXX) -# Cache this result -set( LIBGME_HAVE_GCC_VISIBILITY ${ENABLE_VISIBILITY} CACHE BOOL "GCC support for hidden visibility") + # Cache this result + set( LIBGME_HAVE_GCC_VISIBILITY ${ENABLE_VISIBILITY} CACHE BOOL "GCC support for hidden visibility") +endif (CMAKE_COMPILER_IS_GNUCXX) # Shared library defined here add_subdirectory(gme) diff --git a/libs/gme/changes.txt b/libs/gme/changes.txt index 62391ebb5..034ba4821 100644 --- a/libs/gme/changes.txt +++ b/libs/gme/changes.txt @@ -1,262 +1,5 @@ Game_Music_Emu Change Log ------------------------- -Game_Music_Emu 0.6.0 --------------------- - -- Note: A 0.5.6 release was referenced but never tagged or packaged. - -- SPC improvements: - - Switched to newer snes_spc 0.9.0 for SPC emulation. Uses fast DSP. - - Fixed Spc_Emu::gain(). - - Fixed support for files <0x10200 bytes. - -- Other bugfixes: - - Fixed a couple of GBS bugs, one involving access of memory after - realloc. - - Blip_Buffer works on systems where 'double' is a single-precision - floating-point type. - - Fix uninitialized buffer size in dual_resampler. - - Compilation warnings squashed out as of clang 3.3-pre and gcc 4.7.2. - -- API changes/additions: - - Removed documentation of C++ interface, as the C interface in gme.h is - the only supported one. - - Added gme_enable_accuracy() for enabling more accurate sound emulation - options (currently affects SPC only). - -- Build system improvements: - - Add pkg_config support. - - Fix build on case-insensitive systems. - - Allow for install on Cygwin. - - Fix install on multilib systems, such as many 64-bit distros (CMake must - be able to figure out your system's libsuffix, if any). - - C++ implementation symbols are not leaked into the resultant library - file (requires symbol visibility support). - -- Sample player improvements: - - Can toggle fast/accurate emulation (with the 'A' key). - -Game_Music_Emu 0.5.5 --------------------- -- CMake build support has been added. You can build Game_Music_Emu as -a shared library and install it so that you do not have to include your -own copy if you know libgme will be present on your target system. -Requires CMake 2.6 or higher. - - -Game_Music_Emu 0.5.2 --------------------- -- *TONS* of changes and improvements. You should re-read the new header -files and documentation as the changes will allow you to simplify your -code a lot (it might even be simpler to just rewrite it). Existing code -should continue to work without changes in most cases (see Deprecated -features in gme.txt). - -- New file formats: AY, HES, KSS, SAP, NSFE - -- All-new comprehensive C interface (also usable from C++). Simplifies -many things, especially file loading, and brings everything together in -one header file (gme.h). - -- Information tags and track names and times can be accessed for all -game music formats - -- New features supported by all emulators: end of track fading, -automatic silence detection, adjustable song tempo, seek to new time in -track - -- Updated mini player example to support track names and times, echo, -tempo, and channel muting, and added visual waveform display - -- Improved configuration to use blargg_config.h, which you can modify -and keep when you update to a newer libary version. Includes flag for -library to automatically handle gzipped files using zlib (so you don't -need to use Gzip_File_Reader anymore). - -- GBS: Fixed wave channel to not reset waveform when APU is powered off -(affected Garfield). Also improved invalid bank selection (affected Game -& Watch and others). - -- VGM: Added support for alternate noise shifter register -configurations, used by other systems like the BBC Micro. - -- SPC: Removed IPL ROM dump from emulator, as none of the SPC files I -scanned needed it, and an SPC file can include a copy if necessary. Also -re-enabled supposed clamping in gaussian interpolation between the third -and fourth lookups, though I don't know whether it matters - -- Added Music_Emu::load_mem() to use music data already in memory -(without copying it) - -- Added Music_Emu::warning(), which reports minor problems when loading -and playing a music file - -- Added Music_Emu::set_gain() for uniform adjustment of gain. Can only -be set during initialization, so not useful as a general volume control. - -- Added custom operator new to ensure that no exceptions are thrown in -the library (I'd use std::nothrow if it were part of pre-ISO (ARM) C++) - -- Added BLIP_BUFFER_FAST flag to blargg_config.h to use a lower quality -bandlimited synthesis in "classic" emulators, which might help -performance on ancient processors (measure first!). Don't use this -unless absolutely necessary, as quality suffers. - -- Improved performance a bit for x86 platforms - -- Text files now in DOS newline format so they will open in Notepad -properly - -- Removed requirement that file header structures not have any padding -added to the end - -- Fixed common bug in all CPU emulators where negative program counter -could crash emulator (occurred during a negative branch from the -beginning of memory). Also fixed related bug in Z80 emulator for -IX/IY+displacement mode. - -- Eliminated all warnings when compiling on gcc 4.0. The following -generates no diagnostics: - - gcc -S gme/*.cpp -o /dev/null -ansi -fno-gnu-keywords - -fno-nonansi-builtins -pedantic -W -Wabi -Wall -Wcast-align - -Wcast-qual -Wchar-subscripts -Wdisabled-optimization -Werror - -Winline -Wlong-long -Wmultichar -Winvalid-offsetof - -Wnon-virtual-dtor -Woverloaded-virtual -Wparentheses - -Wpointer-arith -Wredundant-decls -Wreorder -Wsign-compare - -Wsign-promo -Wunknown-pragmas -Wwrite-strings - - -Game_Music_Emu 0.3.0 --------------------- -- Added more demos, including music player using the SDL multimedia -library for sound, and improved documentation - -- All: Improved interface to emulators to allow simpler setup and -loading. Instead of various init() functions, all now support -set_sample_rate( long rate ) and load( const char* file_path ). - -- All: Removed error return from start_track() and play(), and added -error_count() to get the total number of emulation errors since the -track was last started. See demos for examples of new usage. - -- All: Fixed mute_voices() muting to be preserved after loading files -and starting tracks, instead of being cleared as it was whenever a track -was started - -- VGM: Rewrote Vgm_Emu to support Sega Genesis/Mega Drive FM sound at -any sample rate with optional FM oversampling, support for alternate -YM2612 sound cores, and support for optional YM2413 - -- VGM: Added tempo control, useful for slowing 60Hz NTSC Sega Genesis -music to 50Hz PAL - -- VGM: Removed Vgm_Emu::track_data(), since I realized that this -information is already present in the VGM header (oops!) - -- GYM: Changed Gym_Emu::track_length() operation (see Gym_Emu.h) - -- NSF: Added support for Sunsoft FME-7 sound chip used by Gimmick -soundtrack - -- NSF: Fixed Namco 106 problems with Final Lap and others - -- Moved library sources to gme/ directory to reduce clutter, and merged -boost/ functionality into blargg_common.h - -- Added Gzip_File_Reader for transparently using gzipped files - - -Game_Music_Emu 0.2.4 --------------------- -- Created a discussion forum for problems and feedback: -http://groups-beta.google.com/group/blargg-sound-libs - -- Changed error return value of Blip_Buffer::sample_rate() (also for -Stereo_Buffer, Effects_Buffer, etc.) to blargg_err_t (defined in -blargg_common.h), to make error reporting consistent with other -functions. This means the "no error" return value is the opposite of -what it was before, which will break current code which checks the error -return value: - - // current code (broken) - if ( !buf.sample_rate( samples_per_sec ) ) - out_of_memory(); - - // quick-and-dirty fix (just remove the ! operation) - if ( buf.sample_rate( samples_per_sec ) ) - out_of_memory(); - - // proper fix - blargg_err_t error = buf.sample_rate( samples_per_sec ); - if ( error ) - report_error( error ); - -- Implemented workaround for MSVC++ 6 compiler limitations, allowing it -to work on that compiler again - -- Added sample clamping to avoid wrap-around at high volumes, allowing -higher volume with little distortion - -- Added to-do list and design notes - -- Added Music_Emu::skip( long sample_count ) to skip ahead in current -track - -- Added Gym_Emu::track_length() and Vgm_Emu::track_length() for -determining the length of non-looped GYM and VGM files - -- Partially implemented DMC non-linearity when its value is directly set -using $4011, which reduces previously over-emphasized "popping" of -percussion on some games (TMNT II in particular) - -- Fixed Fir_Resampler, used for SPC and GYM playback (was incorrectly -using abs() instead of fabs()...argh) - -- Fixed SPC emulation bugs: eliminated clicks in Plok! soundtrack and -now stops sample slightly earlier than the end, as the SNES does. Fixed -a totally broken CPU addressing mode. - -- Fixed Konami VRC6 saw wave (was very broken before). Now VRC6 music -sounds decent - -- Fixed a minor GBS emulation bug - -- Fixed GYM loop point bug when track was restarted before loop point -had been reached - -- Made default GBS frequency equalization less muffled - -- Added pseudo-surround effect removal for SPC files - -- Added Music_Emu::voice_names() which returns names for each voice. - -- Added BLARGG_SOURCE_BEGIN which allows custom compiler options to be -easily set for library sources - -- Changed assignment of expansion sound chips in Nsf_Emu to be spread -more evenly when using Effects_Buffer - -- Changed 'size_t' values in Blip_Buffer interface to 'long' - -- Changed demo to generate a WAVE sound file rather than an AIFF file - - -Game_Music_Emu 0.2.0 --------------------- -- Redid framework and rewrote/cleaned up emulators - -- Changed licensing to GNU Lesser General Public License (LGPL) - -- Added Sega Genesis GYM and Super Nintendo SPC emulators - -- Added Namco-106 and Konami VRC6 sound chip support to NSF emulator - -- Eliminated use of static mutable data in emulators, allowing -multi-instance safety - - -Game_Music_Emu 0.1.0 --------------------- -- First release +Please see the git version history (e.g. git shortlog tags/0.6.0..tags/0.6.1) +for the accurate change log. diff --git a/libs/gme/demo/basics.c b/libs/gme/demo/basics.c index 551782518..741574afe 100644 --- a/libs/gme/demo/basics.c +++ b/libs/gme/demo/basics.c @@ -1,7 +1,5 @@ /* C example that opens a game music file and records 10 seconds to "out.wav" */ -static char filename [] = "test.nsf"; /* opens this file (can be any music type) */ - #include "gme/gme.h" #include "Wave_Writer.h" /* wave_ functions for writing sound file */ @@ -10,10 +8,15 @@ static char filename [] = "test.nsf"; /* opens this file (can be any music type) void handle_error( const char* str ); -int main() +int main(int argc, char *argv[]) { + const char *filename = "test.nsf"; /* Default file to open */ + if ( argc >= 2 ) + filename = argv[1]; + long sample_rate = 44100; /* number of samples per second */ - int track = 0; /* index of track to play (0 = first) */ + /* index of track to play (0 = first) */ + int track = argc >= 3 ? atoi(argv[2]) : 0; /* Open music file in new emulator */ Music_Emu* emu; diff --git a/libs/gme/demo/cpp_basics.cpp b/libs/gme/demo/cpp_basics.cpp index 53fab4186..5222fe271 100644 --- a/libs/gme/demo/cpp_basics.cpp +++ b/libs/gme/demo/cpp_basics.cpp @@ -1,7 +1,5 @@ // C++ example that opens a game music file and records 10 seconds to "out.wav" -static char filename [] = "test.nsf"; /* opens this file (can be any music type) */ - #include "gme/Music_Emu.h" #include "Wave_Writer.h" @@ -10,10 +8,15 @@ static char filename [] = "test.nsf"; /* opens this file (can be any music type) void handle_error( const char* str ); -int main() +int main(int argc, char *argv[]) { + const char *filename = "test.nsf"; /* Default file to open */ + if ( argc >= 2 ) + filename = argv[1]; + long sample_rate = 44100; // number of samples per second - int track = 0; // index of track to play (0 = first) + // index of track to play (0 = first) + int track = argc >= 3 ? atoi(argv[2]) : 0; // Determine file type gme_type_t file_type; diff --git a/libs/gme/gme.txt b/libs/gme/gme.txt index d9a2452c7..5a7d2f560 100644 --- a/libs/gme/gme.txt +++ b/libs/gme/gme.txt @@ -1,10 +1,10 @@ -Game_Music_Emu 0.6.0 +Game_Music_Emu 0.6.2 -------------------- -Author : Shay Green -Website: http://www.slack.net/~ant/libs/ -Forum : http://groups.google.com/group/blargg-sound-libs -Source : https://code.google.com/p/game-music-emu/ -License: GNU Lesser General Public License (LGPL) +Author : Shay Green +Maintainer : Michael Pyne +Website : https://bitbucket.org/mpyne/game-music-emu/ +Source : https://bitbucket.org/mpyne/game-music-emu/ +License : GNU Lesser General Public License (LGPL), see LICENSE.txt Contents -------- diff --git a/libs/gme/gme/CMakeLists.txt b/libs/gme/gme/CMakeLists.txt index 3c6464fc7..534be8a85 100644 --- a/libs/gme/gme/CMakeLists.txt +++ b/libs/gme/gme/CMakeLists.txt @@ -143,7 +143,7 @@ add_definitions(-DBLARGG_BUILD_DLL) include_directories(${CMAKE_CURRENT_BINARY_DIR}) # Add library to be compiled. -add_library(gme SHARED ${libgme_SRCS}) +add_library(gme ${libgme_SRCS}) # The version is the release. The "soversion" is the API version. As long # as only build fixes are performed (i.e. no backwards-incompatible changes @@ -159,4 +159,4 @@ install(TARGETS gme LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib) # DLL platforms install(FILES ${EXPORTED_HEADERS} DESTINATION include/gme) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgme.pc DESTINATION lib/pkgconfig) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgme.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig) diff --git a/libs/gme/gme/Data_Reader.cpp b/libs/gme/gme/Data_Reader.cpp index 5bbfbf551..f18928f4b 100644 --- a/libs/gme/gme/Data_Reader.cpp +++ b/libs/gme/gme/Data_Reader.cpp @@ -22,8 +22,13 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ const char Data_Reader::eof_error [] = "Unexpected end of file"; +#define RETURN_VALIDITY_CHECK( cond ) \ + do { if ( unlikely( !(cond) ) ) return "Corrupt file"; } while(0) + blargg_err_t Data_Reader::read( void* p, long s ) { + RETURN_VALIDITY_CHECK( s > 0 ); + long result = read_avail( p, s ); if ( result != s ) { @@ -38,6 +43,8 @@ blargg_err_t Data_Reader::read( void* p, long s ) blargg_err_t Data_Reader::skip( long count ) { + RETURN_VALIDITY_CHECK( count >= 0 ); + char buf [512]; while ( count ) { @@ -54,7 +61,8 @@ long File_Reader::remain() const { return size() - tell(); } blargg_err_t File_Reader::skip( long n ) { - assert( n >= 0 ); + RETURN_VALIDITY_CHECK( n >= 0 ); + if ( !n ) return 0; return seek( tell() + n ); @@ -67,13 +75,14 @@ Subset_Reader::Subset_Reader( Data_Reader* dr, long size ) in = dr; remain_ = dr->remain(); if ( remain_ > size ) - remain_ = size; + remain_ = max( 0l, size ); } long Subset_Reader::remain() const { return remain_; } long Subset_Reader::read_avail( void* p, long s ) { + s = max( 0l, s ); if ( s > remain_ ) s = remain_; remain_ -= s; @@ -85,7 +94,7 @@ long Subset_Reader::read_avail( void* p, long s ) Remaining_Reader::Remaining_Reader( void const* h, long size, Data_Reader* r ) { header = (char const*) h; - header_end = header + size; + header_end = header + max( 0l, size ); in = r; } @@ -93,6 +102,7 @@ long Remaining_Reader::remain() const { return header_end - header + in->remain( long Remaining_Reader::read_first( void* out, long count ) { + count = max( 0l, count ); long first = header_end - header; if ( first ) { @@ -107,8 +117,9 @@ long Remaining_Reader::read_first( void* out, long count ) long Remaining_Reader::read_avail( void* out, long count ) { + count = max( 0l, count ); long first = read_first( out, count ); - long second = count - first; + long second = max( 0l, count - first ); if ( second ) { second = in->read_avail( (char*) out + first, second ); @@ -120,8 +131,9 @@ long Remaining_Reader::read_avail( void* out, long count ) blargg_err_t Remaining_Reader::read( void* out, long count ) { + count = max( 0l, count ); long first = read_first( out, count ); - long second = count - first; + long second = max( 0l, count - first ); if ( !second ) return 0; return in->read( (char*) out + first, second ); @@ -131,7 +143,7 @@ blargg_err_t Remaining_Reader::read( void* out, long count ) Mem_File_Reader::Mem_File_Reader( const void* p, long s ) : begin( (const char*) p ), - size_( s ) + size_( max( 0l, s ) ) { pos = 0; } @@ -141,6 +153,7 @@ long Mem_File_Reader::size() const { return size_; } long Mem_File_Reader::read_avail( void* p, long s ) { long r = remain(); + s = max( 0l, s ); if ( s > r ) s = r; memcpy( p, begin + pos, s ); @@ -152,6 +165,7 @@ long Mem_File_Reader::tell() const { return pos; } blargg_err_t Mem_File_Reader::seek( long n ) { + RETURN_VALIDITY_CHECK( n >= 0 ); if ( n > size_ ) return eof_error; pos = n; @@ -164,7 +178,7 @@ Callback_Reader::Callback_Reader( callback_t c, long size, void* d ) : callback( c ), data( d ) { - remain_ = size; + remain_ = max( 0l, size ); } long Callback_Reader::remain() const { return remain_; } @@ -173,13 +187,14 @@ long Callback_Reader::read_avail( void* out, long count ) { if ( count > remain_ ) count = remain_; - if ( Callback_Reader::read( out, count ) ) + if ( count < 0 || Callback_Reader::read( out, count ) ) count = -1; return count; } blargg_err_t Callback_Reader::read( void* out, long count ) { + RETURN_VALIDITY_CHECK( count >= 0 ); if ( count > remain_ ) return eof_error; return callback( data, out, count ); @@ -210,11 +225,12 @@ long Std_File_Reader::size() const long Std_File_Reader::read_avail( void* p, long s ) { - return fread( p, 1, s, (FILE*) file_ ); + return fread( p, 1, max( 0l, s ), (FILE*) file_ ); } blargg_err_t Std_File_Reader::read( void* p, long s ) { + RETURN_VALIDITY_CHECK( s > 0 ); if ( s == (long) fread( p, 1, s, (FILE*) file_ ) ) return 0; if ( feof( (FILE*) file_ ) ) diff --git a/libs/gme/gme/Data_Reader.h b/libs/gme/gme/Data_Reader.h index acf571f67..6c22b678e 100644 --- a/libs/gme/gme/Data_Reader.h +++ b/libs/gme/gme/Data_Reader.h @@ -129,6 +129,8 @@ private: }; #ifdef HAVE_ZLIB_H +#include + // Gzip compressed file reader class Gzip_File_Reader : public File_Reader { public: @@ -143,7 +145,7 @@ public: long tell() const; blargg_err_t seek( long ); private: - void* file_; + gzFile file_; long size_; }; #endif diff --git a/libs/gme/gme/Music_Emu.cpp b/libs/gme/gme/Music_Emu.cpp index 30b25dcfc..942e86e27 100644 --- a/libs/gme/gme/Music_Emu.cpp +++ b/libs/gme/gme/Music_Emu.cpp @@ -178,6 +178,11 @@ blargg_long Music_Emu::msec_to_samples( blargg_long msec ) const return (sec * sample_rate() + msec * sample_rate() / 1000) * stereo; } +long Music_Emu::tell_samples() const +{ + return out_time; +} + long Music_Emu::tell() const { blargg_long rate = sample_rate() * stereo; @@ -185,14 +190,18 @@ long Music_Emu::tell() const return sec * 1000 + (out_time - sec * rate) * 1000 / rate; } -blargg_err_t Music_Emu::seek( long msec ) +blargg_err_t Music_Emu::seek_samples( long time ) { - blargg_long time = msec_to_samples( msec ); if ( time < out_time ) RETURN_ERR( start_track( current_track_ ) ); return skip( time - out_time ); } +blargg_err_t Music_Emu::seek( long msec ) +{ + return seek_samples( msec_to_samples( msec ) ); +} + blargg_err_t Music_Emu::skip( long count ) { require( current_track() >= 0 ); // start_track() must have been called already diff --git a/libs/gme/gme/Music_Emu.h b/libs/gme/gme/Music_Emu.h index b96f4b611..d98f7ce7e 100644 --- a/libs/gme/gme/Music_Emu.h +++ b/libs/gme/gme/Music_Emu.h @@ -41,9 +41,15 @@ public: // Number of milliseconds (1000 msec = 1 second) played since beginning of track long tell() const; + // Number of samples generated since beginning of track + long tell_samples() const; + // Seek to new time in track. Seeking backwards or far forward can take a while. blargg_err_t seek( long msec ); + // Equivalent to restarting track then skipping n samples + blargg_err_t seek_samples( long n ); + // Skip n samples blargg_err_t skip( long n ); diff --git a/libs/gme/gme/Nsfe_Emu.cpp b/libs/gme/gme/Nsfe_Emu.cpp index 824a1a240..55ac4688f 100644 --- a/libs/gme/gme/Nsfe_Emu.cpp +++ b/libs/gme/gme/Nsfe_Emu.cpp @@ -134,6 +134,9 @@ blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu ) RETURN_ERR( in.read( block_header, sizeof block_header ) ); blargg_long size = get_le32( block_header [0] ); blargg_long tag = get_le32( block_header [1] ); + + if ( size <= 0 ) + return "Corrupt file"; //debug_printf( "tag: %c%c%c%c\n", char(tag), char(tag>>8), char(tag>>16), char(tag>>24) ); diff --git a/libs/gme/gme/Spc_Cpu.cpp b/libs/gme/gme/Spc_Cpu.cpp index 90f60ed29..19aae1135 100644 --- a/libs/gme/gme/Spc_Cpu.cpp +++ b/libs/gme/gme/Spc_Cpu.cpp @@ -433,9 +433,7 @@ void Snes_Spc::cpu_write( int data, int addr, rel_time_t time ) #endif // Registers other than $F2 and $F4-$F7 - //if ( reg != 2 && reg != 4 && reg != 5 && reg != 6 && reg != 7 ) - // TODO: this is a bit on the fragile side - if ( ((~0x2F00 << (bits_in_int - 16)) << reg) < 0 ) // 36% + if ( reg != 2 && (reg < 4 || reg > 7) ) // 36% cpu_write_smp_reg( data, time, reg ); } // High mem/address wrap-around diff --git a/libs/gme/gme/Spc_Cpu.h b/libs/gme/gme/Spc_Cpu.h index 4742e0990..10c245090 100644 --- a/libs/gme/gme/Spc_Cpu.h +++ b/libs/gme/gme/Spc_Cpu.h @@ -76,8 +76,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // TODO: remove non-wrapping versions? #define SPC_NO_SP_WRAPAROUND 0 -#define SET_SP( v ) (sp = ram + 0x101 + (v)) -#define GET_SP() (sp - 0x101 - ram) +#define SET_SP( v ) (sp = ram + 0x101 + ((uint8_t) v)) +#define GET_SP() (uint8_t (sp - 0x101 - ram)) #if SPC_NO_SP_WRAPAROUND #define PUSH16( v ) (sp -= 2, SET_LE16( sp, v )) @@ -485,7 +485,7 @@ loop: case 0xAF: // MOV (X)+,A WRITE_DP( 0, x, a + no_read_before_write ); - x++; + x = (uint8_t) (x + 1); goto loop; // 5. 8-BIT LOGIC OPERATION COMMANDS @@ -808,7 +808,7 @@ loop: unsigned temp = y * a; a = (uint8_t) temp; nz = ((temp >> 1) | temp) & 0x7F; - y = temp >> 8; + y = (uint8_t) (temp >> 8); nz |= y; goto loop; } @@ -838,6 +838,7 @@ loop: nz = (uint8_t) a; a = (uint8_t) a; + y = (uint8_t) y; goto loop; } @@ -1004,7 +1005,7 @@ loop: case 0x7F: // RET1 temp = *sp; SET_PC( GET_LE16( sp + 1 ) ); - sp += 3; + SET_SP( GET_SP() + 3 ); goto set_psw; case 0x8E: // POP PSW POP( temp ); diff --git a/libs/gme/gme/blargg_source.h b/libs/gme/gme/blargg_source.h index b011777ad..b65afd30b 100644 --- a/libs/gme/gme/blargg_source.h +++ b/libs/gme/gme/blargg_source.h @@ -18,6 +18,19 @@ all other #include lines. */ #undef require #define require( expr ) assert( expr ) +// Use to provide hints to compiler for optimized code layout in situations where we +// can almost always expect a conditional to go one way or the other. Should only be +// used in situations where an unexpected branch is truly exceptional though! +#undef likely +#undef unlikely +#ifdef __GNUC__ + #define likely( x ) __builtin_expect(x, 1) + #define unlikely( x ) __builtin_expect(x, 0) +#else + #define likely( x ) (x) + #define unlikely( x ) (x) +#endif + // Like printf() except output goes to debug log file. Might be defined to do // nothing (not even evaluate its arguments). // void debug_printf( const char* format, ... ); diff --git a/libs/gme/gme/gme.cpp b/libs/gme/gme/gme.cpp index c05f25eb4..47709840a 100644 --- a/libs/gme/gme/gme.cpp +++ b/libs/gme/gme/gme.cpp @@ -337,7 +337,9 @@ BLARGG_EXPORT gme_err_t gme_play ( Music_Emu* me, int n, short* p ) BLARGG_EXPORT void gme_set_fade ( Music_Emu* me, int start_msec ) { me->set_fade( start_msec ); } BLARGG_EXPORT int gme_track_ended ( Music_Emu const* me ) { return me->track_ended(); } BLARGG_EXPORT int gme_tell ( Music_Emu const* me ) { return me->tell(); } +BLARGG_EXPORT int gme_tell_samples ( Music_Emu const* me ) { return me->tell_samples(); } BLARGG_EXPORT gme_err_t gme_seek ( Music_Emu* me, int msec ) { return me->seek( msec ); } +BLARGG_EXPORT gme_err_t gme_seek_samples ( Music_Emu* me, int n ) { return me->seek_samples( n ); } BLARGG_EXPORT int gme_voice_count ( Music_Emu const* me ) { return me->voice_count(); } BLARGG_EXPORT void gme_ignore_silence ( Music_Emu* me, int disable ) { me->ignore_silence( disable != 0 ); } BLARGG_EXPORT void gme_set_tempo ( Music_Emu* me, double t ) { me->set_tempo( t ); } diff --git a/libs/gme/gme/gme.h b/libs/gme/gme/gme.h index 1f2a2d150..cb07061b4 100644 --- a/libs/gme/gme/gme.h +++ b/libs/gme/gme/gme.h @@ -1,6 +1,6 @@ /* Game music emulator library C interface (also usable from C++) */ -/* Game_Music_Emu 0.6.0 */ +/* Game_Music_Emu 0.6.1 */ #ifndef GME_H #define GME_H @@ -8,7 +8,7 @@ extern "C" { #endif -#define GME_VERSION 0x000600 /* 1 byte major, 1 byte minor, 1 byte patch-level */ +#define GME_VERSION 0x000601 /* 1 byte major, 1 byte minor, 1 byte patch-level */ /* Error string returned by library functions, or NULL if no error (success) */ typedef const char* gme_err_t; @@ -47,9 +47,15 @@ int gme_track_ended( Music_Emu const* ); /* Number of milliseconds (1000 = one second) played since beginning of track */ int gme_tell( Music_Emu const* ); +/* Number of samples generated since beginning of track */ +int gme_tell_samples( Music_Emu const* ); + /* Seek to new time in track. Seeking backwards or far forward can take a while. */ gme_err_t gme_seek( Music_Emu*, int msec ); +/* Equivalent to restarting track then skipping n samples */ +gme_err_t gme_seek_samples( Music_Emu*, int n ); + /******** Informational ********/ diff --git a/libs/gme/gme/libgme.pc.in b/libs/gme/gme/libgme.pc.in index 4f420d9ed..49fd5b1df 100644 --- a/libs/gme/gme/libgme.pc.in +++ b/libs/gme/gme/libgme.pc.in @@ -3,7 +3,7 @@ # later are used by pkg-config. prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} -lib_suffix= +lib_suffix=@LIB_SUFFIX@ libdir=${exec_prefix}/lib${lib_suffix} includedir=${prefix}/include @@ -13,3 +13,4 @@ URL: http://code.google.com/p/game-music-emu/ Version: @GME_VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -lgme +Libs.private: -lstdc++ diff --git a/libs/gme/include/gme/gme.h b/libs/gme/include/gme/gme.h index 1f2a2d150..cb07061b4 100644 --- a/libs/gme/include/gme/gme.h +++ b/libs/gme/include/gme/gme.h @@ -1,6 +1,6 @@ /* Game music emulator library C interface (also usable from C++) */ -/* Game_Music_Emu 0.6.0 */ +/* Game_Music_Emu 0.6.1 */ #ifndef GME_H #define GME_H @@ -8,7 +8,7 @@ extern "C" { #endif -#define GME_VERSION 0x000600 /* 1 byte major, 1 byte minor, 1 byte patch-level */ +#define GME_VERSION 0x000601 /* 1 byte major, 1 byte minor, 1 byte patch-level */ /* Error string returned by library functions, or NULL if no error (success) */ typedef const char* gme_err_t; @@ -47,9 +47,15 @@ int gme_track_ended( Music_Emu const* ); /* Number of milliseconds (1000 = one second) played since beginning of track */ int gme_tell( Music_Emu const* ); +/* Number of samples generated since beginning of track */ +int gme_tell_samples( Music_Emu const* ); + /* Seek to new time in track. Seeking backwards or far forward can take a while. */ gme_err_t gme_seek( Music_Emu*, int msec ); +/* Equivalent to restarting track then skipping n samples */ +gme_err_t gme_seek_samples( Music_Emu*, int n ); + /******** Informational ********/ diff --git a/libs/gme/readme.txt b/libs/gme/readme.txt index 82a501dbd..4cfe5e7a8 100644 --- a/libs/gme/readme.txt +++ b/libs/gme/readme.txt @@ -1,4 +1,4 @@ -Game_Music_Emu 0.6.0: Game Music Emulators +Game_Music_Emu 0.6.2: Game Music Emulators ------------------------------------------ Game_Music_Emu is a collection of video game music file emulators that support the following formats and systems: @@ -34,30 +34,45 @@ several architectures, Mac OS, MorphOS, Xbox, PlayStation Portable, GP2X, and Nintendo DS. Author : Shay Green -Website: http://www.slack.net/~ant/ -Forum : http://groups.google.com/group/blargg-sound-libs +Website: https://bitbucket.org/mpyne/game-music-emu/wiki/Home License: GNU Lesser General Public License (LGPL) +Current Maintainer: Michael Pyne Getting Started --------------- Build a program consisting of demo/basics.c, demo/Wave_Writer.cpp, and -all source files in gme/. If you have CMake 2.6 or later, execute +all source files in gme/. - run cmake - cd demo - run make +Or, if you have CMake 2.6 or later, execute at a command prompt (from the +extracted source directory): -Be sure "test.nsf" is in the same directory as the program. Running it + mkdir build + cd build + cmake ../ # <-- Pass any needed CMake flags here + make # To build the library + cd demo + make # To build the demo itself + +Be sure "test.nsf" is in the same directory as the demo program. Running it should generate the recording "out.wav". +You can use "make install" to install the library. To choose where to install +the library to, use the CMake argument "-DCMAKE_INSTALL_PREFIX=/usr/local" +(and replace /usr/local with the base path you wish to use). Alternately, you +can specify the base path to install to when you run "make install" by passing +'DESTDIR=/usr/local' on the make install command line (again, replace +/usr/local as appropriate). + +To build a static library instead of shared (the default), pass +-DBUILD_SHARED_LIBS=OFF to the cmake command when running cmake. + A slightly more extensive demo application is available in the player/ directory. It requires SDL to build. Read gme.txt for more information. Post to the discussion forum for assistance. - Files ----- gme.txt General notes about the library diff --git a/libs/gme/win32/libgme.dll.a b/libs/gme/win32/libgme.dll.a index d56d87396..2c5e95853 100644 Binary files a/libs/gme/win32/libgme.dll.a and b/libs/gme/win32/libgme.dll.a differ diff --git a/libs/gme/win64/libgme.dll.a b/libs/gme/win64/libgme.dll.a index 38079dc2a..8348f12de 100644 Binary files a/libs/gme/win64/libgme.dll.a and b/libs/gme/win64/libgme.dll.a differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4a9ef5ba8..a6fab34ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -377,6 +377,12 @@ if(${SRB2_CONFIG_HAVE_PNG} AND ${SRB2_CONFIG_HAVE_ZLIB}) set(SRB2_HAVE_PNG ON) add_definitions(-DHAVE_PNG) add_definitions(-D_LARGEFILE64_SOURCE) + set(SRB2_PNG_SOURCES apng.c) + set(SRB2_PNG_HEADERS apng.h) + prepend_sources(SRB2_PNG_SOURCES) + prepend_sources(SRB2_PNG_HEADERS) + source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS} + ${SRB2_PNG_SOURCES} ${SRB2_PNG_HEADERS}) else() message(WARNING "You have specified that PNG is available but it was not found. SRB2 may not compile correctly.") endif() diff --git a/src/Makefile b/src/Makefile index c894203a4..6363ab7dc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -338,6 +338,8 @@ endif LIBS+=$(PNG_LDFLAGS) CFLAGS+=$(PNG_CFLAGS) + +OBJS+=$(OBJDIR)/apng.o endif ifdef HAVE_LIBGME diff --git a/src/Makefile.cfg b/src/Makefile.cfg index 1238050b3..a0398154a 100644 --- a/src/Makefile.cfg +++ b/src/Makefile.cfg @@ -7,6 +7,10 @@ # and other things # +ifdef GCC81 +GCC80=1 +endif + ifdef GCC80 GCC72=1 endif @@ -116,6 +120,7 @@ WFLAGS+=-Wfloat-equal #WFLAGS+=-Wtraditional ifdef VCHELP WFLAGS+=-Wdeclaration-after-statement + WFLAGS+=-Wno-error=declaration-after-statement endif WFLAGS+=-Wundef ifndef GCC295 @@ -189,12 +194,6 @@ ifdef GCC46 WFLAGS+=-Wno-suggest-attribute=noreturn endif -ifndef MINGW -ifdef GCC45 -WFLAGS+=-Wunsuffixed-float-constants -endif -endif - ifdef NOLDWARNING LDFLAGS+=-Wl,--as-needed endif @@ -208,6 +207,9 @@ WFLAGS+=$(OLDWFLAGS) ifdef GCC43 #WFLAGS+=-Wno-error=clobbered endif +ifdef GCC44 + WFLAGS+=-Wno-error=array-bounds +endif ifdef GCC46 WFLAGS+=-Wno-error=suggest-attribute=noreturn endif @@ -228,6 +230,7 @@ ifdef GCC80 WFLAGS+=-Wno-format-overflow WFLAGS+=-Wno-stringop-truncation WFLAGS+=-Wno-stringop-overflow + WFLAGS+=-Wno-error=multistatement-macros endif diff --git a/src/android/i_sound.c b/src/android/i_sound.c index 2bb304424..b5a1c3646 100644 --- a/src/android/i_sound.c +++ b/src/android/i_sound.c @@ -96,6 +96,37 @@ boolean I_SetSongSpeed(float speed) return false; } +/// ------------------------ +// MUSIC SEEKING +/// ------------------------ + +UINT32 I_GetSongLength(void) +{ + return 0; +} + +boolean I_SetSongLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetSongLoopPoint(void) +{ + return 0; +} + +boolean I_SetSongPosition(UINT32 position) +{ + (void)position; + return false; +} + +UINT32 I_GetSongPosition(void) +{ + return 0; +} + /// ------------------------ // MUSIC PLAYBACK /// ------------------------ @@ -140,3 +171,44 @@ void I_SetMusicVolume(INT32 volume) { (void)volume; } + +/// ------------------------ +// MUSIC FADING +/// ------------------------ + +void I_SetInternalMusicVolume(UINT8 volume) +{ + (void)volume; +} + +void I_StopFadingSong(void) +{ +} + +boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void)); +{ + (void)target_volume; + (void)source_volume; + (void)ms; + return false; +} + +boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)); +{ + (void)target_volume; + (void)ms; + return false; +} + +boolean I_FadeOutStopSong(UINT32 ms) +{ + (void)ms; + return false; +} + +boolean I_FadeInPlaySong(UINT32 ms, boolean looping) +{ + (void)ms; + (void)looping; + return false; +} diff --git a/src/apng.c b/src/apng.c new file mode 100644 index 000000000..694b3d1e8 --- /dev/null +++ b/src/apng.c @@ -0,0 +1,289 @@ +/* +Copyright 2019, James R. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "apng.h" + +#define APNG_INFO_acTL 0x20000U + +#define APNG_WROTE_acTL 0x10000U + +struct apng_info_def +{ + png_uint_32 mode; + png_uint_32 valid; + + png_uint_32 num_frames; + png_uint_32 num_plays; + + long start_acTL;/* acTL is written here */ + + png_flush_ptr output_flush_fn; + apng_seek_ptr output_seek_fn; + apng_tell_ptr output_tell_fn; + + apng_set_acTL_ptr set_acTL_fn; +}; + +/* PROTOS (FUCK COMPILER) */ +void apng_seek (png_structp, apng_const_infop, size_t); +size_t apng_tell (png_structp, apng_const_infop); +#ifdef PNG_WRITE_FLUSH_SUPPORTED +void apng_flush (png_structp, apng_infop); +#ifdef PNG_STDIO_SUPPORTED +void apng_default_flush (png_structp); +#endif/* PNG_STDIO_SUPPORTED */ +#endif/* PNG_WRITE_FLUSH_SUPPORTED */ +#ifdef PNG_STDIO_SUPPORTED +void apng_default_seek (png_structp, size_t); +size_t apng_default_tell (png_structp); +#endif/* PNG_STDIO_SUPPORTED */ +void apng_write_IEND (png_structp); +void apng_write_acTL (png_structp, png_uint_32, png_uint_32); +#ifndef PNG_WRITE_APNG_SUPPORTED +png_uint_32 apng_set_acTL_dummy (png_structp, png_infop, + png_uint_32, png_uint_32); +#endif/* PNG_WRITE_APNG_SUPPORTED */ + +apng_infop +apng_create_info_struct (png_structp pngp) +{ + apng_infop ainfop; + (void)pngp; + if (( ainfop = calloc(sizeof (apng_info),1) )) + { + apng_set_write_fn(pngp, ainfop, 0, 0, 0, 0, 0); + apng_set_set_acTL_fn(pngp, ainfop, 0); + } + return ainfop; +} + +void +apng_destroy_info_struct (png_structp pngp, apng_infopp ainfopp) +{ + (void)pngp; + if (!( pngp && ainfopp )) + return; + + free((*ainfopp)); +} + +void +apng_seek (png_structp pngp, apng_const_infop ainfop, size_t l) +{ + (*(ainfop->output_seek_fn))(pngp, l); +} + +size_t +apng_tell (png_structp pngp, apng_const_infop ainfop) +{ + return (*(ainfop->output_tell_fn))(pngp); +} + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +void +apng_flush (png_structp pngp, apng_infop ainfop) +{ + if (ainfop->output_flush_fn) + (*(ainfop->output_flush_fn))(pngp); +} + +#ifdef PNG_STDIO_SUPPORTED +void +apng_default_flush (png_structp pngp) +{ + if (!( pngp )) + return; + + fflush((png_FILE_p)png_get_io_ptr); +} +#endif/* PNG_STDIO_SUPPORTED */ +#endif/* PNG_WRITE_FLUSH_SUPPORTED */ + +#ifdef PNG_STDIO_SUPPORTED +void +apng_default_seek (png_structp pngp, size_t l) +{ + if (!( pngp )) + return; + + if (fseek((png_FILE_p)png_get_io_ptr(pngp), (long)l, SEEK_SET) == -1) + png_error(pngp, "Seek Error"); +} + +size_t +apng_default_tell (png_structp pngp) +{ + long l; + + if (!( pngp )) + { + png_error(pngp, "Call to apng_default_tell with NULL pngp failed"); + } + + if (( l = ftell((png_FILE_p)png_get_io_ptr(pngp)) ) == -1) + png_error(pngp, "Tell Error"); + + return (size_t)l; +} +#endif/* PNG_STDIO_SUPPORTED */ + +void +apng_set_write_fn (png_structp pngp, apng_infop ainfop, png_voidp iop, + png_rw_ptr write_f, png_flush_ptr flush_f, + apng_seek_ptr seek_f, apng_tell_ptr tell_f) +{ + if (!( pngp && ainfop )) + return; + + png_set_write_fn(pngp, iop, write_f, flush_f); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED + if (!flush_f) + ainfop->output_flush_fn = &apng_default_flush; + else +#endif/* PNG_STDIO_SUPPORTED */ + ainfop->output_flush_fn = flush_f; +#endif/* PNG_WRITE_FLUSH_SUPPORTED */ +#ifdef PNG_STDIO_SUPPORTED + if (!seek_f) + ainfop->output_seek_fn = &apng_default_seek; + else +#endif/* PNG_STDIO_SUPPORTED */ + ainfop->output_seek_fn = seek_f; +#ifdef PNG_STDIO_SUPPORTED + if (!seek_f) + ainfop->output_tell_fn = apng_default_tell; + else +#endif/* PNG_STDIO_SUPPORTED */ + ainfop->output_tell_fn = tell_f; +} + +void +apng_write_IEND (png_structp pngp) +{ + png_byte chunkc[] = "IEND"; + png_write_chunk(pngp, chunkc, 0, 0); +} + +void +apng_write_acTL (png_structp pngp, png_uint_32 frames, png_uint_32 plays) +{ + png_byte chunkc[] = "acTL"; + png_byte buf[8]; + png_save_uint_32(buf, frames); + png_save_uint_32(buf + 4, plays); + png_write_chunk(pngp, chunkc, buf, 8); +} + +png_uint_32 +apng_set_acTL (png_structp pngp, png_infop infop, apng_infop ainfop, + png_uint_32 frames, png_uint_32 plays) +{ + (void)pngp; + (void)infop; + if (!( pngp && infop && ainfop )) + return 0; + + ainfop->num_frames = frames; + ainfop->num_plays = plays; + + ainfop->valid |= APNG_INFO_acTL; + + return 1; +} + +void +apng_write_info_before_PLTE (png_structp pngp, png_infop infop, + apng_infop ainfop) +{ + if (!( pngp && infop && ainfop )) + return; + + png_write_info_before_PLTE(pngp, infop); + + if (( ainfop->valid & APNG_INFO_acTL )&&!( ainfop->mode & APNG_WROTE_acTL )) + { + ainfop->start_acTL = apng_tell(pngp, ainfop); + + apng_write_acTL(pngp, 0, 0); + /* modified for runtime dynamic linking */ + (*(ainfop->set_acTL_fn))(pngp, infop, PNG_UINT_31_MAX, 0); + + ainfop->mode |= APNG_WROTE_acTL; + } +} + +void +apng_write_info (png_structp pngp, png_infop infop, + apng_infop ainfop) +{ + apng_write_info_before_PLTE(pngp, infop, ainfop); + png_write_info(pngp, infop); +} + +void +apng_write_end (png_structp pngp, png_infop infop, apng_infop ainfop) +{ + (void)infop; + apng_write_IEND(pngp); + apng_seek(pngp, ainfop, ainfop->start_acTL); + apng_write_acTL(pngp, ainfop->num_frames, ainfop->num_plays); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +#ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED + apng_flush(pngp, infop); +#endif/* PNG_WRITE_FLUSH_SUPPORTED */ +#endif/* PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED */ +} + +#ifndef PNG_WRITE_APNG_SUPPORTED +png_uint_32 +apng_set_acTL_dummy (png_structp pngp, png_infop infop, + png_uint_32 frames, png_uint_32 plays) +{ + (void)pngp; + (void)infop; + (void)frames; + (void)plays; + return 0; +} +#endif/* PNG_WRITE_APNG_SUPPORTED */ + +/* Dynamic runtime linking capable! (Hopefully.) */ +void +apng_set_set_acTL_fn (png_structp pngp, apng_infop ainfop, + apng_set_acTL_ptr set_acTL_f) +{ + (void)pngp; + if (!ainfop->set_acTL_fn) +#ifndef PNG_WRITE_APNG_SUPPORTED + ainfop->set_acTL_fn = &apng_set_acTL_dummy; +#else + ainfop->set_acTL_fn = &png_set_acTL; +#endif/* PNG_WRITE_APNG_SUPPORTED */ + else + ainfop->set_acTL_fn = set_acTL_f; +} diff --git a/src/apng.h b/src/apng.h new file mode 100644 index 000000000..aa7fac3df --- /dev/null +++ b/src/apng.h @@ -0,0 +1,82 @@ +/* +Copyright 2019, James R. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef APNG_H +#define APNG_H + +#ifndef _MSC_VER +#ifndef _WII +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#endif +#endif + +#ifndef _LFS64_LARGEFILE +#define _LFS64_LARGEFILE +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 0 +#endif + +#include + +typedef struct apng_info_def apng_info; +typedef apng_info * apng_infop; +typedef const apng_info * apng_const_infop; +typedef apng_info * * apng_infopp; + +typedef void (*apng_seek_ptr)(png_structp, size_t); +typedef size_t (*apng_tell_ptr)(png_structp); + +typedef png_uint_32 (*apng_set_acTL_ptr)(png_structp, png_infop, + png_uint_32, png_uint_32); + +apng_infop apng_create_info_struct (png_structp png_ptr); + +void apng_destroy_info_struct (png_structp png_ptr, + apng_infopp info_ptr_ptr); + +/* Call the following functions in place of the libpng counterparts. */ + +png_uint_32 apng_set_acTL (png_structp png_ptr, png_infop info_ptr, + apng_infop ainfo_ptr, + png_uint_32 num_frames, png_uint_32 num_plays); + +void apng_write_info_before_PLTE (png_structp png_ptr, png_infop info_ptr, + apng_infop ainfo_ptr); +void apng_write_info (png_structp png_ptr, png_infop info_ptr, + apng_infop ainfo_ptr); + +void apng_write_end (png_structp png_ptr, png_infop info_ptr, + apng_infop ainfo_ptr); + +void apng_set_write_fn (png_structp png_ptr, apng_infop ainfo_ptr, + png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn, + apng_seek_ptr output_seek_fn, apng_tell_ptr output_tell_fn); + +void apng_set_set_acTL_fn (png_structp png_ptr, apng_infop ainfo_ptr, + apng_set_acTL_ptr set_acTL_fn); + +#endif/* APNG_H */ diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 2529b05d0..a0f9f40ab 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2415,6 +2415,8 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) #ifdef HAVE_BLUA LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting +#else + (void)reason; #endif // Reset player data diff --git a/src/d_main.c b/src/d_main.c index dd2cfe0e5..1782e94f5 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1130,6 +1130,10 @@ void D_SRB2Main(void) // Setup default unlockable conditions M_SetupDefaultConditionSets(); + // Setup character tables + // Have to be done here before files are loaded + M_InitCharacterTables(); + // load wad, including the main wad file CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n"); if (!W_InitMultipleFiles(startupwadfiles)) diff --git a/src/d_net.h b/src/d_net.h index 61c669dbb..3d1058702 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -19,7 +19,7 @@ #define __D_NET__ // Max computers in a game -#define MAXNETNODES 32 +#define MAXNETNODES (MAXPLAYERS+4) #define BROADCASTADDR MAXNETNODES #define MAXSPLITSCREENPLAYERS 2 // Max number of players on a single computer //#define NETSPLITSCREEN // Kart's splitscreen netgame feature diff --git a/src/dehacked.c b/src/dehacked.c index a726ecbc1..bda0c38f7 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -435,11 +435,11 @@ static void readAnimTex(MYFILE *f, INT32 num) static boolean findFreeSlot(INT32 *num) { // Send the character select entry to a free slot. - while (*num < 32 && PlayerMenu[*num].status != IT_DISABLED) + while (*num < MAXSKINS && PlayerMenu[*num].status != IT_DISABLED) *num = *num+1; // No more free slots. :( - if (*num >= 32) + if (*num >= MAXSKINS) return false; // Found one! ^_^ @@ -1196,6 +1196,13 @@ static void readlevelheader(MYFILE *f, INT32 num) #endif else if (fastcmp(word, "MUSICTRACK")) mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1); + else if (fastcmp(word, "MUSICPOS")) + mapheaderinfo[num-1]->muspos = (UINT32)get_number(word2); + else if (fastcmp(word, "MUSICINTERFADEOUT")) + mapheaderinfo[num-1]->musinterfadeout = (UINT32)get_number(word2); + else if (fastcmp(word, "MUSICINTER")) + deh_strlcpy(mapheaderinfo[num-1]->musintername, word2, + sizeof(mapheaderinfo[num-1]->musintername), va("Level header %d: intermission music", num)); else if (fastcmp(word, "FORCECHARACTER")) { strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1); @@ -1499,6 +1506,11 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musswitchflags), UNDO_NONE); cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; } + else if (fastcmp(word, "MUSICPOS")) + { + DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musswitchposition), UNDO_NONE); + cutscenes[num]->scene[scenenum].musswitchposition = (UINT32)get_number(word2); + } else if (fastcmp(word, "MUSICLOOP")) { DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musicloop), UNDO_NONE); @@ -7003,6 +7015,7 @@ struct { // doomdef.h constants {"TICRATE",TICRATE}, + {"MUSICRATE",MUSICRATE}, {"RING_DIST",RING_DIST}, {"PUSHACCEL",PUSHACCEL}, {"MODID",MODID}, // I don't know, I just thought it would be cool for a wad to potentially know what mod it was loaded into. @@ -8314,6 +8327,9 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"mapmusflags")) { lua_pushinteger(L, mapmusflags); return 1; + } else if (fastcmp(word,"mapmusposition")) { + lua_pushinteger(L, mapmusposition); + return 1; } else if (fastcmp(word,"server")) { if ((!multiplayer || !netgame) && !playeringame[serverplayer]) return 0; diff --git a/src/djgppdos/i_sound.c b/src/djgppdos/i_sound.c index 52c90aac2..88b598622 100644 --- a/src/djgppdos/i_sound.c +++ b/src/djgppdos/i_sound.c @@ -438,6 +438,37 @@ boolean I_SetSongSpeed(float speed) return false; } +/// ------------------------ +// MUSIC SEEKING +/// ------------------------ + +UINT32 I_GetSongLength(void) +{ + return 0; +} + +boolean I_SetSongLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetSongLoopPoint(void) +{ + return 0; +} + +boolean I_SetSongPosition(UINT32 position) +{ + (void)position; + return false; +} + +UINT32 I_GetSongPosition(void) +{ + return 0; +} + /// ------------------------ // MUSIC PLAYBACK /// ------------------------ @@ -545,3 +576,44 @@ int I_QrySongPlaying(int handle) return (midi_pos==-1); } #endif + +/// ------------------------ +// MUSIC FADING +/// ------------------------ + +void I_SetInternalMusicVolume(UINT8 volume) +{ + (void)volume; +} + +void I_StopFadingSong(void) +{ +} + +boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void)); +{ + (void)target_volume; + (void)source_volume; + (void)ms; + return false; +} + +boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)); +{ + (void)target_volume; + (void)ms; + return false; +} + +boolean I_FadeOutStopSong(UINT32 ms) +{ + (void)ms; + return false; +} + +boolean I_FadeInPlaySong(UINT32 ms, boolean looping) +{ + (void)ms; + (void)looping; + return false; +} diff --git a/src/doomdef.h b/src/doomdef.h index 527cdf05f..088d81d0a 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -305,6 +305,8 @@ typedef enum #define NEWTICRATERATIO 1 // try 4 for 140 fps :) #define NEWTICRATE (TICRATE*NEWTICRATERATIO) +#define MUSICRATE 1000 // sound timing is calculated by milliseconds + #define RING_DIST 512*FRACUNIT // how close you need to be to a ring to attract it #define PUSHACCEL (2*FRACUNIT) // Acceleration for MF2_SLIDEPUSH items. diff --git a/src/doomstat.h b/src/doomstat.h index d37ae440a..d9132798f 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -33,8 +33,10 @@ extern INT16 gamemap; extern char mapmusname[7]; extern UINT16 mapmusflags; +extern UINT32 mapmusposition; #define MUSIC_TRACKMASK 0x0FFF // ----************ #define MUSIC_RELOADRESET 0x8000 // *--------------- +#define MUSIC_FORCERESET 0x4000 // -*-------------- // Use other bits if necessary. extern INT16 maptol; @@ -145,6 +147,7 @@ typedef struct char musswitch[7]; UINT16 musswitchflags; + UINT32 musswitchposition; UINT8 fadecolor; // Color number for fade, 0 means don't do the first fade UINT8 fadeinid; // ID of the first fade, to a color -- ignored if fadecolor is 0 @@ -215,6 +218,7 @@ typedef struct INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end. char musname[7]; ///< Music track to play. "" for no music. UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. + UINT32 muspos; ///< Music position to jump to. char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable. UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave. INT16 skynum; ///< Sky number to use. @@ -243,6 +247,10 @@ typedef struct UINT8 numGradedMares; ///< Internal. For grade support. nightsgrades_t *grades; ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful. + // Music stuff. + UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds + char musintername[7]; ///< Intermission screen music. + // Lua stuff. // (This is not ifdeffed so the map header structure can stay identical, just in case.) UINT8 numCustomOptions; ///< Internal. For Lua custom value support. diff --git a/src/dummy/i_sound.c b/src/dummy/i_sound.c index 7275bb1ae..f09158e01 100644 --- a/src/dummy/i_sound.c +++ b/src/dummy/i_sound.c @@ -95,6 +95,37 @@ boolean I_SetSongSpeed(float speed) return false; } +/// ------------------------ +// MUSIC SEEKING +/// ------------------------ + +UINT32 I_GetSongLength(void) +{ + return 0; +} + +boolean I_SetSongLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetSongLoopPoint(void) +{ + return 0; +} + +boolean I_SetSongPosition(UINT32 position) +{ + (void)position; + return false; +} + +UINT32 I_GetSongPosition(void) +{ + return 0; +} + /// ------------------------ // MUSIC PLAYBACK /// ------------------------ @@ -142,4 +173,45 @@ boolean I_SetSongTrack(int track) { (void)track; return false; -} \ No newline at end of file +} + +/// ------------------------ +// MUSIC FADING +/// ------------------------ + +void I_SetInternalMusicVolume(UINT8 volume) +{ + (void)volume; +} + +void I_StopFadingSong(void) +{ +} + +boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void)); +{ + (void)target_volume; + (void)source_volume; + (void)ms; + return false; +} + +boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)); +{ + (void)target_volume; + (void)ms; + return false; +} + +boolean I_FadeOutStopSong(UINT32 ms) +{ + (void)ms; + return false; +} + +boolean I_FadeInPlaySong(UINT32 ms, boolean looping) +{ + (void)ms; + (void)looping; + return false; +} diff --git a/src/f_finale.c b/src/f_finale.c index 7708642e8..b7c319091 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1728,9 +1728,10 @@ static void F_AdvanceToNextScene(void) picypos = cutscenes[cutnum]->scene[scenenum].ycoord[picnum]; if (cutscenes[cutnum]->scene[scenenum].musswitch[0]) - S_ChangeMusic(cutscenes[cutnum]->scene[scenenum].musswitch, + S_ChangeMusicEx(cutscenes[cutnum]->scene[scenenum].musswitch, cutscenes[cutnum]->scene[scenenum].musswitchflags, - cutscenes[cutnum]->scene[scenenum].musicloop); + cutscenes[cutnum]->scene[scenenum].musicloop, + cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0); // Fade to the next dofadenow = true; @@ -1801,9 +1802,10 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset stoptimer = 0; if (cutscenes[cutnum]->scene[0].musswitch[0]) - S_ChangeMusic(cutscenes[cutnum]->scene[0].musswitch, + S_ChangeMusicEx(cutscenes[cutnum]->scene[0].musswitch, cutscenes[cutnum]->scene[0].musswitchflags, - cutscenes[cutnum]->scene[0].musicloop); + cutscenes[cutnum]->scene[0].musicloop, + cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0); else S_StopMusic(); } diff --git a/src/g_game.c b/src/g_game.c index 213c3b83e..c0cb469a1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -71,6 +71,7 @@ static void G_DoWorldDone(void); char mapmusname[7]; // Music name UINT16 mapmusflags; // Track and reset bit +UINT32 mapmusposition; // Position to jump to INT16 gamemap = 1; INT16 maptol; @@ -2268,9 +2269,14 @@ void G_PlayerReborn(INT32 player) { strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7); mapmusname[6] = 0; - mapmusflags = mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK; + mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); + mapmusposition = mapheaderinfo[gamemap-1]->muspos; } - S_ChangeMusic(mapmusname, mapmusflags, true); + + // This is in S_Start, but this was not here previously. + // if (cv_resetmusic.value) + // S_StopMusic(); + S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); } if (gametype == GT_COOP) diff --git a/src/i_sound.h b/src/i_sound.h index fd73d1454..9a5c2930a 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -146,6 +146,18 @@ boolean I_SongPaused(void); boolean I_SetSongSpeed(float speed); +/// ------------------------ +// MUSIC SEEKING +/// ------------------------ + +UINT32 I_GetSongLength(void); + +boolean I_SetSongLoopPoint(UINT32 looppoint); +UINT32 I_GetSongLoopPoint(void); + +boolean I_SetSongPosition(UINT32 position); +UINT32 I_GetSongPosition(void); + /// ------------------------ // MUSIC PLAYBACK /// ------------------------ @@ -216,6 +228,17 @@ void I_SetMusicVolume(UINT8 volume); boolean I_SetSongTrack(INT32 track); +/// ------------------------ +/// MUSIC FADING +/// ------------------------ + +void I_SetInternalMusicVolume(UINT8 volume); +void I_StopFadingSong(void); +boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void)); +boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)); +boolean I_FadeOutStopSong(UINT32 ms); +boolean I_FadeInPlaySong(UINT32 ms, boolean looping); + /// ------------------------ // CD MUSIC I/O /// ------------------------ diff --git a/src/lua_baselib.c b/src/lua_baselib.c index fd83cf955..d3443312a 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -780,7 +780,8 @@ static int lib_pRestoreMusic(lua_State *L) NOHUD if (!player) return LUA_ErrInvalid(L, "player_t"); - P_RestoreMusic(player); + if (P_IsLocalPlayer(player)) + P_RestoreMusic(player); return 0; } @@ -1820,7 +1821,7 @@ static int lib_sChangeMusic(lua_State *L) { #ifdef MUSICSLOT_COMPATIBILITY const char *music_name; - UINT32 music_num; + UINT32 music_num, position, prefadems, fadeinms; char music_compat_name[7]; boolean looping; @@ -1848,7 +1849,6 @@ static int lib_sChangeMusic(lua_State *L) music_name = luaL_checkstring(L, 1); } - looping = (boolean)lua_opttrueboolean(L, 2); #else @@ -1873,8 +1873,12 @@ static int lib_sChangeMusic(lua_State *L) #endif music_flags = (UINT16)luaL_optinteger(L, 4, 0); + position = (UINT32)luaL_optinteger(L, 5, 0); + prefadems = (UINT32)luaL_optinteger(L, 6, 0); + fadeinms = (UINT32)luaL_optinteger(L, 7, 0); + if (!player || P_IsLocalPlayer(player)) - S_ChangeMusic(music_name, music_flags, looping); + S_ChangeMusicEx(music_name, music_flags, looping, position, prefadems, fadeinms); return 0; } @@ -1891,10 +1895,8 @@ static int lib_sSpeedMusic(lua_State *L) return LUA_ErrInvalid(L, "player_t"); } if (!player || P_IsLocalPlayer(player)) - lua_pushboolean(L, S_SpeedMusic(speed)); - else - lua_pushboolean(L, false); - return 1; + S_SpeedMusic(speed); + return 0; } static int lib_sStopMusic(lua_State *L) @@ -1912,6 +1914,110 @@ static int lib_sStopMusic(lua_State *L) return 0; } +static int lib_sSetInternalMusicVolume(lua_State *L) +{ + UINT32 volume = (UINT32)luaL_checkinteger(L, 1); + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + { + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + { + S_SetInternalMusicVolume(volume); + lua_pushboolean(L, true); + } + else + lua_pushnil(L); + return 1; +} + +static int lib_sStopFadingMusic(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + { + S_StopFadingMusic(); + lua_pushboolean(L, true); + } + else + lua_pushnil(L); + return 1; +} + +static int lib_sFadeMusic(lua_State *L) +{ + UINT32 target_volume = (UINT32)luaL_checkinteger(L, 1); + UINT32 ms; + INT32 source_volume; + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) + { + player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + ms = (UINT32)luaL_checkinteger(L, 2); + source_volume = -1; + } + else if (!lua_isnone(L, 4) && lua_isuserdata(L, 4)) + { + player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + source_volume = (INT32)luaL_checkinteger(L, 2); + ms = (UINT32)luaL_checkinteger(L, 3); + } + else if (luaL_optinteger(L, 3, INT32_MAX) == INT32_MAX) + { + ms = (UINT32)luaL_checkinteger(L, 2); + source_volume = -1; + } + else + { + source_volume = (INT32)luaL_checkinteger(L, 2); + ms = (UINT32)luaL_checkinteger(L, 3); + } + + NOHUD + + if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_FadeMusicFromVolume(target_volume, source_volume, ms)); + else + lua_pushnil(L); + return 1; +} + +static int lib_sFadeOutStopMusic(lua_State *L) +{ + UINT32 ms = (UINT32)luaL_checkinteger(L, 1); + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + { + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + { + lua_pushboolean(L, S_FadeOutStopMusic(ms)); + } + else + lua_pushnil(L); + return 1; +} + static int lib_sOriginPlaying(lua_State *L) { void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -2264,6 +2370,10 @@ static luaL_Reg lib[] = { {"S_ChangeMusic",lib_sChangeMusic}, {"S_SpeedMusic",lib_sSpeedMusic}, {"S_StopMusic",lib_sStopMusic}, + {"S_SetInternalMusicVolume", lib_sSetInternalMusicVolume}, + {"S_StopFadingMusic",lib_sStopFadingMusic}, + {"S_FadeMusic",lib_sFadeMusic}, + {"S_FadeOutStopMusic",lib_sFadeOutStopMusic}, {"S_OriginPlaying",lib_sOriginPlaying}, {"S_IdPlaying",lib_sIdPlaying}, {"S_SoundPlaying",lib_sSoundPlaying}, diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 1f2414ba5..35542fdce 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -1468,6 +1468,12 @@ static int mapheaderinfo_get(lua_State *L) lua_pushstring(L, header->musname); else if (fastcmp(field,"mustrack")) lua_pushinteger(L, header->mustrack); + else if (fastcmp(field,"muspos")) + lua_pushinteger(L, header->muspos); + else if (fastcmp(field,"musinterfadeout")) + lua_pushinteger(L, header->musinterfadeout); + else if (fastcmp(field,"musintername")) + lua_pushstring(L, header->musintername); else if (fastcmp(field,"forcecharacter")) lua_pushstring(L, header->forcecharacter); else if (fastcmp(field,"weather")) diff --git a/src/m_menu.c b/src/m_menu.c index 266bc2516..65647d2a6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -112,41 +112,8 @@ typedef enum const char *quitmsg[NUM_QUITMESSAGES]; // Stuff for customizing the player select screen Tails 09-22-2003 -description_t description[32] = -{ - {"\x82Sonic\x80 is the fastest of the three, but also the hardest to control. Beginners beware, but experts will find Sonic very powerful.\n\n\x82""Ability:\x80 Speed Thok\nDouble jump to zoom forward with a huge burst of speed.\n\n\x82Tip:\x80 Simply letting go of forward does not slow down in SRB2. To slow down, hold the opposite direction.", "", "sonic"}, - {"\x82Tails\x80 is the most mobile of the three, but has the slowest speed. Because of his mobility, he's well-\nsuited to beginners.\n\n\x82""Ability:\x80 Fly\nDouble jump to start flying for a limited time. Repetitively hit the jump button to ascend.\n\n\x82Tip:\x80 To quickly descend while flying, hit the spin button.", "", "tails"}, - {"\x82Knuckles\x80 is well-\nrounded and can destroy breakable walls simply by touching them, but he can't jump as high as the other two.\n\n\x82""Ability:\x80 Glide & Climb\nDouble jump to glide in the air as long as jump is held. Glide into a wall to climb it.\n\n\x82Tip:\x80 Press spin while climbing to jump off the wall; press jump instead to jump off\nand face away from\nthe wall.", "", "knuckles"}, - {"\x82Sonic & Tails\x80 team up to take on Dr. Eggman!\nControl Sonic while Tails desperately struggles to keep up.\n\nPlayer 2 can control Tails directly by setting the controls in the options menu.\nTails's directional controls are relative to Player 1's camera.\n\nTails can pick up Sonic while flying and carry him around.", "CHRS&T", "sonic&tails"}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""}, - {"???", "", ""} -}; +description_t description[MAXSKINS]; + static char *char_notes = NULL; static fixed_t char_scroll = 0; @@ -842,41 +809,7 @@ static menuitem_t SP_LevelStatsMenu[] = // A rare case. // External files modify this menu, so we can't call it static. // And I'm too lazy to go through and rename it everywhere. ARRGH! -menuitem_t PlayerMenu[32] = -{ - {IT_CALL, NULL, NULL, M_ChoosePlayer, 0}, - {IT_CALL, NULL, NULL, M_ChoosePlayer, 0}, - {IT_CALL, NULL, NULL, M_ChoosePlayer, 0}, - {IT_CALL, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}, - {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0} -}; +menuitem_t PlayerMenu[MAXSKINS]; // ----------------------------------- // Multiplayer and all of its submenus @@ -2864,6 +2797,55 @@ void M_Init(void) CV_RegisterVar(&cv_allcaps); } +void M_InitCharacterTables(void) +{ + UINT8 i; + + // Setup PlayerMenu table + for (i = 0; i < MAXSKINS; i++) + { + PlayerMenu[i].status = (i < 4 ? IT_CALL : IT_DISABLED); + PlayerMenu[i].patch = PlayerMenu[i].text = NULL; + PlayerMenu[i].itemaction = M_ChoosePlayer; + PlayerMenu[i].alphaKey = 0; + } + + // Setup description table + for (i = 0; i < MAXSKINS; i++) + { + if (i == 0) + { + strcpy(description[i].notes, "\x82Sonic\x80 is the fastest of the three, but also the hardest to control. Beginners beware, but experts will find Sonic very powerful.\n\n\x82""Ability:\x80 Speed Thok\nDouble jump to zoom forward with a huge burst of speed.\n\n\x82Tip:\x80 Simply letting go of forward does not slow down in SRB2. To slow down, hold the opposite direction."); + strcpy(description[i].picname, ""); + strcpy(description[i].skinname, "sonic"); + } + else if (i == 1) + { + strcpy(description[i].notes, "\x82Tails\x80 is the most mobile of the three, but has the slowest speed. Because of his mobility, he's well-\nsuited to beginners.\n\n\x82""Ability:\x80 Fly\nDouble jump to start flying for a limited time. Repetitively hit the jump button to ascend.\n\n\x82Tip:\x80 To quickly descend while flying, hit the spin button."); + strcpy(description[i].picname, ""); + strcpy(description[i].skinname, "tails"); + } + else if (i == 2) + { + strcpy(description[i].notes, "\x82Knuckles\x80 is well-\nrounded and can destroy breakable walls simply by touching them, but he can't jump as high as the other two.\n\n\x82""Ability:\x80 Glide & Climb\nDouble jump to glide in the air as long as jump is held. Glide into a wall to climb it.\n\n\x82Tip:\x80 Press spin while climbing to jump off the wall; press jump instead to jump off\nand face away from\nthe wall."); + strcpy(description[i].picname, ""); + strcpy(description[i].skinname, "knuckles"); + } + else if (i == 3) + { + strcpy(description[i].notes, "\x82Sonic & Tails\x80 team up to take on Dr. Eggman!\nControl Sonic while Tails desperately struggles to keep up.\n\nPlayer 2 can control Tails directly by setting the controls in the options menu.\nTails's directional controls are relative to Player 1's camera.\n\nTails can pick up Sonic while flying and carry him around."); + strcpy(description[i].picname, "CHRS&T"); + strcpy(description[i].skinname, "sonic&tails"); + } + else + { + strcpy(description[i].notes, "???"); + strcpy(description[i].picname, ""); + strcpy(description[i].skinname, ""); + } + } +} + // ========================================================================== // SPECIAL MENU OPTION DRAW ROUTINES GO HERE // ========================================================================== @@ -7516,7 +7498,7 @@ static void M_DrawControl(void) } static INT32 controltochange; -static char controltochangetext[55]; +static char controltochangetext[33]; static void M_ChangecontrolResponse(event_t *ev) { @@ -7588,7 +7570,8 @@ static void M_ChangecontrolResponse(event_t *ev) } else if (ch == KEY_PAUSE) { - static char tmp[155]; + // This buffer assumes a 125-character message plus a 32-character control name (per controltochangetext buffer size) + static char tmp[158]; menu_t *prev = currentMenu->prevMenu; if (controltochange == gc_pause) @@ -7612,12 +7595,14 @@ static void M_ChangecontrolResponse(event_t *ev) static void M_ChangeControl(INT32 choice) { - static char tmp[55]; + // This buffer assumes a 35-character message (per below) plus a max control name limit of 32 chars (per controltochangetext) + // If you change the below message, then change the size of this buffer! + static char tmp[68]; controltochange = currentMenu->menuitems[choice].alphaKey; sprintf(tmp, M_GetText("Hit the new key for\n%s\nESC for Cancel"), currentMenu->menuitems[choice].text); - strncpy(controltochangetext, currentMenu->menuitems[choice].text, 55); + strlcpy(controltochangetext, currentMenu->menuitems[choice].text, 33); M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER); } diff --git a/src/m_menu.h b/src/m_menu.h index eb770c194..fcde5b7db 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -38,6 +38,9 @@ void M_Drawer(void); // Called by D_SRB2Main, loads the config file. void M_Init(void); +// Called by D_SRB2Main also, sets up the playermenu and description tables. +void M_InitCharacterTables(void); + // Called by intro code to force menu up upon a keypress, // does nothing if menu is already up. void M_StartControlPanel(void); @@ -151,7 +154,7 @@ typedef struct menuitem_s UINT8 alphaKey; } menuitem_t; -extern menuitem_t PlayerMenu[32]; +extern menuitem_t PlayerMenu[MAXSKINS]; typedef struct menu_s { @@ -206,7 +209,7 @@ typedef struct UINT8 netgame; } saveinfo_t; -extern description_t description[32]; +extern description_t description[MAXSKINS]; extern consvar_t cv_newgametype, cv_nextmap, cv_chooseskin, cv_serversort; extern CV_PossibleValue_t gametype_cons_t[]; diff --git a/src/m_misc.c b/src/m_misc.c index 88ae3b86a..232ccb477 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -94,7 +94,8 @@ typedef off_t off64_t; #ifdef PNG_WRITE_SUPPORTED #define USE_PNG // Only actually use PNG if write is supported. #if defined (PNG_WRITE_APNG_SUPPORTED) //|| !defined(PNG_STATIC) - #define USE_APNG + #include "apng.h" + #define USE_APNG #endif // See hardware/hw_draw.c for a similar check to this one. #endif @@ -808,13 +809,13 @@ static inline void M_PNGImage(png_structp png_ptr, png_infop png_info_ptr, PNG_C #ifdef USE_APNG static png_structp apng_ptr = NULL; static png_infop apng_info_ptr = NULL; +static apng_infop apng_ainfo_ptr = NULL; static png_FILE_p apng_FILE = NULL; static png_uint_32 apng_frames = 0; -static png_byte acTL_cn[5] = { 97, 99, 84, 76, '\0'}; #ifdef PNG_STATIC // Win32 build have static libpng -#define apng_set_acTL png_set_acTL -#define apng_write_frame_head png_write_frame_head -#define apng_write_frame_tail png_write_frame_tail +#define aPNG_set_acTL png_set_acTL +#define aPNG_write_frame_head png_write_frame_head +#define aPNG_write_frame_tail png_write_frame_tail #else // outside libpng may not have apng support #ifndef PNG_WRITE_APNG_SUPPORTED // libpng header may not have apng patch @@ -851,20 +852,20 @@ static png_byte acTL_cn[5] = { 97, 99, 84, 76, '\0'}; #endif #endif -typedef PNG_EXPORT(png_uint_32, (*P_png_set_acTL)) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays)); -typedef PNG_EXPORT (void, (*P_png_write_frame_head)) PNGARG((png_structp png_ptr, +typedef png_uint_32 (*P_png_set_acTL) (png_structp png_ptr, + png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays); +typedef void (*P_png_write_frame_head) (png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers, png_uint_32 width, png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset, png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, - png_byte blend_op)); + png_byte blend_op); -typedef PNG_EXPORT (void, (*P_png_write_frame_tail)) PNGARG((png_structp png_ptr, - png_infop info_ptr)); -static P_png_set_acTL apng_set_acTL = NULL; -static P_png_write_frame_head apng_write_frame_head = NULL; -static P_png_write_frame_tail apng_write_frame_tail = NULL; +typedef void (*P_png_write_frame_tail) (png_structp png_ptr, + png_infop info_ptr); +static P_png_set_acTL aPNG_set_acTL = NULL; +static P_png_write_frame_head aPNG_write_frame_head = NULL; +static P_png_write_frame_tail aPNG_write_frame_tail = NULL; #endif static inline boolean M_PNGLib(void) @@ -873,7 +874,7 @@ static inline boolean M_PNGLib(void) return true; #else static void *pnglib = NULL; - if (apng_set_acTL && apng_write_frame_head && apng_write_frame_tail) + if (aPNG_set_acTL && aPNG_write_frame_head && aPNG_write_frame_tail) return true; if (pnglib) return false; @@ -893,16 +894,16 @@ static inline boolean M_PNGLib(void) if (!pnglib) return false; #ifdef HAVE_SDL - apng_set_acTL = hwSym("png_set_acTL", pnglib); - apng_write_frame_head = hwSym("png_write_frame_head", pnglib); - apng_write_frame_tail = hwSym("png_write_frame_tail", pnglib); + aPNG_set_acTL = hwSym("png_set_acTL", pnglib); + aPNG_write_frame_head = hwSym("png_write_frame_head", pnglib); + aPNG_write_frame_tail = hwSym("png_write_frame_tail", pnglib); #endif #ifdef _WIN32 - apng_set_acTL = GetProcAddress("png_set_acTL", pnglib); - apng_write_frame_head = GetProcAddress("png_write_frame_head", pnglib); - apng_write_frame_tail = GetProcAddress("png_write_frame_tail", pnglib); + aPNG_set_acTL = GetProcAddress("png_set_acTL", pnglib); + aPNG_write_frame_head = GetProcAddress("png_write_frame_head", pnglib); + aPNG_write_frame_tail = GetProcAddress("png_write_frame_tail", pnglib); #endif - return (apng_set_acTL && apng_write_frame_head && apng_write_frame_tail); + return (aPNG_set_acTL && aPNG_write_frame_head && aPNG_write_frame_tail); #endif } @@ -916,11 +917,6 @@ static void M_PNGFrame(png_structp png_ptr, png_infop png_info_ptr, png_bytep pn apng_frames++; -#ifndef PNG_STATIC - if (apng_set_acTL) -#endif - apng_set_acTL(apng_ptr, apng_info_ptr, apng_frames, 0); - for (y = 0; y < height; y++) { row_pointers[y] = png_buf; @@ -928,9 +924,9 @@ static void M_PNGFrame(png_structp png_ptr, png_infop png_info_ptr, png_bytep pn } #ifndef PNG_STATIC - if (apng_write_frame_head) + if (aPNG_write_frame_head) #endif - apng_write_frame_head(apng_ptr, apng_info_ptr, row_pointers, + aPNG_write_frame_head(apng_ptr, apng_info_ptr, row_pointers, vid.width, /* width */ height, /* height */ 0, /* x offset */ @@ -943,57 +939,21 @@ static void M_PNGFrame(png_structp png_ptr, png_infop png_info_ptr, png_bytep pn png_write_image(png_ptr, row_pointers); #ifndef PNG_STATIC - if (apng_write_frame_tail) + if (aPNG_write_frame_tail) #endif - apng_write_frame_tail(apng_ptr, apng_info_ptr); + aPNG_write_frame_tail(apng_ptr, apng_info_ptr); png_free(png_ptr, (png_voidp)row_pointers); } -static inline boolean M_PNGfind_acTL(void) +static void M_PNGfix_acTL(png_structp png_ptr, png_infop png_info_ptr, + apng_infop png_ainfo_ptr) { - png_byte cn[8]; // 4 bytes for len then 4 byes for name - long endpos = ftell(apng_FILE); // not the real end of file, just what of libpng wrote - for (fseek(apng_FILE, 0, SEEK_SET); // let go to the start of the file - ftell(apng_FILE)+12 < endpos; // let not go over the file bound - fseek(apng_FILE, 1, SEEK_CUR) // we went 8 steps back and now we go 1 step forward - ) - { - if (fread(cn, sizeof(cn), 1, apng_FILE) != 1) // read 8 bytes - return false; // failed to read data - if (fseek(apng_FILE, -8, SEEK_CUR) != 0) //rewind 8 bytes - return false; // failed to rewird - if (!png_memcmp(cn+4, acTL_cn, 4)) //cmp for chuck header - return true; // found it - } - return false; // acTL chuck not found -} - -static void M_PNGfix_acTL(png_structp png_ptr, png_infop png_info_ptr) -{ - png_byte data[16]; - long oldpos; - -#ifndef PNG_STATIC - if (apng_set_acTL) -#endif - apng_set_acTL(png_ptr, png_info_ptr, apng_frames, 0); + apng_set_acTL(png_ptr, png_info_ptr, png_ainfo_ptr, apng_frames, 0); #ifndef NO_PNG_DEBUG png_debug(1, "in png_write_acTL\n"); #endif - - png_ptr->num_frames_to_write = apng_frames; - - png_save_uint_32(data, apng_frames); - png_save_uint_32(data + 4, 0); - - oldpos = ftell(apng_FILE); - - if (M_PNGfind_acTL()) - png_write_chunk(png_ptr, (png_bytep)acTL_cn, data, (png_size_t)8); - - fseek(apng_FILE, oldpos, SEEK_SET); } static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal) @@ -1025,6 +985,16 @@ static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal) return false; } + apng_ainfo_ptr = apng_create_info_struct(apng_ptr); + if (!apng_ainfo_ptr) + { + CONS_Debug(DBG_RENDER, "M_StartMovie: Error on allocate for apng\n"); + png_destroy_write_struct(&apng_ptr, &apng_info_ptr); + fclose(apng_FILE); + remove(filename); + return false; + } + png_init_io(apng_ptr, apng_FILE); #ifdef PNG_SET_USER_LIMITS_SUPPORTED @@ -1042,12 +1012,11 @@ static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal) M_PNGText(apng_ptr, apng_info_ptr, true); -#ifndef PNG_STATIC - if (apng_set_acTL) -#endif - apng_set_acTL(apng_ptr, apng_info_ptr, PNG_UINT_31_MAX, 0); + apng_set_set_acTL_fn(apng_ptr, apng_ainfo_ptr, aPNG_set_acTL); - png_write_info(apng_ptr, apng_info_ptr); + apng_set_acTL(apng_ptr, apng_info_ptr, apng_ainfo_ptr, PNG_UINT_31_MAX, 0); + + apng_write_info(apng_ptr, apng_info_ptr, apng_ainfo_ptr); apng_frames = 0; @@ -1249,8 +1218,8 @@ void M_StopMovie(void) if (apng_frames) { - M_PNGfix_acTL(apng_ptr, apng_info_ptr); - png_write_end(apng_ptr, apng_info_ptr); + M_PNGfix_acTL(apng_ptr, apng_info_ptr, apng_ainfo_ptr); + apng_write_end(apng_ptr, apng_info_ptr, apng_ainfo_ptr); } png_destroy_write_struct(&apng_ptr, &apng_info_ptr); diff --git a/src/p_setup.c b/src/p_setup.c index 5e1355981..033e99f10 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -187,6 +187,12 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->musname[6] = 0; DEH_WriteUndoline("MUSICTRACK", va("%d", mapheaderinfo[num]->mustrack), UNDO_NONE); mapheaderinfo[num]->mustrack = 0; + DEH_WriteUndoline("MUSICPOS", va("%d", mapheaderinfo[num]->muspos), UNDO_NONE); + mapheaderinfo[num]->muspos = 0; + DEH_WriteUndoline("MUSICINTERFADEOUT", va("%d", mapheaderinfo[num]->musinterfadeout), UNDO_NONE); + mapheaderinfo[num]->musinterfadeout = 0; + DEH_WriteUndoline("MUSICINTER", mapheaderinfo[num]->musintername, UNDO_NONE); + mapheaderinfo[num]->musintername[0] = '\0'; DEH_WriteUndoline("FORCECHARACTER", va("%d", mapheaderinfo[num]->forcecharacter), UNDO_NONE); mapheaderinfo[num]->forcecharacter[0] = '\0'; DEH_WriteUndoline("WEATHER", va("%d", mapheaderinfo[num]->weather), UNDO_NONE); @@ -1527,19 +1533,33 @@ static void P_LoadRawSideDefs2(void *data) { M_Memcpy(process,msd->bottomtexture,8); process[8] = '\0'; - sd->bottomtexture = get_number(process)-1; + sd->bottomtexture = get_number(process); } - M_Memcpy(process,msd->toptexture,8); - process[8] = '\0'; - sd->text = Z_Malloc(7, PU_LEVEL, NULL); - // If they type in O_ or D_ and their music name, just shrug, - // then copy the rest instead. - if ((process[0] == 'O' || process[0] == 'D') && process[7]) - M_Memcpy(sd->text, process+2, 6); - else // Assume it's a proper music name. - M_Memcpy(sd->text, process, 6); - sd->text[6] = 0; + if (!(msd->midtexture[0] == '-' && msd->midtexture[1] == '\0') || msd->midtexture[1] != '\0') + { + M_Memcpy(process,msd->midtexture,8); + process[8] = '\0'; + sd->midtexture = get_number(process); + } + + // always process if back sidedef, because we need that - symbol + sd->text = Z_Malloc(7, PU_LEVEL, NULL); + if (i == 1 || msd->toptexture[0] != '-' || msd->toptexture[1] != '\0') + { + M_Memcpy(process,msd->toptexture,8); + process[8] = '\0'; + + // If they type in O_ or D_ and their music name, just shrug, + // then copy the rest instead. + if ((process[0] == 'O' || process[0] == 'D') && process[7]) + M_Memcpy(sd->text, process+2, 6); + else // Assume it's a proper music name. + M_Memcpy(sd->text, process, 6); + sd->text[6] = 0; + } + else + sd->text[0] = 0; break; } diff --git a/src/p_slopes.c b/src/p_slopes.c index 68767b50c..4e12b104f 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -264,7 +264,7 @@ void P_SpawnSlope_Line(int linenum) if(!line->frontsector || !line->backsector) { - CONS_Printf("P_SpawnSlope_Line used on a line without two sides.\n"); + CONS_Debug(DBG_SETUP, "P_SpawnSlope_Line used on a line without two sides. (line number %i)\n", linenum); return; } diff --git a/src/p_spec.c b/src/p_spec.c index 50b8aec9d..f3be86ee1 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2408,16 +2408,68 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // console player only unless NOCLIMB is set if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player))) { - UINT16 tracknum = (UINT16)sides[line->sidenum[0]].bottomtexture; + boolean musicsame = (!sides[line->sidenum[0]].text[0] || !strnicmp(sides[line->sidenum[0]].text, S_MusicName(), 7)); + UINT16 tracknum = (UINT16)max(sides[line->sidenum[0]].bottomtexture, 0); + INT32 position = (INT32)max(sides[line->sidenum[0]].midtexture, 0); + UINT32 prefadems = (UINT32)max(sides[line->sidenum[0]].textureoffset >> FRACBITS, 0); + UINT32 postfadems = (UINT32)max(sides[line->sidenum[0]].rowoffset >> FRACBITS, 0); + UINT8 fadetarget = (UINT8)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].textureoffset >> FRACBITS : 0, 0); + INT16 fadesource = (INT16)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].rowoffset >> FRACBITS : -1, -1); - strncpy(mapmusname, sides[line->sidenum[0]].text, 7); - mapmusname[6] = 0; + // Seek offset from current song position + if (line->flags & ML_EFFECT1) + { + // adjust for loop point if subtracting + if (position < 0 && S_GetMusicLength() && + S_GetMusicPosition() > S_GetMusicLoopPoint() && + S_GetMusicPosition() + position < S_GetMusicLoopPoint()) + position = max(S_GetMusicLength() - (S_GetMusicLoopPoint() - (S_GetMusicPosition() + position)), 0); + else + position = max(S_GetMusicPosition() + position, 0); + } - mapmusflags = tracknum & MUSIC_TRACKMASK; - if (!(line->flags & ML_BLOCKMONSTERS)) - mapmusflags |= MUSIC_RELOADRESET; + // Fade current music to target volume (if music won't be changed) + if ((line->flags & ML_EFFECT2) && fadetarget && musicsame) + { + // 0 fadesource means fade from current volume. + // meaning that we can't specify volume 0 as the source volume -- this starts at 1. + if (!fadesource) + fadesource = -1; - S_ChangeMusic(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4)); + if (!postfadems) + S_SetInternalMusicVolume(fadetarget); + else + S_FadeMusicFromVolume(fadetarget, fadesource, postfadems); + + if (position) + S_SetMusicPosition(position); + } + // Change the music and apply position/fade operations + else + { + strncpy(mapmusname, sides[line->sidenum[0]].text, 7); + mapmusname[6] = 0; + + mapmusflags = tracknum & MUSIC_TRACKMASK; + if (!(line->flags & ML_BLOCKMONSTERS)) + mapmusflags |= MUSIC_RELOADRESET; + if (line->flags & ML_BOUNCY) + mapmusflags |= MUSIC_FORCERESET; + + mapmusposition = position; + + S_ChangeMusicEx(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4), position, + !(line->flags & ML_EFFECT2) ? prefadems : 0, + !(line->flags & ML_EFFECT2) ? postfadems : 0); + + if ((line->flags & ML_EFFECT2) && fadetarget) + { + if (!postfadems) + S_SetInternalMusicVolume(fadetarget); + else + S_FadeMusicFromVolume(fadetarget, fadesource, postfadems); + } + } // Except, you can use the ML_BLOCKMONSTERS flag to change this behavior. // if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn. diff --git a/src/p_user.c b/src/p_user.c index e4cb01f63..f04386fec 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1124,13 +1124,13 @@ void P_RestoreMusic(player_t *player) if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC) { S_SpeedMusic(1.4f); - S_ChangeMusic(mapmusname, mapmusflags, true); + S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); } else S_ChangeMusicInternal("shoes", true); } else - S_ChangeMusic(mapmusname, mapmusflags, true); + S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); } // @@ -8688,8 +8688,11 @@ void P_PlayerThink(player_t *player) if (player->bot) { - if (player->playerstate == PST_LIVE && B_CheckRespawn(player)) - player->playerstate = PST_REBORN; + if (player->playerstate == PST_LIVE || player->playerstate == PST_DEAD) + { + if (B_CheckRespawn(player)) + player->playerstate = PST_REBORN; + } if (player->playerstate == PST_REBORN) return; } diff --git a/src/r_segs.c b/src/r_segs.c index 6d6ba1efd..748365264 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -3063,8 +3063,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) else markceiling = false; - // Don't render the ceiling again when rendering polyobjects - if (curline->polyseg) + // Don't mark ceiling flat lines for polys unless this line has an upper texture, otherwise we get flat leakage pulling downward + // (If it DOES have an upper texture and we do this, the ceiling won't render at all) + if (curline->polyseg && !curline->sidedef->toptexture) markceiling = false; } @@ -3076,8 +3077,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) else markfloor = false; - // Don't render the floor again when rendering polyobjects - if (curline->polyseg) + // Don't mark floor flat lines for polys unless this line has a lower texture, otherwise we get flat leakage pulling upward + // (If it DOES have a lower texture and we do this, the floor won't render at all) + if (curline->polyseg && !curline->sidedef->bottomtexture) markfloor = false; } diff --git a/src/r_things.c b/src/r_things.c index 67a45a76e..0382596f1 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2306,7 +2306,7 @@ void R_DrawMasked(void) // ========================================================================== INT32 numskins = 0; -skin_t skins[MAXSKINS+1]; +skin_t skins[MAXSKINS]; // FIXTHIS: don't work because it must be inistilised before the config load //#define SKINVALUES #ifdef SKINVALUES @@ -2559,7 +2559,7 @@ void R_AddSkins(UINT16 wadnum) // advance by default lastlump = lump + 1; - if (numskins > MAXSKINS) + if (numskins >= MAXSKINS) { CONS_Debug(DBG_RENDER, "ignored skin (%d skins maximum)\n", MAXSKINS); continue; // so we know how many skins couldn't be added diff --git a/src/r_things.h b/src/r_things.h index 6614e0aa4..2823c3894 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -180,7 +180,7 @@ typedef struct drawnode_s } drawnode_t; extern INT32 numskins; -extern skin_t skins[MAXSKINS + 1]; +extern skin_t skins[MAXSKINS]; void SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 diff --git a/src/s_sound.c b/src/s_sound.c index 0961a4427..acb7dcbbe 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -38,6 +38,10 @@ extern INT32 msg_id; #include "p_local.h" // camera info #include "m_misc.h" // for tunes command +#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS) +#include "lua_hook.h" // MusicChange hook +#endif + #ifdef HW3SOUND // 3D Sound Interface #include "hardware/hw3sound.h" @@ -1241,6 +1245,12 @@ static void *music_data; static UINT16 music_flags; static boolean music_looping; +static char queue_name[7]; +static UINT16 queue_flags; +static boolean queue_looping; +static UINT32 queue_position; +static UINT32 queue_fadeinms; + /// ------------------------ /// Music Status /// ------------------------ @@ -1275,6 +1285,11 @@ musictype_t S_MusicType(void) return I_SongType(); } +const char *S_MusicName(void) +{ + return music_name; +} + boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping) { if (!I_SongPlaying()) @@ -1305,6 +1320,35 @@ boolean S_SpeedMusic(float speed) return I_SetSongSpeed(speed); } +/// ------------------------ +/// Music Seeking +/// ------------------------ + +UINT32 S_GetMusicLength(void) +{ + return I_GetSongLength(); +} + +boolean S_SetMusicLoopPoint(UINT32 looppoint) +{ + return I_SetSongLoopPoint(looppoint); +} + +UINT32 S_GetMusicLoopPoint(void) +{ + return I_GetSongLoopPoint(); +} + +boolean S_SetMusicPosition(UINT32 position) +{ + return I_SetSongPosition(position); +} + +UINT32 S_GetMusicPosition(void) +{ + return I_GetSongPosition(); +} + /// ------------------------ /// Music Playback /// ------------------------ @@ -1377,12 +1421,13 @@ static void S_UnloadMusic(void) music_looping = false; } -static boolean S_PlayMusic(boolean looping) +static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) { if (S_MusicDisabled()) return false; - if (!I_PlaySong(looping)) + if ((!fadeinms && !I_PlaySong(looping)) || + (fadeinms && !I_FadeInPlaySong(fadeinms, looping))) { S_UnloadMusic(); return false; @@ -1392,8 +1437,30 @@ static boolean S_PlayMusic(boolean looping) return true; } -void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) +static void S_QueueMusic(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 fadeinms) { + strncpy(queue_name, mmusic, 7); + queue_flags = mflags; + queue_looping = looping; + queue_position = position; + queue_fadeinms = fadeinms; +} + +static void S_ClearQueue(void) +{ + queue_name[0] = queue_flags = queue_looping = queue_position = queue_fadeinms = 0; +} + +static void S_ChangeMusicToQueue(void) +{ + S_ChangeMusicEx(queue_name, queue_flags, queue_looping, queue_position, 0, queue_fadeinms); + S_ClearQueue(); +} + +void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms) +{ + char newmusic[7]; + #if defined (DC) || defined (_WIN32_WCE) || defined (PSP) || defined(GP2X) S_ClearSfx(); #endif @@ -1401,33 +1468,66 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) if (S_MusicDisabled()) return; - // No Music (empty string) - if (mmusic[0] == 0) - { - S_StopMusic(); + strncpy(newmusic, mmusic, 7); +#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS) + if(LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms)) + return; +#endif + newmusic[6] = 0; + + // No Music (empty string) + if (newmusic[0] == 0) + { + if (prefadems) + I_FadeSong(0, prefadems, &S_StopMusic); + else + S_StopMusic(); return; } - if (strnicmp(music_name, mmusic, 6)) + if (prefadems && S_MusicPlaying()) // queue music change for after fade // allow even if the music is the same { - S_StopMusic(); // shutdown old music + CONS_Debug(DBG_DETAILED, "Now fading out song %s\n", music_name); + S_QueueMusic(newmusic, mflags, looping, position, fadeinms); + I_FadeSong(0, prefadems, S_ChangeMusicToQueue); + return; + } + else if (strnicmp(music_name, newmusic, 6) || (mflags & MUSIC_FORCERESET)) + { + CONS_Debug(DBG_DETAILED, "Now playing song %s\n", newmusic); - if (!S_LoadMusic(mmusic)) + S_StopMusic(); + + if (!S_LoadMusic(newmusic)) { - CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded!\n", mmusic); + CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded!\n", newmusic); return; } music_flags = mflags; music_looping = looping; - if (!S_PlayMusic(looping)) - { - CONS_Alert(CONS_ERROR, "Music %.6s could not be played!\n", mmusic); + if (!S_PlayMusic(looping, fadeinms)) + { + CONS_Alert(CONS_ERROR, "Music %.6s could not be played!\n", newmusic); return; } + + if (position) + I_SetSongPosition(position); + + I_SetSongTrack(mflags & MUSIC_TRACKMASK); + } + else if (fadeinms) // let fades happen with same music + { + I_SetSongPosition(position); + I_FadeSong(100, fadeinms, NULL); + } + else // reset volume to 100 with same music + { + I_StopFadingSong(); + I_FadeSong(100, 500, NULL); } - I_SetSongTrack(mflags & MUSIC_TRACKMASK); } void S_StopMusic(void) @@ -1502,6 +1602,32 @@ void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume) } } +/// ------------------------ +/// Music Fading +/// ------------------------ + +void S_SetInternalMusicVolume(INT32 volume) +{ + I_SetInternalMusicVolume(min(max(volume, 0), 100)); +} + +void S_StopFadingMusic(void) +{ + I_StopFadingSong(); +} + +boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms) +{ + if (source_volume < 0) + return I_FadeSong(target_volume, ms, NULL); + else + return I_FadeSongFromVolume(target_volume, source_volume, ms, NULL); +} + +boolean S_FadeOutStopMusic(UINT32 ms) +{ + return I_FadeSong(0, ms, &S_StopMusic); +} /// ------------------------ /// Init & Others @@ -1519,22 +1645,24 @@ void S_Start(void) strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7); mapmusname[6] = 0; mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); + mapmusposition = mapheaderinfo[gamemap-1]->muspos; } if (cv_resetmusic.value) S_StopMusic(); - S_ChangeMusic(mapmusname, mapmusflags, true); + S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); } static void Command_Tunes_f(void) { const char *tunearg; UINT16 tunenum, track = 0; + UINT32 position = 0; const size_t argc = COM_Argc(); if (argc < 2) //tunes slot ... { - CONS_Printf("tunes [track] [speed] / <-show> / <-default> / <-none>:\n"); + CONS_Printf("tunes [track] [speed] [position] / <-show> / <-default> / <-none>:\n"); CONS_Printf(M_GetText("Play an arbitrary music lump. If a map number is used, 'MAP##M' is played.\n")); CONS_Printf(M_GetText("If the format supports multiple songs, you can specify which one to play.\n\n")); CONS_Printf(M_GetText("* With \"-show\", shows the currently playing tune and track.\n")); @@ -1581,10 +1709,15 @@ static void Command_Tunes_f(void) snprintf(mapmusname, 7, "%sM", G_BuildMapName(tunenum)); else strncpy(mapmusname, tunearg, 7); + + if (argc > 4) + position = (UINT32)atoi(COM_Argv(4)); + mapmusname[6] = 0; mapmusflags = (track & MUSIC_TRACKMASK); + mapmusposition = position; - S_ChangeMusic(mapmusname, mapmusflags, true); + S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); if (argc > 3) { diff --git a/src/s_sound.h b/src/s_sound.h index 821746074..157b8b1cc 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -112,29 +112,49 @@ boolean S_MusicDisabled(void); boolean S_MusicPlaying(void); boolean S_MusicPaused(void); musictype_t S_MusicType(void); +const char *S_MusicName(void); boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping); boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi); #define S_DigExists(a) S_MusicExists(a, false, true) #define S_MIDIExists(a) S_MusicExists(a, true, false) - // -// Music Properties +// Music Effects // // Set Speed of Music boolean S_SpeedMusic(float speed); // -// Music Routines +// Music Seeking +// + +// Get Length of Music +UINT32 S_GetMusicLength(void); + +// Set LoopPoint of Music +boolean S_SetMusicLoopPoint(UINT32 looppoint); + +// Get LoopPoint of Music +UINT32 S_GetMusicLoopPoint(void); + +// Set Position of Music +boolean S_SetMusicPosition(UINT32 position); + +// Get Position of Music +UINT32 S_GetMusicPosition(void); + +// +// Music Playback // // Start music track, arbitrary, given its name, and set whether looping // note: music flags 12 bits for tracknum (gme, other formats with more than one track) // 13-15 aren't used yet // and the last bit we ignore (internal game flag for resetting music on reload) -#define S_ChangeMusicInternal(a,b) S_ChangeMusic(a,0,b) -void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping); +void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms); +#define S_ChangeMusicInternal(a,b) S_ChangeMusicEx(a,0,b,0,0,0) +#define S_ChangeMusic(a,b,c) S_ChangeMusicEx(a,b,c,0,0,0) // Stops the music. void S_StopMusic(void); @@ -143,6 +163,17 @@ void S_StopMusic(void); void S_PauseAudio(void); void S_ResumeAudio(void); +// +// Music Fading +// + +void S_SetInternalMusicVolume(INT32 volume); +void S_StopFadingMusic(void); +boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms); +#define S_FadeMusic(a, b) S_FadeMusicFromVolume(a, -1, b) +#define S_FadeInChangeMusic(a,b,c,d) S_ChangeMusicEx(a,b,c,0,0,d) +boolean S_FadeOutStopMusic(UINT32 ms); + // // Updates music & sounds // diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt index f7b7c7ba4..7f8f052ba 100644 --- a/src/sdl/CMakeLists.txt +++ b/src/sdl/CMakeLists.txt @@ -70,6 +70,8 @@ if(${SDL2_FOUND}) set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS} + ${SRB2_PNG_SOURCES} + ${SRB2_PNG_HEADERS} ${SRB2_CORE_RENDER_SOURCES} ${SRB2_CORE_GAME_SOURCES} ${SRB2_LUA_SOURCES} @@ -80,7 +82,8 @@ if(${SDL2_FOUND}) ${SRB2_SDL2_HEADERS} ) - source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS}) + source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS} + ${SRB2_PNG_SOURCES} ${SRB2_PNG_HEADERS}) source_group("Renderer" FILES ${SRB2_CORE_RENDER_SOURCES}) source_group("Game" FILES ${SRB2_CORE_GAME_SOURCES}) source_group("Assembly" FILES ${SRB2_ASM_SOURCES} ${SRB2_NASM_SOURCES}) diff --git a/src/sdl/SDL_icon.xpm b/src/sdl/SDL_icon.xpm index 30259d55e..1d0f9d314 100644 --- a/src/sdl/SDL_icon.xpm +++ b/src/sdl/SDL_icon.xpm @@ -1,213 +1,163 @@ /* XPM */ -static const char *SDL_icon_xpm[] = { -/* columns rows colors chars-per-pixel */ -"32 32 175 2 ", -" c None", -". c #2E2E2E", -"X c #3C3C3C", -"o c #493939", -"O c #4E473F", -"+ c #161658", -"@ c #131369", -"# c #06067B", -"$ c #111173", -"% c #16167F", -"& c #252567", -"* c #372B7C", -"= c #3D3679", -"- c #41414A", -"; c #575655", -": c #6A5841", -"> c #5B4B72", -", c #616160", -"< c #7B7B7B", -"1 c #906E49", -"2 c #89685D", -"3 c #A67B4A", -"4 c #AA7F50", -"5 c #9B7560", -"6 c #856C78", -"7 c #997B7D", -"8 c #B48552", -"9 c #BA8A55", -"0 c #A48665", -"q c #B98F67", -"w c #B9946A", -"e c #B7937A", -"r c #C8955C", -"t c #CA9966", -"y c #DAA469", -"u c #C9A37B", -"i c #D7AB7B", -"p c #DFB07D", -"a c #EBAE6A", -"s c #E5B27A", -"d c #F1B779", -"f c #0A0A83", -"g c #05058B", -"h c #060687", -"j c #101089", -"k c #131382", -"l c #040494", -"z c #02029D", -"x c #0C0B9C", -"c c #120F9E", -"v c #19199B", -"b c #382D84", -"n c #39398D", -"m c #222296", -"M c #0101A6", -"N c #0A0AA2", -"B c #0202AC", -"V c #1919A2", -"C c #1616AD", -"Z c #0000B5", -"A c #0202BC", -"S c #0C0CB6", -"D c #1313B3", -"F c #1011BD", -"G c #1B1BBE", -"H c #2B2BAC", -"J c #3737A1", -"K c #2A26BE", -"L c #2A29B4", -"P c #3B3BB8", -"I c #48478B", -"U c #57578A", -"Y c #4A499A", -"T c #524F95", -"R c #565399", -"E c #4C4CA8", -"W c #524DA7", -"Q c #5353A4", -"! c #5555A9", -"~ c #5555B4", -"^ c #5656B7", -"/ c #6464A6", -"( c #6F67B5", -") c #0404C3", -"_ c #0707CA", -"` c #1414CB", -"' c #1A1AC6", -"] c #0A0AD3", -"[ c #0D0DDC", -"{ c #1A1AD4", -"} c #1010DF", -"| c #1E1EDE", -" . c #1817DE", -".. c #221FCA", -"X. c #2B2BCC", -"o. c #2727C9", -"O. c #3434C3", -"+. c #3434D4", -"@. c #0F0FE2", -"#. c #1313E5", -"$. c #1515ED", -"%. c #1B1BEA", -"&. c #1C1CE4", -"*. c #1515F4", -"=. c #1818F3", -"-. c #1717FD", -";. c #1818FF", -":. c #2B2BE9", -">. c #2424FF", -",. c #2A2AFF", -"<. c #2222F1", -"1. c #3737FF", -"2. c #5D5DC3", -"3. c #5F5FC9", -"4. c #5655C2", -"5. c #4747D1", -"6. c #5B5BD4", -"7. c #6565C8", -"8. c #6363DA", -"9. c #4545FF", -"0. c #4D4DFC", -"q. c #5454FF", -"w. c #5959FF", -"e. c #6969E5", -"r. c #6B6CEA", -"t. c #6666E7", -"y. c #6B6BFE", -"u. c #6767F8", -"i. c #7070F6", -"p. c #7373FF", -"a. c #7C7CFF", -"s. c #91918F", -"d. c #8F9090", -"f. c #979797", -"g. c #9C9C9C", -"h. c #8585A1", -"j. c #9C9CA7", -"k. c #9292B6", -"l. c #A4A4A4", -"z. c #BDB2A4", -"x. c #A4A4B1", -"c. c #BFBFBD", -"v. c #BABAB7", -"b. c #C8AA87", -"n. c #DAAE82", -"m. c #DBB081", -"M. c #EBBA85", -"N. c #F3BF84", -"B. c #F2BE88", -"V. c #C2B3A3", -"C. c #FBC386", -"Z. c #FCC68C", -"A. c #FFC88F", -"S. c #F4C387", -"D. c #FFC990", -"F. c #C3C1BF", -"G. c #8F8FCB", -"H. c #BDBDC2", -"J. c #BDBDD1", -"K. c #8888F9", -"L. c #A4A4FB", -"P. c #CDCDCC", -"I. c #CECAC6", -"U. c #D3CFCA", -"Y. c #D3D0CC", -"T. c #C0C0D5", -"R. c #D6D5D4", -"E. c #D7D7DD", -"W. c #E1E1DF", -"Q. c #DEDEE1", -"!. c #E4E4E4", -"~. c #E8E8E8", -"^. c #F0F0EE", -"/. c #F5F5F2", -"(. c #FFFFFF", -/* pixels */ -" ", -" ", -" ", -" I Q T = ", -" Q 7.e.r.i.8.E E 3.r.6.J ", -" H ~ n 4.r.p.p.p.p.8.R > 5.^ w.,.-.{ v ", -" { 9.^ & P t.p.p.p.p.p.8.I 5 q K L <.;.;.;.-.' ", -" { %.H +.y.p.p.p.p.p.e.Y 2 a n.K F $.*.$.@.} ] N ", -" x D :.y.p.p.p.p.p.p.r.R 8 C.u ..F A ) A Z M h $ ", -" f =.q.p.p.p.p.p.p.p.p.i.( e 6 $.` l B M g ", -" ` ;.q.p.p.p.p.p.a.K.a.p.p.4.L -.` l N % ", -" V =.-.>.q.y.p.p.p.L.L.K.i.w.,.-.;.$.<.q.u.2. ", -" D { =.-.;.>.1.1.9.( h.h.Q &.-.-.-.;.9.p.p.p.r.! ", -" U j.o.-.;.-.;.-.P x.Q.^.R.~ *.-.;.;.>.1.q.y.p.i.2. ", -" H./.! *.;.;.;.o.x./.(.(.(.J.| -.-.;.-.-.;.,.9.u.p.7. ", -" !.(.k.#.;.-.=./ !.(.(.(.(.Q.X.-.;.;.;.;.-.-.;.;.1.w.6. ", -" ~.(.H.G ;.-.D j.(.(.(.(.(.!.O.-.-.;.;.;.-.;.-.;.-.;.,.O. ", -" ~.(.v.@ *.$.+ d.(.(.(.(.(.E.o.-.-.;.;.-.;.;.;.*.=.=.*.$.v ", -" ~.(.l.- Y T ; < (.(.(.(.(.J.&.-.;.;.$.@.[ ] _ ) ) Z B B f ", -" P.(.F.X c.I.X f.(.(.(.(.(.G.=.-.=.] A Z Z Z Z z f $ ", -" l.!.R.s.F.I.g.W.(.(.(.(.R.E .[ A Z Z Z B g $ ", -" . , ; - 0 M.b.V.U.R.Y.z.u n.7 c Z Z B g # + ", -" : w p Z.D.A.S.p u i M.A.A.S.* Z B h z ] C ", -" s D.D.A.A.A.A.A.A.A.i B.B.b A Z Z @.-.` ", -" 1 y C.D.A.A.A.A.A.M.u Z.e c A Z Z [ ;.&. ", -" 8 y d C.A.A.A.C.B.t * B Z Z Z A #.=.m ", -" 3 9 r t r 9 8 o @ $ # f j l B #.V ", -" j k ", -" ", -" ", -" ", -" " -}; +const char * SDL_icon_xpm[] = { +"96 96 64 1", +" c None", +". c #040656", +"+ c #0100B2", +"@ c #04056E", +"# c #0000BD", +"$ c #0B0C09", +"% c #0B0D26", +"& c #090C42", +"* c #060AA7", +"= c #1604DA", +"- c #020CD5", +"; c #100F8D", +"> c #040DE4", +", c #11129B", +"' c #1D1A83", +") c #2A10FD", +"! c #1318FA", +"~ c #25225B", +"{ c #252271", +"] c #312E2B", +"^ c #33334D", +"/ c #363775", +"( c #3D3B69", +"_ c #3A3B8B", +": c #373AFF", +"< c #4142AA", +"[ c #4B4864", +"} c #4D4B4A", +"| c #60492F", +"1 c #4F4C57", +"2 c #4A4A9E", +"3 c #4F4E85", +"4 c #474ADE", +"5 c #4E4FFE", +"6 c #5D5CB3", +"7 c #686663", +"8 c #666682", +"9 c #676875", +"0 c #66659E", +"a c #8B6538", +"b c #6465D5", +"c c #7F694F", +"d c #6767FF", +"e c #7272FF", +"f c #91795C", +"g c #7677FD", +"h c #828396", +"i c #A78153", +"j c #888989", +"k c #8D897E", +"l c #9190FD", +"m c #CA9048", +"n c #C09968", +"o c #A9A8A1", +"p c #A6A8B0", +"q c #B0B1FB", +"r c #EEAC61", +"s c #E3B478", +"t c #C3C4BE", +"u c #FFC68C", +"v c #FCCD90", +"w c #D4D7D3", +"x c #E3E5E0", +"y c #FCFFFB", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ttj7777777joot ", +" 9hh8830000088hh9 ", +" 9888(//__-*{^kt ", +" &,5b60^ (02*{} ", +" tp,-)!5egb3} ~_<4dgggeeeeeeeeeeeeeegb6/_2[amusf'#!<_'>))))))))))))!)>+{~ ", +" p;-))!5gb2^^'#5eggeeeeeeeeeeeeeeegg6/_23amrusi{#!+;;>))))))))))))))!!-'8p ", +" tp'#!)):d6(@*>5egeeeeeeeeeeeeeeeegg6_/<(amrrvvn{+)-,;>))))))!!!!!!)))!!>,~j ", +" p;#!))-'{'+-5eggeeeeeeeeeeeeeeeegb222(cmrruvvn{+)>,@>!)!!)!!>>>>======>-,/8 ", +" ;#)!-*.;-!5eggeeeeeeeeeeeeeeeegb2_<6|mrrsvvvn{+)!,.-!!!!>>=--######+++-#@(k ", +" h@-)+@.*>!5egeeeeeeeeeeeeeeeeeegb_>--###++++++###+;@{(9j ", +" kh,#+@@,>!:dggeeeeeeeeeeeeeeeeeeebbb_]mrruuvvsf'#)!*.+-###+++++++##+*;'3(&^9 ", +" 8*,@@*)):dggeeeeeeeeeeeeeeeeeeeeggg<(|iruvvvsc,=!!*.;*++++++++###+,@&1o ", +" 8@@@-!)!5eeeeeeeeeeeeeeeeeeeeeeeeeggb2[csvvvn^#)!!+@;*#+++++###*@~[ ", +" 9&@*!)):5geeeeeeeeeeeeeeeeeeeeeeeeegge637nsvf{>))!+;;*-######*;{.^ ", +" 9%;!!)):dgeeeeeeeeeeeeeeeeeeeeeeeeeeeggb_1ir7;>))!+;;,++++++*'(} ", +" 9{+!))!5egeeeeeeeeeeeeeeeeeddddeeeeeeeege2}|~#!))!#;@...@@@.^hp ", +" 8,=!))):dggeeeeeeeeeeeeeeeeggggeeeeeeeeggb_~,>!))!+@@@;;;;@&^o ", +" }(-)))))!:eegeeeeeeeeeeeeeegllllgeeeeeeeegd5+=))))!+;,#>--#,'/hj ", +" o8.>))))))!:dgggeeeeeeeeeeellqqqqlgeeeeggg5:!!!)))))-*+>)!:55db631 ", +" p8<*!)))))))!:5deggggggeeeegqqqqqqqqlggged5:!))))))))>->!!:5ddeegb3/ ", +" oh'#!))))))))))!:ddeeeeeeeeglqqqqqqqqlgedd:!)))))))))))))!:dggggeggg239 ", +" ^*>!))!)))))))))!::55dddeegglll600333_4:!!)))))))))))))):dggeeeeeeggb6(9o ", +" ~+=-+#>))))))))))!!!:::::5554<3889988[/,=)))))))))))))):5gggeeeeeeeggb6087 ", +" ~**@~'+>!))))))))))))))))!!>*{1kkooook7(,-!)))))))))))!:5deeeeeeeeeeeggb289 ", +" ~,'1o7(*>!))))))))))))))))=,[jtttwxxxwto^;>!))))))))))!!!::5deggeeeeeeegbb3] ", +" ~@/oxt7'#))))))))))))))))=,3ktwxxyyyyyyxk/+!))))))))))))))!:::5degggeeegggb3^ ", +" ^&8xyyt^,)))))))))))))))>,3otwxyyyyyyyyyxh'>)))))))))))))))))):5ddeeeeeeeggb3^ ", +" 771pyyyx7'=!)))))))))))!!#(jtxxyyyyyyyyyyyt3-)))))))))))))))))))!!::degggeeegb2[o ", +" 77tyyyxk/+!!)))))))))))-;9owxyyyyyyyyyyyywh*>)))))))))))))))))))))!::5ddgggggb68j ", +" owyyyyt8;>))))))))))))*(otwyyyyyyyyyyyyyxp'-)))))))))))))))))))))))!!:5deeeggg_8j ", +" jtxyyyyxh'>)))))))))!!#_ktxyyyyyyyyyyyyyyyt_+))))))))))))))))))))))))))!!:5deggg63j ", +" 7jwyyyyyyp/=))))))))))>,3owxyyyyyyyyyyyyyyyw/+))))))))))))))))))))))))))))!::5degb689 ", +" 7xyyyyyyo[#))))))))))-/jtwyyyyyyyyyyyyyyyyw/*)))))))))))))))))))))))))))))))!:5dgg_/ ", +" }xyyyyyyt9*=))))))))=*9owyyyyyyyyyyyyyyyyyw/*)))))))))))))))))))))))))))))))))!!:5d3} ", +" }xyyyyyywj'#!))))))!#@7oxyyyyyyyyyyyyyyyyyw/*)))))))))))))))))))))))))))))))))))!!:4/7 ", +" 7xyyyyyyxj&,!!))))!!,%}oyyyyyyyyyyyyyyyyyyw/*))))))))))))))))))))))))))))))))))))))>487 ", +" 7xyyyyyywk$@!!)))!!-.$]oyyyyyyyyyyyyyyyyyyw/+))))))))))))))))))))))))))))))!!!!))))!>' ", +" }xyyyyyywj$&+!!)!)>;%$]jyyyyyyyyyyyyyyyyyyt{#)))))))))))))))))))))!!!!!!))!)!!!!!!))!#' ", +" 7xyyyyyyt7$%@-!)!>*[]$$jyyyyyyyyyyyyyyyyyxp;-))))))))))))))))))!!!!!!!!!!!!>>>>>>>>>>!,^ ", +" 7xyyyyyyt}$][;-)=,(o7$$7yyyyyyyyyyyyyyyyyxp,-)))))))))))!!!!)!!!!>>>>=-----########--=+'9 ", +" jwyyyyyyo}$}o(';@~7wj$$7yyyyyyyyyyyyyyyyywh*>)))))))))))!>>>=>=---#####+########+++***;@17 ", +" otxyyyyyt}$7t7}1}7kw7$$7yyyyyyyyyyyyyyyyyt0-)))))))))!!!>--####+++++++++++++##+***,;''.&] ", +" ooowyyyyyt}$}j7owwojo}$$jyyyyyyyyyyyyyyyyyp2>)))))))!!!=##++++++++++++++###+*;@.~[8[9hph ", +" ojtyyyyywj$$}jwyyxo}$$]jyyyyyyyyyyyyyyyyyp'>))))))!>>-#++++++++++++####+,;'_3/&^}77kot ", +" 7tyyyyyxo]$$oxyyyt]$$}tyyyyyyyyyyyyyyyyx0*!)))!!!>-#++++++++++++#+##+*;.&1ko ", +" 7tyyyyyyx7]}xyyyyxj}]oxyyyyyyyyyyyyyyyyp<=)!!!!>-#++++++++++++####*;.(8h ", +" owxyxxyytooywptwwtppxyyyyyyyyyyyyyyyxp3,-=!)!>-#++++++++++###+*,'_{&1k ", +" jtwwttwtwwtj7kjowxyyyyyyyyyyyyyyyyxt7~'',+>=#+++++++++++###*;@&^j ", +" ]joojj7}]}]|innfc7jtwyyyyyyyyyyyxtjcfnnnf[@*#+++++++++###+@.&%% ", +" ]$}77}}$$$$]fsssnnifkkotwwwwwwwtpjkfinvvvsi}@*#++++++###*;@.@@&[ ", +" o7$]]]]]$$]|isvvvvvusifckopppopok7cisvvvvvvvn(,#++++++#+*@.&@*#;3o ", +" }}$]|||fnnsvvvuvvvuuvvsniffffffnnsvvvvuuuvvvc{*+#++##*@&.@*+#--<7 ", +" }]cninsuvvvvuuuuuuvvvvusnnnnnssuvvvvvuuuuvvc~*+#+++*@.@;*##=>>,^ ", +" 7fvvvvvvuuuuuuuuuuuuvvvvvvvvvvvuuuuuuuuuvvc~*+#+#+,.@*###->!!*~ ", +" pkivvvvuuuuuuuuuuuuuuuvvvvvvvvuuuvsnsuuuvvf~*+#++++*+++->!!)!#. ", +" kfsuvvuuuuuuuuuuuuuuuuuuuuuuuuuvvnfsuvuvvc{++#++++###->!!))!-;h ", +" kisvvvuuuuuuuuuuuuuuuuuuuuuuuvvvicsvvvvs1@##+++++++#>!!))))=,ho ", +" 7imuvvvuuuuuuuuuuuuuuuuuuuuvusfcivvuvvn~;##+++++++#>!!))))!#8k ", +" cimruuuuuvuuuuuuuuuuuuuuuuvsnfisuvvvsc@*#+++++++++#>!!))))-3} ", +" 7amrruuuuuuuuuuuuuuuuuuuuvsnnsvvuvvi^,##++++++++++#>!!)))>/^ ", +" kfamrruuuuvvvuuuuuuuuuuuuuvvvvvvvn1@+#++++++++++++#>!)))>{~ ", +" 7|iimrrruuuuuuuuuuuuuuuuvvvvuusn1'+#########++++++->!))>; ", +" 7cammrrrrruuuuuuvvvvvuuuuurrm|.*-#+#######+###+++->!!!*' ", +" ookcaimmrrrrrruuuuurrrrrmi|]%.@@@@@;,*,*+########->!!*6o ", +" p7}|ainiimmmmmmmmmmminnia|$%.....{3322_{''',,**+#=!!#6k ", +" j7||aaiiiiiaa||7j ookok711^&.';,*+=!>> + @@ -316,6 +317,7 @@ + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index ac0b03177..d67ac6308 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -294,6 +294,9 @@ LUA + + M_Misc + M_Misc diff --git a/src/sdl/Srb2SDL-vc9.vcproj b/src/sdl/Srb2SDL-vc9.vcproj index d2a268f8d..3898aeba4 100644 --- a/src/sdl/Srb2SDL-vc9.vcproj +++ b/src/sdl/Srb2SDL-vc9.vcproj @@ -2834,6 +2834,50 @@ RelativePath="..\m_argv.h" > + + + + + + + + + + + + + + + + diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 50c3018aa..b5597784e 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2045,8 +2045,8 @@ static void I_ShutdownTimer(void) // tic_t I_GetTime (void) { - static Uint32 basetime = 0; - Uint32 ticks = SDL_GetTicks(); + static Uint64 basetime = 0; + Uint64 ticks = SDL_GetTicks(); if (!basetime) basetime = ticks; diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj index 94a3fbb63..a8ecbf7f8 100644 --- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 1E44AF0D0B67CDE900BAD059 /* m_fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AEFE0B67CDE900BAD059 /* m_fixed.c */; }; 1E44AF0F0B67CDE900BAD059 /* m_menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF000B67CDE900BAD059 /* m_menu.c */; }; 1E44AF110B67CDE900BAD059 /* m_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF020B67CDE900BAD059 /* m_misc.c */; }; + 1E44AF110B67CDE900BAD059 /* apng.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF020B67CDE900BAD059 /* apng.c */; }; 1E44AF130B67CDE900BAD059 /* m_random.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF040B67CDE900BAD059 /* m_random.c */; }; 1E44AF1A0B67CE2A00BAD059 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF180B67CE2A00BAD059 /* info.c */; }; 1E44AF1E0B67CE3600BAD059 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF1C0B67CE3600BAD059 /* md5.c */; }; @@ -253,7 +254,9 @@ 1E44AF000B67CDE900BAD059 /* m_menu.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_menu.c; path = ../../m_menu.c; sourceTree = SOURCE_ROOT; }; 1E44AF010B67CDE900BAD059 /* m_menu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_menu.h; path = ../../m_menu.h; sourceTree = SOURCE_ROOT; }; 1E44AF020B67CDE900BAD059 /* m_misc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_misc.c; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; + 1E44AF020B67CDE900BAD059 /* apng.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = apng.c; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; 1E44AF030B67CDE900BAD059 /* m_misc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_misc.h; path = ../../m_misc.h; sourceTree = SOURCE_ROOT; }; + 1E44AF020B67CDE900BAD059 /* apng.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = apng.h; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; 1E44AF040B67CDE900BAD059 /* m_random.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_random.c; path = ../../m_random.c; sourceTree = SOURCE_ROOT; }; 1E44AF050B67CDE900BAD059 /* m_random.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_random.h; path = ../../m_random.h; sourceTree = SOURCE_ROOT; }; 1E44AF060B67CDE900BAD059 /* m_swap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_swap.h; path = ../../m_swap.h; sourceTree = SOURCE_ROOT; }; @@ -679,6 +682,8 @@ 1E44AEFF0B67CDE900BAD059 /* m_fixed.h */, 1E44AF020B67CDE900BAD059 /* m_misc.c */, 1E44AF030B67CDE900BAD059 /* m_misc.h */, + 1E44AF020B67CDE900BAD059 /* apng.c */, + 1E44AF030B67CDE900BAD059 /* apng.h */, 676BB51C0E0DE06100C95963 /* m_queue.c */, 676BB51D0E0DE06100C95963 /* m_queue.h */, 1E44AF040B67CDE900BAD059 /* m_random.c */, diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 6e90a6e06..dde62fc7a 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -75,15 +75,41 @@ UINT8 sound_started = false; static Mix_Music *music; -static UINT8 music_volume, sfx_volume; +static UINT8 music_volume, sfx_volume, internal_volume; static float loop_point; +static float song_length; // length in seconds static boolean songpaused; +static UINT32 music_bytes; +static boolean is_looping; + +// fading +static boolean is_fading; +static UINT8 fading_source; +static UINT8 fading_target; +static UINT32 fading_timer; +static UINT32 fading_duration; +static INT32 fading_id; +static void (*fading_callback)(void); #ifdef HAVE_LIBGME static Music_Emu *gme; static INT32 current_track; #endif +static void var_cleanup(void) +{ + loop_point = song_length =\ + music_bytes = fading_source = fading_target =\ + fading_timer = fading_duration = 0; + + songpaused = is_looping =\ + is_fading = false; + + fading_callback = NULL; + + internal_volume = 100; +} + /// ------------------------ /// Audio System /// ------------------------ @@ -111,6 +137,8 @@ void I_StartupSound(void) return; } + var_cleanup(); + music = NULL; music_volume = sfx_volume = 0; @@ -336,6 +364,7 @@ void *I_GetSfx(sfxinfo_t *sfx) len = (info->play_length * 441 / 10) << 2; mem = malloc(len); gme_play(emu, len >> 1, mem); + gme_free_info(info); gme_delete(emu); return Mix_QuickLoad_RAW((Uint8 *)mem, len); @@ -408,6 +437,7 @@ void *I_GetSfx(sfxinfo_t *sfx) len = (info->play_length * 441 / 10) << 2; mem = malloc(len); gme_play(emu, len >> 1, mem); + gme_free_info(info); gme_delete(emu); return Mix_QuickLoad_RAW((Uint8 *)mem, len); @@ -482,14 +512,102 @@ void I_SetSfxVolume(UINT8 volume) sfx_volume = volume; } +/// ------------------------ +/// Music Utilities +/// ------------------------ + +static UINT32 get_real_volume(UINT8 volume) +{ +#ifdef _WIN32 + if (I_SongType() == MU_MID) + // HACK: Until we stop using native MIDI, + // disable volume changes + return ((UINT32)31*128/31); // volume = 31 + else +#endif + // convert volume to mixer's 128 scale + // then apply internal_volume as a percentage + return ((UINT32)volume*128/31) * (UINT32)internal_volume / 100; +} + +static UINT32 get_adjusted_position(UINT32 position) +{ + // all in milliseconds + UINT32 length = I_GetSongLength(); + UINT32 looppoint = I_GetSongLoopPoint(); + if (length) + return position >= length ? (position % (length-looppoint)) : position; + else + return position; +} + +static void do_fading_callback(void) +{ + if (fading_callback) + (*fading_callback)(); + fading_callback = NULL; +} + /// ------------------------ /// Music Hooks /// ------------------------ +static void count_music_bytes(int chan, void *stream, int len, void *udata) +{ + (void)chan; + (void)stream; + (void)udata; + + if (!music || I_SongType() == MU_GME || I_SongType() == MU_MOD || I_SongType() == MU_MID) + return; + music_bytes += len; +} + static void music_loop(void) { - Mix_PlayMusic(music, 0); - Mix_SetMusicPosition(loop_point); + if (is_looping) + { + Mix_PlayMusic(music, 0); + Mix_SetMusicPosition(loop_point); + music_bytes = loop_point*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition) + } + else + I_StopSong(); +} + +static UINT32 music_fade(UINT32 interval, void *param) +{ + (void)param; + + if (!is_fading || + internal_volume == fading_target || + fading_duration == 0) + { + I_StopFadingSong(); + do_fading_callback(); + return 0; + } + else if (songpaused) // don't decrement timer + return interval; + else if ((fading_timer -= 10) <= 0) + { + internal_volume = fading_target; + Mix_VolumeMusic(get_real_volume(music_volume)); + I_StopFadingSong(); + do_fading_callback(); + return 0; + } + else + { + UINT8 delta = abs(fading_target - fading_source); + fixed_t factor = FixedDiv(fading_duration - fading_timer, fading_duration); + if (fading_target < fading_source) + internal_volume = max(min(internal_volume, fading_source - FixedMul(delta, factor)), fading_target); + else if (fading_target > fading_source) + internal_volume = min(max(internal_volume, fading_source + FixedMul(delta, factor)), fading_target); + Mix_VolumeMusic(get_real_volume(music_volume)); + return interval; + } } #ifdef HAVE_LIBGME @@ -509,7 +627,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len) // apply volume to stream for (i = 0, p = (short *)stream; i < len/2; i++, p++) - *p = ((INT32)*p) * music_volume*2 / 42; + *p = ((INT32)*p) * (music_volume*internal_volume/100)*2 / 42; } #endif @@ -587,6 +705,194 @@ boolean I_SetSongSpeed(float speed) return false; } +/// ------------------------ +/// MUSIC SEEKING +/// ------------------------ + +UINT32 I_GetSongLength(void) +{ + INT32 length; + +#ifdef HAVE_LIBGME + if (gme) + { + gme_info_t *info; + gme_err_t gme_e = gme_track_info(gme, &info, current_track); + + if (gme_e != NULL) + { + CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e); + length = 0; + } + else + { + // reconstruct info->play_length, from GME source + // we only want intro + 1 loop, not 2 + length = info->length; + if (length <= 0) + { + length = info->intro_length + info->loop_length; // intro + 1 loop + if (length <= 0) + length = 150 * 1000; // 2.5 minutes + } + } + + gme_free_info(info); + return max(length, 0); + } + else +#endif + if (!music || I_SongType() == MU_MOD || I_SongType() == MU_MID) + return 0; + else + { + // VERY IMPORTANT to set your LENGTHMS= in your song files, folks! + // SDL mixer can't read music length itself. + length = (UINT32)(song_length*1000); + if (!length) + CONS_Debug(DBG_DETAILED, "Getting music length: music is missing LENGTHMS= tag. Needed for seeking.\n"); + return length; + } +} + +boolean I_SetSongLoopPoint(UINT32 looppoint) +{ + if (!music || I_SongType() == MU_GME || I_SongType() == MU_MOD || I_SongType() == MU_MID || !is_looping) + return false; + else + { + UINT32 length = I_GetSongLength(); + + if (length > 0) + looppoint %= length; + + loop_point = max((float)(looppoint / 1000.0L), 0); + return true; + } +} + +UINT32 I_GetSongLoopPoint(void) +{ +#ifdef HAVE_LIBGME + if (gme) + { + INT32 looppoint; + gme_info_t *info; + gme_err_t gme_e = gme_track_info(gme, &info, current_track); + + if (gme_e != NULL) + { + CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e); + looppoint = 0; + } + else + looppoint = info->intro_length > 0 ? info->intro_length : 0; + + gme_free_info(info); + return max(looppoint, 0); + } + else +#endif + if (!music || I_SongType() == MU_MOD || I_SongType() == MU_MID) + return 0; + else + return (UINT32)(loop_point * 1000); +} + +boolean I_SetSongPosition(UINT32 position) +{ + UINT32 length; +#ifdef HAVE_LIBGME + if (gme) + { + // this is unstable, so fail silently + return true; + // this isn't required technically, but GME thread-locks for a second + // if you seek too high from the counter + // length = I_GetSongLength(); + // if (length) + // position = get_adjusted_position(position); + + // SDL_LockAudio(); + // gme_err_t gme_e = gme_seek(gme, position); + // SDL_UnlockAudio(); + + // if (gme_e != NULL) + // { + // CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e); + // return false; + // } + // else + // return true; + } + else +#endif + if (!music || I_SongType() == MU_MID) + return false; + else if (I_SongType() == MU_MOD) + return Mix_SetMusicPosition(position); // Goes by channels + else + { + // Because SDL mixer can't identify song length, if you have + // a position input greater than the real length, then + // music_bytes becomes inaccurate. + + length = I_GetSongLength(); // get it in MS + if (length) + position = get_adjusted_position(position); + + Mix_RewindMusic(); // needed for mp3 + if(Mix_SetMusicPosition((float)(position/1000.0L)) == 0) + music_bytes = position/1000.0L*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition) + else + // NOTE: This block fires on incorrect song format, + // NOT if position input is greater than song length. + music_bytes = 0; + + return true; + } +} + +UINT32 I_GetSongPosition(void) +{ +#ifdef HAVE_LIBGME + if (gme) + { + INT32 position = gme_tell(gme); + + gme_info_t *info; + gme_err_t gme_e = gme_track_info(gme, &info, current_track); + + if (gme_e != NULL) + { + CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e); + return position; + } + else + { + // adjust position, since GME's counter keeps going past loop + if (info->length > 0) + position %= info->length; + else if (info->intro_length + info->loop_length > 0) + position = position >= (info->intro_length + info->loop_length) ? (position % info->loop_length) : position; + else + position %= 150 * 1000; // 2.5 minutes + } + + gme_free_info(info); + return max(position, 0); + } + else +#endif + if (!music || I_SongType() == MU_MID) + return 0; + else + return music_bytes/44100.0L*1000.0L/4; //assume 44.1khz + // 4 = byte length for 16-bit samples (AUDIO_S16SYS), stereo (2-channel) + // This is hardcoded in I_StartupSound. Other formats for factor: + // 8M: 1 | 8S: 2 | 16M: 2 | 16S: 4 +} + /// ------------------------ /// Music Playback /// ------------------------ @@ -596,9 +902,21 @@ boolean I_LoadSong(char *data, size_t len) const char *key1 = "LOOP"; const char *key2 = "POINT="; const char *key3 = "MS="; + const char *key4 = "LENGTHMS="; const size_t key1len = strlen(key1); const size_t key2len = strlen(key2); const size_t key3len = strlen(key3); + const size_t key4len = strlen(key4); + + // for mp3 wide chars + const char *key1w = "L\0O\0O\0P\0"; + const char *key2w = "P\0O\0I\0N\0T\0\0\0\xFF\xFE"; + const char *key3w = "M\0S\0\0\0\xFF\xFE"; + const char *key4w = "L\0E\0N\0G\0T\0H\0M\0S\0\0\0\xFF\xFE"; + const char *wterm = "\0\0"; + char wval[10]; + + size_t wstart, wp; char *p = data; SDL_RWops *rw; @@ -609,6 +927,9 @@ boolean I_LoadSong(char *data, size_t len) ) I_UnloadSong(); + // always do this whether or not a music already exists + var_cleanup(); + #ifdef HAVE_LIBGME if ((UINT8)data[0] == 0x1F && (UINT8)data[1] == 0x8B) @@ -718,30 +1039,88 @@ boolean I_LoadSong(char *data, size_t len) // Find the OGG loop point. loop_point = 0.0f; + song_length = 0.0f; while ((UINT32)(p - data) < len) { - if (strncmp(p++, key1, key1len)) - continue; - p += key1len-1; // skip OOP (the L was skipped in strncmp) - if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=? + if (fpclassify(loop_point) == FP_ZERO && !strncmp(p, key1, key1len)) { - p += key2len; // skip POINT= - loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count. - // because SDL_Mixer is USELESS and can't even tell us - // something simple like the frequency of the streaming music, - // we are unfortunately forced to assume that ALL MUSIC is 44100hz. - // This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly. + p += key1len; // skip LOOP + if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=? + { + p += key2len; // skip POINT= + loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count. + // because SDL_Mixer is USELESS and can't even tell us + // something simple like the frequency of the streaming music, + // we are unfortunately forced to assume that ALL MUSIC is 44100hz. + // This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly. + } + else if (!strncmp(p, key3, key3len)) // is it LOOPMS=? + { + p += key3len; // skip MS= + loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds. + // Everything that uses LOOPMS will work perfectly with SDL_Mixer. + } } - else if (!strncmp(p, key3, key3len)) // is it LOOPMS=? + else if (fpclassify(song_length) == FP_ZERO && !strncmp(p, key4, key4len)) // is it LENGTHMS=? { - p += key3len; // skip MS= - loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds. - // Everything that uses LOOPMS will work perfectly with SDL_Mixer. + p += key4len; // skip LENGTHMS + song_length = (float)(atoi(p) / 1000.0L); + } + // below: search MP3 or other tags that use wide char encoding + else if (fpclassify(loop_point) == FP_ZERO && !memcmp(p, key1w, key1len*2)) // LOOP wide char + { + p += key1len*2; + if (!memcmp(p, key2w, (key2len+1)*2)) // POINT= wide char + { + p += (key2len+1)*2; + wstart = (size_t)p; + wp = 0; + while (wp < 9 && memcmp(p, wterm, 2)) + { + wval[wp] = *p; + p += 2; + wp = ((size_t)(p-wstart))/2; + } + wval[min(wp, 9)] = 0; + loop_point = (float)((44.1L+atoi(wval) / 44100.0L)); + } + else if (!memcmp(p, key3w, (key3len+1)*2)) // MS= wide char + { + p += (key3len+1)*2; + wstart = (size_t)p; + wp = 0; + while (wp < 9 && memcmp(p, wterm, 2)) + { + wval[wp] = *p; + p += 2; + wp = ((size_t)(p-wstart))/2; + } + wval[min(wp, 9)] = 0; + loop_point = (float)(atoi(wval) / 1000.0L); + } + } + else if (fpclassify(song_length) == FP_ZERO && !memcmp(p, key4w, (key4len+1)*2)) // LENGTHMS= wide char + { + p += (key4len+1)*2; + wstart = (size_t)p; + wp = 0; + while (wp < 9 && memcmp(p, wterm, 2)) + { + wval[wp] = *p; + p += 2; + wp = ((size_t)(p-wstart))/2; + } + wval[min(wp, 9)] = 0; + song_length = (float)(atoi(wval) / 1000.0L); } - // Neither?! Continue searching. - } + if (fpclassify(loop_point) != FP_ZERO && fpclassify(song_length) != FP_ZERO && song_length > loop_point) // Got what we needed + // the last case is a sanity check, in case the wide char searches were false matches. + break; + else // continue searching + p++; + } return true; } @@ -765,7 +1144,6 @@ void I_UnloadSong(void) boolean I_PlaySong(boolean looping) { - boolean lpz = fpclassify(loop_point) == FP_ZERO; #ifdef HAVE_LIBGME if (gme) { @@ -779,21 +1157,37 @@ boolean I_PlaySong(boolean looping) if (!music) return false; + if (fpclassify(song_length) == FP_ZERO && (I_SongType() == MU_OGG || I_SongType() == MU_MP3 || I_SongType() == MU_FLAC)) + CONS_Debug(DBG_DETAILED, "This song is missing a LENGTHMS= tag! Required to make seeking work properly.\n"); - if (Mix_PlayMusic(music, looping && lpz ? -1 : 0) == -1) + if (I_SongType() != MU_MOD && I_SongType() != MU_MID && Mix_PlayMusic(music, 0) == -1) + { + CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError()); + return false; + } + else if ((I_SongType() == MU_MOD || I_SongType() == MU_MID) && Mix_PlayMusic(music, looping ? -1 : 0) == -1) // if MOD, loop forever { CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError()); return false; } - Mix_VolumeMusic((UINT32)music_volume*128/31); - if (!lpz) - Mix_HookMusicFinished(music_loop); + is_looping = looping; + + I_SetMusicVolume(music_volume); + + if (I_SongType() != MU_MOD && I_SongType() != MU_MID) + Mix_HookMusicFinished(music_loop); // don't bother counting if MOD + + if(I_SongType() != MU_MOD && I_SongType() != MU_MID && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL)) + CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError()); + return true; } void I_StopSong(void) { + I_StopFadingSong(); + #ifdef HAVE_LIBGME if (gme) { @@ -803,19 +1197,40 @@ void I_StopSong(void) #endif if (music) { + Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); Mix_HookMusicFinished(NULL); Mix_HaltMusic(); } + + var_cleanup(); } void I_PauseSong(void) { + if(I_SongType() == MU_MID) // really, SDL Mixer? why can't you pause MIDI??? + return; + + if(I_SongType() != MU_GME && I_SongType() != MU_MOD && I_SongType() != MU_MID) + Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); + Mix_PauseMusic(); songpaused = true; } void I_ResumeSong(void) { + if (I_SongType() == MU_MID) + return; + + if (I_SongType() != MU_GME && I_SongType() != MU_MOD && I_SongType() != MU_MID) + { + while(Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes) != 0) { } + // HACK: fixes issue of multiple effect callbacks being registered + + if(music && I_SongType() != MU_MOD && I_SongType() != MU_MID && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL)) + CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError()); + } + Mix_ResumeMusic(); songpaused = false; } @@ -834,7 +1249,7 @@ void I_SetMusicVolume(UINT8 volume) #endif music_volume = volume; - Mix_VolumeMusic((UINT32)music_volume*128/31); + Mix_VolumeMusic(get_real_volume(music_volume)); } boolean I_SetSongTrack(int track) @@ -863,9 +1278,100 @@ boolean I_SetSongTrack(int track) SDL_UnlockAudio(); return false; } + else #endif + if (I_SongType() == MU_MOD) + return !Mix_SetMusicPosition(track); (void)track; return false; } +/// ------------------------ +/// MUSIC FADING +/// ------------------------ + +void I_SetInternalMusicVolume(UINT8 volume) +{ + internal_volume = volume; + if (!I_SongPlaying()) + return; + Mix_VolumeMusic(get_real_volume(music_volume)); +} + +void I_StopFadingSong(void) +{ + if (fading_id) + SDL_RemoveTimer(fading_id); + is_fading = false; + fading_source = fading_target = fading_timer = fading_duration = fading_id = 0; +} + +boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void)) +{ + INT16 volume_delta; + + source_volume = min(source_volume, 100); + volume_delta = (INT16)(target_volume - source_volume); + + I_StopFadingSong(); + + if (!ms && volume_delta) + { + I_SetInternalMusicVolume(target_volume); + if (callback) + (*callback)(); + return true; + + } + else if (!volume_delta) + { + if (callback) + (*callback)(); + return true; + } + + // Round MS to nearest 10 + // If n - lower > higher - n, then round up + ms = (ms - ((ms / 10) * 10) > (((ms / 10) * 10) + 10) - ms) ? + (((ms / 10) * 10) + 10) // higher + : ((ms / 10) * 10); // lower + + if (!ms) + I_SetInternalMusicVolume(target_volume); + else if (source_volume != target_volume) + { + fading_id = SDL_AddTimer(10, music_fade, NULL); + if (fading_id) + { + is_fading = true; + fading_timer = fading_duration = ms; + fading_source = source_volume; + fading_target = target_volume; + fading_callback = callback; + + if (internal_volume != source_volume) + I_SetInternalMusicVolume(source_volume); + } + } + + return is_fading; +} + +boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)) +{ + return I_FadeSongFromVolume(target_volume, internal_volume, ms, callback); +} + +boolean I_FadeOutStopSong(UINT32 ms) +{ + return I_FadeSongFromVolume(0, internal_volume, ms, &I_StopSong); +} + +boolean I_FadeInPlaySong(UINT32 ms, boolean looping) +{ + if (I_PlaySong(looping)) + return I_FadeSongFromVolume(100, 0, ms, NULL); + else + return false; +} #endif diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index 412102790..e32da0614 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -1375,6 +1375,37 @@ boolean I_SetSongSpeed(float speed) return false; } +/// ------------------------ +// MUSIC SEEKING +/// ------------------------ + +UINT32 I_GetSongLength(void) +{ + return 0; +} + +boolean I_SetSongLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetSongLoopPoint(void) +{ + return 0; +} + +boolean I_SetSongPosition(UINT32 position) +{ + (void)position; + return false; +} + +UINT32 I_GetSongPosition(void) +{ + return 0; +} + /// ------------------------ // MUSIC PLAYBACK /// ------------------------ @@ -1443,6 +1474,47 @@ boolean I_SetSongTrack(int track) return false; } +/// ------------------------ +/// MUSIC FADING +/// ------------------------ + +void I_SetInternalMusicVolume(UINT8 volume) +{ + (void)volume; +} + +void I_StopFadingSong(void) +{ +} + +boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void)) +{ + (void)target_volume; + (void)source_volume; + (void)ms; + return false; +} + +boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)) +{ + (void)target_volume; + (void)ms; + return false; +} + +boolean I_FadeOutStopSong(UINT32 ms) +{ + (void)ms; + return false; +} + +boolean I_FadeInPlaySong(UINT32 ms, boolean looping) +{ + (void)ms; + (void)looping; + return false; +} + /// ------------------------ // MUSIC LOADING AND CLEANUP // \todo Split logic between loading and playing, diff --git a/src/sdl/srb2icon.png b/src/sdl/srb2icon.png new file mode 100644 index 000000000..cdee18a84 Binary files /dev/null and b/src/sdl/srb2icon.png differ diff --git a/src/sdl12/Srb2SDL-vc10.vcxproj b/src/sdl12/Srb2SDL-vc10.vcxproj index 958cd7d02..99916f58d 100644 --- a/src/sdl12/Srb2SDL-vc10.vcxproj +++ b/src/sdl12/Srb2SDL-vc10.vcxproj @@ -835,6 +835,16 @@ %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) @@ -1293,6 +1303,7 @@ + diff --git a/src/sdl12/Srb2SDL-vc9.vcproj b/src/sdl12/Srb2SDL-vc9.vcproj index d2a268f8d..fa386e381 100644 --- a/src/sdl12/Srb2SDL-vc9.vcproj +++ b/src/sdl12/Srb2SDL-vc9.vcproj @@ -2790,6 +2790,50 @@ + + + + + + + + + + + + + + + + diff --git a/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj index de12201f5..1f8e3276a 100644 --- a/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj +++ b/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj @@ -1365,6 +1365,20 @@ path = ../../m_misc.h; refType = 2; }; + 84177764085A10EB000C01D8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = apng.c; + path = ../../apng.c; + refType = 2; + }; + 84177765085A10EB000C01D8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = m_misc.h; + path = ../../apng.h; + refType = 2; + }; 84177766085A10EB000C01D8 = { fileEncoding = 30; isa = PBXFileReference; diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj index 0ab40c45e..69c544c56 100644 --- a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 1E44AF0D0B67CDE900BAD059 /* m_fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AEFE0B67CDE900BAD059 /* m_fixed.c */; }; 1E44AF0F0B67CDE900BAD059 /* m_menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF000B67CDE900BAD059 /* m_menu.c */; }; 1E44AF110B67CDE900BAD059 /* m_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF020B67CDE900BAD059 /* m_misc.c */; }; + 1E44AF110B67CDE900BAD059 /* apng.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF020B67CDE900BAD059 /* apng.c */; }; 1E44AF130B67CDE900BAD059 /* m_random.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF040B67CDE900BAD059 /* m_random.c */; }; 1E44AF1A0B67CE2A00BAD059 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF180B67CE2A00BAD059 /* info.c */; }; 1E44AF1E0B67CE3600BAD059 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF1C0B67CE3600BAD059 /* md5.c */; }; @@ -254,6 +255,8 @@ 1E44AF010B67CDE900BAD059 /* m_menu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_menu.h; path = ../../m_menu.h; sourceTree = SOURCE_ROOT; }; 1E44AF020B67CDE900BAD059 /* m_misc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_misc.c; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; 1E44AF030B67CDE900BAD059 /* m_misc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_misc.h; path = ../../m_misc.h; sourceTree = SOURCE_ROOT; }; + 1E44AF020B67CDE900BAD059 /* apng.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = apng.c; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; + 1E44AF030B67CDE900BAD059 /* apng.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = apng.h; path = ../../m_misc.h; sourceTree = SOURCE_ROOT; }; 1E44AF040B67CDE900BAD059 /* m_random.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_random.c; path = ../../m_random.c; sourceTree = SOURCE_ROOT; }; 1E44AF050B67CDE900BAD059 /* m_random.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_random.h; path = ../../m_random.h; sourceTree = SOURCE_ROOT; }; 1E44AF060B67CDE900BAD059 /* m_swap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_swap.h; path = ../../m_swap.h; sourceTree = SOURCE_ROOT; }; @@ -679,6 +682,8 @@ 1E44AEFF0B67CDE900BAD059 /* m_fixed.h */, 1E44AF020B67CDE900BAD059 /* m_misc.c */, 1E44AF030B67CDE900BAD059 /* m_misc.h */, + 1E44AF020B67CDE900BAD059 /* apng.c */, + 1E44AF030B67CDE900BAD059 /* apng.h */, 676BB51C0E0DE06100C95963 /* m_queue.c */, 676BB51D0E0DE06100C95963 /* m_queue.h */, 1E44AF040B67CDE900BAD059 /* m_random.c */, diff --git a/src/w_wad.c b/src/w_wad.c index da2d5128e..4d95c3bbd 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -185,6 +185,7 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors) static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum) { UINT16 posStart, posEnd; +#ifdef HAVE_BLUA posStart = W_CheckNumForFolderStartPK3("Lua/", wadnum, 0); if (posStart != INT16_MAX) { @@ -193,6 +194,7 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum) for (; posStart < posEnd; posStart++) LUA_LoadLump(wadnum, posStart); } +#endif posStart = W_CheckNumForFolderStartPK3("SOC/", wadnum, 0); if (posStart != INT16_MAX) { @@ -792,9 +794,11 @@ UINT16 W_InitFile(const char *filename) CONS_Printf(M_GetText("Loading SOC from %s\n"), wadfile->filename); DEH_LoadDehackedLumpPwad(numwadfiles - 1, 0); break; +#ifdef HAVE_BLUA case RET_LUA: LUA_LoadLump(numwadfiles - 1, 0); break; +#endif default: break; } diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj index ca73b1293..774ce5cbe 100644 --- a/src/win32/Srb2win-vc10.vcxproj +++ b/src/win32/Srb2win-vc10.vcxproj @@ -182,6 +182,7 @@ + @@ -330,6 +331,7 @@ + diff --git a/src/win32/Srb2win-vc9.vcproj b/src/win32/Srb2win-vc9.vcproj index 24235bc7b..a64b8638c 100644 --- a/src/win32/Srb2win-vc9.vcproj +++ b/src/win32/Srb2win-vc9.vcproj @@ -2851,6 +2851,50 @@ RelativePath="..\m_misc.h" > + + + + + + + + + + + + + + + + diff --git a/src/win32/win_snd.c b/src/win32/win_snd.c index 454c53e37..f3e3bbed4 100644 --- a/src/win32/win_snd.c +++ b/src/win32/win_snd.c @@ -815,6 +815,60 @@ void I_SetMusicVolume(UINT8 volume) FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); } +UINT32 I_GetSongLength(void) +{ + UINT32 length; + if (I_SongType() == MU_MID) + return 0; + FMR_MUSIC(FMOD_Sound_GetLength(music_stream, &length, FMOD_TIMEUNIT_MS)); + return length; +} + +boolean I_SetSongLoopPoint(UINT32 looppoint) +{ + (void)looppoint; + return false; +} + +UINT32 I_GetSongLoopPoint(void) +{ + return 0; +} + +boolean I_SetSongPosition(UINT32 position) +{ + FMOD_RESULT e; + if(I_SongType() == MU_MID) + // Dummy out; this works for some MIDI, but not others. + // SDL does not support this for any MIDI. + return false; + e = FMOD_Channel_SetPosition(music_channel, position, FMOD_TIMEUNIT_MS); + if (e == FMOD_OK) + return true; + else if (e == FMOD_ERR_UNSUPPORTED // Only music modules, numbnuts! + || e == FMOD_ERR_INVALID_POSITION) // Out-of-bounds! + return false; + else // Congrats, you horribly broke it somehow + { + FMR_MUSIC(e); + return false; + } +} + +UINT32 I_GetSongPosition(void) +{ + FMOD_RESULT e; + unsigned int fmposition = 0; + if(I_SongType() == MU_MID) + // Dummy out because unsupported, even though FMOD does this correctly. + return 0; + e = FMOD_Channel_GetPosition(music_channel, &fmposition, FMOD_TIMEUNIT_MS); + if (e == FMOD_OK) + return (UINT32)fmposition; + else + return 0; +} + boolean I_SetSongTrack(INT32 track) { if (track != current_track) // If the track's already playing, then why bother? @@ -859,3 +913,46 @@ boolean I_SetSongTrack(INT32 track) } return false; } + +/// ------------------------ +/// MUSIC FADING +/// ------------------------ + +void I_SetInternalMusicVolume(UINT8 volume) +{ + (void)volume; +} + +void I_StopFadingSong(void) +{ +} + +boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void)) +{ + (void)target_volume; + (void)source_volume; + (void)ms; + (void)callback; + return false; +} + +boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)) +{ + (void)target_volume; + (void)ms; + (void)callback; + return false; +} + +boolean I_FadeOutStopSong(UINT32 ms) +{ + (void)ms; + return false; +} + +boolean I_FadeInPlaySong(UINT32 ms, boolean looping) +{ + (void)ms; + (void)looping; + return false; +} diff --git a/src/y_inter.c b/src/y_inter.c index 4b340cabd..ed4972d2e 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -696,7 +696,19 @@ void Y_Ticker(void) boolean anybonuses = false; if (!intertic) // first time only - S_ChangeMusicInternal("lclear", false); // don't loop it + { + if (mapheaderinfo[gamemap-1]->musinterfadeout +#ifdef _WIN32 + // can't fade midi due to win32 volume hack + && S_MusicType() != MU_MID +#endif + ) + S_FadeOutStopMusic(mapheaderinfo[gamemap-1]->musinterfadeout); + else if (mapheaderinfo[gamemap-1]->musintername[0] && S_MusicExists(mapheaderinfo[gamemap-1]->musintername, !midi_disabled, !digital_disabled)) + S_ChangeMusicInternal(mapheaderinfo[gamemap-1]->musintername, false); // don't loop it + else + S_ChangeMusicInternal("lclear", false); // don't loop it + } if (intertic < TICRATE) // one second pause before tally begins return; @@ -757,7 +769,17 @@ void Y_Ticker(void) if (!intertic) // first time only { - S_ChangeMusicInternal("lclear", false); // don't loop it + if (mapheaderinfo[gamemap-1]->musinterfadeout +#ifdef _WIN32 + // can't fade midi due to win32 volume hack + && S_MusicType() != MU_MID +#endif + ) + S_FadeOutStopMusic(mapheaderinfo[gamemap-1]->musinterfadeout); + else if (mapheaderinfo[gamemap-1]->musintername[0] && S_MusicExists(mapheaderinfo[gamemap-1]->musintername, !midi_disabled, !digital_disabled)) + S_ChangeMusicInternal(mapheaderinfo[gamemap-1]->musintername, false); // don't loop it + else + S_ChangeMusicInternal("lclear", false); // don't loop it tallydonetic = 0; }