diff --git a/.circleci/config.yml b/.circleci/config.yml
index ca9105685d1d3696fbd350954b703db7d61b5568..1784ba1ea19e89810a83d939c69d4199c39573c5 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -3,7 +3,7 @@ jobs:
   build:
     working_directory: /root/SRB2
     docker:
-      - image: debian:jessie
+      - image: debian:stretch
         environment:
           CC: ccache gcc -m32
           PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
@@ -36,14 +36,20 @@ 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 libpng-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: Clean build
+          name: Compile without network support and BLUA
+          command: make -C src LINUX=1 ERRORMODE=1 -k NONET=1 NO_LUA=1
+      - run:
+          name: wipe build
+          command: make -C src LINUX=1 cleandep
+      - run:
+          name: rebuild depend
           command: make -C src LINUX=1 clean
       - restore_cache:
           keys:
diff --git a/.travis.yml b/.travis.yml
index e9c8d0d71928500effecd312622b7ba1ea11ce95..6d2e8cddfc1d55810123c5da2a083197dc2cec9f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,6 +26,7 @@ matrix:
               - p7zip-full
               - gcc-4.4
           compiler: gcc-4.4
+          env: GCC44=1
           if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-4.4 (Ubuntu/Linaro 4.4.7-8ubuntu1) 4.4.7
         - os: linux
@@ -39,6 +40,7 @@ matrix:
               - p7zip-full
               - gcc-4.6
           compiler: gcc-4.6
+          env: GCC46=1
           if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-4.6 (Ubuntu/Linaro 4.6.4-6ubuntu2) 4.6.4
         - os: linux
@@ -52,10 +54,12 @@ matrix:
               - p7zip-full
               - gcc-4.7
           compiler: gcc-4.7
+          env: GCC47=1
           if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-4.7
         - os: linux
           compiler: gcc
+          env: GCC48=1
           if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
         - os: linux
@@ -71,6 +75,7 @@ matrix:
               - p7zip-full
               - gcc-4.8
           compiler: gcc-4.8
+          env: GCC48=1
           if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
         - os: linux
@@ -86,7 +91,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
           if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-7 (Ubuntu 7.2.0-1ubuntu1~14.04) 7.2.0 20170802
         - os: linux
@@ -102,7 +107,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 -Wno-error=format-truncation" GCC81=1
           if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-8 (Ubuntu 7.2.0-1ubuntu1~14.04) 8.1.0
         - os: linux
@@ -249,17 +254,21 @@ matrix:
 #          osx_image: xcode7.2
 #          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 #          #Apple LLVM version 7.0.2 (clang-700.1.81)
+#        - os: osx
+#          osx_image: xcode7.3
+#          #Apple LLVM version 7.3.0 (clang-703.0.31)
+#        - os: osx
+#          osx_image: xcode7.3
+#          #Apple LLVM version 7.3.0 (clang-703.0.31)
         - os: osx
-          osx_image: xcode7.3
           if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
-          #Apple LLVM version 7.3.0 (clang-703.0.31)
+          #Default: macOS 10.13 and Xcode 9.4.1
 
 
 ################################
 # Deployer Buildbots - OSX
 ################################
         - os: osx
-          osx_image: xcode7.3
           if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
               AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
               AND env(DPL_TERMINATE_MAIN) != "1"
@@ -559,6 +568,16 @@ addons:
     - libgme-dev
     - zlib1g-dev
     - p7zip-full
+  homebrew:
+    taps:
+    - mazmazz/srb2
+    packages:
+    - sdl2_mixer
+    - game-music-emu
+    - p7zip
+    - cmake
+    update: true
+
 
 
 before_install:
@@ -591,18 +610,10 @@ install:
   #     * `sdl2_mixer` requires options from the formula tap https://github.com/mazmazz/homebrew-srb2
   #     * `brew postinstall` runs post-install scripts after building a bottle
   - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
-      brew update;
-      brew tap mazmazz/srb2;
-    fi;
-  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
-      if [[ "$__DPL_ACTIVE" != "1" ]]; then
-        brew install sdl2 sdl2_mixer game-music-emu p7zip;
-        brew install cmake||true;
-      else
-        brew install --build-bottle sdl2 game-music-emu p7zip;
+      if [[ "$__DPL_ACTIVE" == "1" ]]; then
+        brew install --build-bottle sdl2 game-music-emu;
         brew install --build-bottle mazmazz/srb2/sdl2_mixer --with-flac --with-mpg123;
-        brew postinstall sdl2 game-music-emu p7zip mazmazz/srb2/sdl2_mixer;
-        brew install cmake||true;
+        brew postinstall sdl2 game-music-emu mazmazz/srb2/sdl2_mixer;
       fi;
     fi
   - mkdir -p $HOME/srb2_cache
@@ -667,7 +678,6 @@ before_script:
       -DCPACK_PACKAGE_VENDOR="${PROGRAM_VENDOR}"
       -DSRB2_SDL2_EXE_NAME="${PROGRAM_FILENAME}"
 
-
 script:
   # Build our Makefile from Cmake!
   - if [[ "$__DPL_ACTIVE" == "1" ]]; then
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bc198e81b90a83c300fd5a51867f1d8e146d345f..fe5ee33eabce86b6aae4cdc3c25a502444889066 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -56,13 +56,19 @@ macro(copy_files_to_build_dir target dlllist_var)
 	endif()
 endmacro()
 
-# 64-bit check
-if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+# bitness check
+set(SRB2_SYSTEM_BITS 0)
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
 	message(STATUS "Target is 64-bit")
 	set(SRB2_SYSTEM_BITS 64)
-else()
+endif()
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+	message(STATUS "Target is 32-bit")
 	set(SRB2_SYSTEM_BITS 32)
 endif()
+if(${SRB2_SYSTEM_BITS} EQUAL 0)
+	message(STATUS "Target bitness is unknown")
+endif()
 
 # OS macros
 if (UNIX)
diff --git a/libs/dll-binaries/i686/libgme.dll b/libs/dll-binaries/i686/libgme.dll
index ddf8b0d82e703c2ecb847ed9453f1d58bc6f7cad..9a31bc4d2e0c1d0c0be5c8215c704a92320b9e62 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 2ba99450f5c7a9372a5eaa67ccdb1ee20dd5c81c..598c2d71cf80e4d2556691e1eb71edd7020a2f26 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 8beee872f9e44da54c16a2f4e8f489570915eedf..392b01856da89e07ac5430d4db0df223194152f3 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 62391ebb5e286fa5a6d0242033a001f655bd4f25..034ba48217586d0bea7c2a72ffd7565c94e4c970 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 551782518aad88cd0fdb7bbe4fae4e2cab168654..741574afe051e8455b816fd3c6275224b87c10e3 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 53fab4186aa2209fd93b253f4569b93b1f304ad0..5222fe271449fc4ec4b98913553f440b0a028032 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 d9a2452c70e91388c1ed9416b1e7f439a4ac60a9..5a7d2f560f0ce2c6efd52bc0a8e7bf07e3e9a25b 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 <gblargg@gmail.com>
-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 <gblargg@gmail.com>
+Maintainer : Michael Pyne <mpyne@purinchu.net>
+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 3c6464fc775903829082d5c9e61bd7441f2b15e8..534be8a858b4c2d0e546d8096318aff4346e434a 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 5bbfbf551d8d54304d9bc1ee81a4b860ab850e15..f18928f4bf0d9b5660d2e1ead32e458c57368cf6 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 acf571f6711fe47679c97239a4c1adae7e9160ff..6c22b678e5de3c81d1286adf3a7f3d95f79024df 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 <zlib.h>
+
 // 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 30b25dcfc64b08fef7ecee36a76514f2ef62d79e..942e86e27db8bf23a9495d734714818ca04ed110 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 b96f4b61177a8a507cd2c29149d2705d34565a2b..d98f7ce7ea06dbcb2e7b595e7c0e2dc638502a1d 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 824a1a24006bb0b05cb11197345021541c7ea9c9..55ac4688fff1773f424eed8db56177677f560125 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 90f60ed2970e772c49a18dee81152889935d75fc..19aae1135de0abaf1c5c1ae1f669d7e6f26ca22b 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 4742e09908038f6e4bb77023bb6308e71df5a4e5..10c2450909d5b7054f95a218476a082020ccd4ed 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 b011777ad8f786fdc73d0d418d5f4acf3dbd2625..b65afd30b62e174260ea26c230e22306d3c55a03 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 c05f25eb444961d3d8db18a7f58e9a0311b5c969..47709840a031d5ef8606cee8b05add7c9879353b 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 1f2a2d15007755788884f879444f4fb05a675324..cb07061b4b9ab0c4d20de0a5148de5be8098ba78 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 4f420d9edab58d30b6620d3464722d80046aa85a..49fd5b1df44294e3cd76821c7e88cca1e4922b04 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 1f2a2d15007755788884f879444f4fb05a675324..cb07061b4b9ab0c4d20de0a5148de5be8098ba78 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 82a501dbdad2e5bb4c4ec80e7f4eb210fab9f754..4cfe5e7a8e71b121556df97736d6ddc68d4d1840 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 <gblargg@gmail.com>
-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 <mpyne@purinchu.net>
 
 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 d56d87396d511830d163ef4d081584eeac2d4e21..2c5e95853e7d8897e23debb4d0d2fa6ddbd8e651 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 38079dc2a2c01b010c94e78d5285ba3781c7eb9e..8348f12de7973c43e23d17be8f9b52d35c1c2cc2 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 4a9ef5ba8ccb37106b2d1779770e2539c74d8763..a6fab34ff621af052079ac5c8acb145f7ab8f65e 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 c894203a4e509b638600763d651df2712a9f1cd0..6363ab7dc2cf907db106e9f0ffae5813044732cf 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 1238050b3441de6c349180a574e38947b85e8347..a0398154a5c14a80b0e408c1413e4f48597cac74 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/apng.c b/src/apng.c
new file mode 100644
index 0000000000000000000000000000000000000000..694b3d1e8b5d90efb45bb0145960e3061b9cf5aa
--- /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 <stdlib.h>
+#include <string.h>
+
+#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 0000000000000000000000000000000000000000..aa7fac3df34e7ee14fe9504722a87005cf0f4ae9
--- /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 <png.h>
+
+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/command.c b/src/command.c
index ba0095e079b4a6be92a0e9983217d9e6432325fa..de5a99d510ecff134622c9f1459007bfdc9bbfee 100644
--- a/src/command.c
+++ b/src/command.c
@@ -148,6 +148,20 @@ void COM_BufInsertText(const char *ptext)
 	}
 }
 
+/** Progress the wait timer and flush waiting console commands when ready.
+  */
+void
+COM_BufTicker(void)
+{
+	if (com_wait)
+	{
+		com_wait--;
+		return;
+	}
+
+	COM_BufExecute();
+}
+
 /** Flushes (executes) console commands in the buffer.
   */
 void COM_BufExecute(void)
@@ -157,12 +171,6 @@ void COM_BufExecute(void)
 	char line[1024] = "";
 	INT32 quotes;
 
-	if (com_wait)
-	{
-		com_wait--;
-		return;
-	}
-
 	while (com_text.cursize)
 	{
 		// find a '\n' or; line break
@@ -514,7 +522,6 @@ static void COM_ExecuteString(char *ptext)
 	{
 		if (!stricmp(com_argv[0], cmd->name)) //case insensitive now that we have lower and uppercase!
 		{
-			recursion = 0;
 			cmd->function();
 			return;
 		}
@@ -526,19 +533,17 @@ static void COM_ExecuteString(char *ptext)
 		if (!stricmp(com_argv[0], a->name))
 		{
 			if (recursion > MAX_ALIAS_RECURSION)
-			{
 				CONS_Alert(CONS_WARNING, M_GetText("Alias recursion cycle detected!\n"));
-				recursion = 0;
-				return;
+			else
+			{ // Monster Iestyn: keep track of how many levels of recursion we're in
+				recursion++;
+				COM_BufInsertText(a->value);
+				recursion--;
 			}
-			recursion++;
-			COM_BufInsertText(a->value);
 			return;
 		}
 	}
 
-	recursion = 0;
-
 	// check cvars
 	// Hurdler: added at Ebola's request ;)
 	// (don't flood the console in software mode with bad gr_xxx command)
diff --git a/src/command.h b/src/command.h
index e6767825c7561c56a0b62995c4ecb66c8399d925..4682ba4a4cf4f066599f8426c04b27dc05fa966c 100644
--- a/src/command.h
+++ b/src/command.h
@@ -45,6 +45,9 @@ void COM_ImmedExecute(const char *ptext);
 // Execute commands in buffer, flush them
 void COM_BufExecute(void);
 
+// As above; and progress the wait timer.
+void COM_BufTicker(void);
+
 // setup command buffer, at game tartup
 void COM_Init(void);
 
diff --git a/src/console.c b/src/console.c
index 5c173e4594cf2d62037779c77af5da27af9716c0..91baf25fcfe4fbfd6c2240258a8eccda23bebd8a 100644
--- a/src/console.c
+++ b/src/console.c
@@ -96,6 +96,7 @@ static size_t input_len; // length of current line, used to bound cursor and suc
 // protos.
 static void CON_InputInit(void);
 static void CON_RecalcSize(void);
+static void CON_ChangeHeight(void);
 
 static void CONS_hudlines_Change(void);
 static void CONS_backcolor_Change(void);
@@ -447,6 +448,12 @@ static void CON_RecalcSize(void)
 		con_destlines = vid.height;
 	}
 
+	if (con_destlines > 0) // Resize console if already open
+	{
+		CON_ChangeHeight();
+		con_curlines = con_destlines;
+	}
+
 	// check for change of video width
 	if (conw == con_width)
 		return; // didn't change
@@ -496,6 +503,20 @@ static void CON_RecalcSize(void)
 	Z_Free(tmp_buffer);
 }
 
+static void CON_ChangeHeight(void)
+{
+	INT32 minheight = 20 * con_scalefactor;	// 20 = 8+8+4
+
+	// toggle console in
+	con_destlines = (cons_height.value*vid.height)/100;
+	if (con_destlines < minheight)
+		con_destlines = minheight;
+	else if (con_destlines > vid.height)
+		con_destlines = vid.height;
+
+	con_destlines &= ~0x3; // multiple of text row height
+}
+
 // Handles Console moves in/out of screen (per frame)
 //
 static void CON_MoveConsole(void)
@@ -584,16 +605,7 @@ void CON_Ticker(void)
 			CON_ClearHUD();
 		}
 		else
-		{
-			// toggle console in
-			con_destlines = (cons_height.value*vid.height)/100;
-			if (con_destlines < minheight)
-				con_destlines = minheight;
-			else if (con_destlines > vid.height)
-				con_destlines = vid.height;
-
-			con_destlines &= ~0x3; // multiple of text row height
-		}
+			CON_ChangeHeight();
 	}
 
 	// console movement
@@ -1051,16 +1063,6 @@ boolean CON_Responder(event_t *ev)
 	else if (key == KEY_KPADSLASH)
 		key = '/';
 
-	// capslock
-	if (key == KEY_CAPSLOCK)	// it's a toggle.
-	{
-		if (capslock)
-			capslock = false;
-		else
-			capslock = true;
-		return true;
-	}
-
 	if (key >= 'a' && key <= 'z')
 	{
 		if (capslock ^ shiftdown)
@@ -1106,6 +1108,7 @@ static void CON_Print(char *msg)
 {
 	size_t l;
 	INT32 controlchars = 0; // for color changing
+	char color = '\x80';  // keep color across lines
 
 	if (msg == NULL)
 		return;
@@ -1131,7 +1134,7 @@ static void CON_Print(char *msg)
 		{
 			if (*msg & 0x80)
 			{
-				con_line[con_cx++] = *(msg++);
+				color = con_line[con_cx++] = *(msg++);
 				controlchars++;
 				continue;
 			}
@@ -1139,12 +1142,14 @@ static void CON_Print(char *msg)
 			{
 				con_cy--;
 				CON_Linefeed();
+				color = '\x80';
 				controlchars = 0;
 			}
 			else if (*msg == '\n') // linefeed
 			{
 				CON_Linefeed();
-				controlchars = 0;
+				con_line[con_cx++] = color;
+				controlchars = 1;
 			}
 			else if (*msg == ' ') // space
 			{
@@ -1152,7 +1157,8 @@ static void CON_Print(char *msg)
 				if (con_cx - controlchars >= con_width-11)
 				{
 					CON_Linefeed();
-					controlchars = 0;
+					con_line[con_cx++] = color;
+					controlchars = 1;
 				}
 			}
 			else if (*msg == '\t')
@@ -1167,7 +1173,8 @@ static void CON_Print(char *msg)
 				if (con_cx - controlchars >= con_width-11)
 				{
 					CON_Linefeed();
-					controlchars = 0;
+					con_line[con_cx++] = color;
+					controlchars = 1;
 				}
 			}
 			msg++;
@@ -1184,7 +1191,8 @@ static void CON_Print(char *msg)
 		if ((con_cx - controlchars) + l > con_width-11)
 		{
 			CON_Linefeed();
-			controlchars = 0;
+			con_line[con_cx++] = color;
+			controlchars = 1;
 		}
 
 		// a word at a time
@@ -1539,8 +1547,7 @@ static void CON_DrawConsole(void)
 	i = con_cy - con_scrollup;
 
 	// skip the last empty line due to the cursor being at the start of a new line
-	if (!con_scrollup && !con_cx)
-		i--;
+	i--;
 
 	i -= (con_curlines - minheight) / charheight;
 
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 2529b05d0e03b908ce3b3249d48dd4e62776c9f4..1b0cb523f85f4cf16ee4cfab4d84326aba0678e7 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
@@ -4561,7 +4563,7 @@ void TryRunTics(tic_t realtics)
 
 	if (realtics >= 1)
 	{
-		COM_BufExecute();
+		COM_BufTicker();
 		if (mapchangepending)
 			D_MapChange(-1, 0, ultimatemode, false, 2, false, fromlevelselect); // finish the map change
 	}
diff --git a/src/d_main.c b/src/d_main.c
index dd2cfe0e520308efc722ae06315cf60ba6676154..529c8360232742f8ccfe453f9bce0b32ea3129a5 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -176,37 +176,11 @@ void D_PostEvent_end(void) {};
 #endif
 
 // modifier keys
+// Now handled in I_OsPolling
 UINT8 shiftdown = 0; // 0x1 left, 0x2 right
 UINT8 ctrldown = 0; // 0x1 left, 0x2 right
 UINT8 altdown = 0; // 0x1 left, 0x2 right
 boolean capslock = 0;	// gee i wonder what this does.
-//
-// D_ModifierKeyResponder
-// Sets global shift/ctrl/alt variables, never actually eats events
-//
-static inline void D_ModifierKeyResponder(event_t *ev)
-{
-	if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1)
-	{
-		case KEY_LSHIFT: shiftdown |= 0x1; return;
-		case KEY_RSHIFT: shiftdown |= 0x2; return;
-		case KEY_LCTRL: ctrldown |= 0x1; return;
-		case KEY_RCTRL: ctrldown |= 0x2; return;
-		case KEY_LALT: altdown |= 0x1; return;
-		case KEY_RALT: altdown |= 0x2; return;
-		default: return;
-	}
-	else if (ev->type == ev_keyup) switch (ev->data1)
-	{
-		case KEY_LSHIFT: shiftdown &= ~0x1; return;
-		case KEY_RSHIFT: shiftdown &= ~0x2; return;
-		case KEY_LCTRL: ctrldown &= ~0x1; return;
-		case KEY_RCTRL: ctrldown &= ~0x2; return;
-		case KEY_LALT: altdown &= ~0x1; return;
-		case KEY_RALT: altdown &= ~0x2; return;
-		default: return;
-	}
-}
 
 //
 // D_ProcessEvents
@@ -220,9 +194,6 @@ void D_ProcessEvents(void)
 	{
 		ev = &events[eventtail];
 
-		// Set global shift/ctrl/alt down variables
-		D_ModifierKeyResponder(ev); // never eats events
-
 		// Screenshots over everything so that they can be taken anywhere.
 		if (M_ScreenshotResponder(ev))
 			continue; // ate the event
@@ -726,7 +697,6 @@ void D_StartTitle(void)
 	paused = false;
 	advancedemo = false;
 	F_StartTitleScreen();
-	CON_ToggleOff();
 
 	// Reset the palette
 	if (rendermode != render_none)
@@ -1396,13 +1366,13 @@ void D_SRB2Main(void)
 	}
 	else if (M_CheckParm("-skipintro"))
 	{
-		CON_ToggleOff();
-		CON_ClearHUD();
 		F_StartTitleScreen();
 	}
 	else
 		F_StartIntro(); // Tails 03-03-2002
 
+	CON_ToggleOff();
+
 	if (dedicated && server)
 	{
 		pagename = "TITLESKY";
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 11b9413a82905cf1e9066a72d4848b44e14d32d8..bee6b4091169413a483f66fea840711b03ca7a36 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -1831,9 +1831,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
 		CONS_Printf(M_GetText("Speeding off to level...\n"));
 	}
 
-	CON_ToggleOff();
-	CON_ClearHUD();
-
 	if (demoplayback && !timingdemo)
 		precache = false;
 
diff --git a/src/f_finale.c b/src/f_finale.c
index 64e3712118d23264e3b277591b5ea38fdfb727df..d4a468c5718e2cd1f0e58e0409efb7b72936d6cc 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -444,7 +444,6 @@ void F_StartIntro(void)
 	gameaction = ga_nothing;
 	paused = false;
 	CON_ToggleOff();
-	CON_ClearHUD();
 	F_NewCutscene(introtext[0]);
 
 	intro_scenenum = 0;
@@ -1146,7 +1145,6 @@ void F_StartCredits(void)
 	gameaction = ga_nothing;
 	paused = false;
 	CON_ToggleOff();
-	CON_ClearHUD();
 	S_StopMusic();
 
 	S_ChangeMusicInternal("credit", false);
@@ -1192,16 +1190,34 @@ void F_CreditDrawer(void)
 		if (FixedMul(y,vid.dupy) > vid.height)
 			break;
 	}
+}
+
+void F_CreditTicker(void)
+{
+	// "Simulate" the drawing of the credits so that dedicated mode doesn't get stuck
+	UINT16 i;
+	fixed_t y = (80<<FRACBITS) - 5*(animtimer<<FRACBITS)/8;
+
+	// Draw credits text on top
+	for (i = 0; credits[i]; i++)
+	{
+		switch(credits[i][0])
+		{
+			case 0: y += 80<<FRACBITS; break;
+			case 1: y += 30<<FRACBITS; break;
+			default: y += 12<<FRACBITS; break;
+		}
+		if (FixedMul(y,vid.dupy) > vid.height)
+			break;
+	}
 
+	// Do this here rather than in the drawer you doofus! (this is why dedicated mode broke at credits)
 	if (!credits[i] && y <= 120<<FRACBITS && !finalecount)
 	{
 		timetonext = 5*TICRATE+1;
 		finalecount = 5*TICRATE;
 	}
-}
 
-void F_CreditTicker(void)
-{
 	if (timetonext)
 		timetonext--;
 	else
@@ -1295,7 +1311,6 @@ void F_StartGameEvaluation(void)
 	gameaction = ga_nothing;
 	paused = false;
 	CON_ToggleOff();
-	CON_ClearHUD();
 
 	finalecount = 0;
 }
@@ -1405,7 +1420,6 @@ void F_StartGameEnd(void)
 	gameaction = ga_nothing;
 	paused = false;
 	CON_ToggleOff();
-	CON_ClearHUD();
 	S_StopMusic();
 
 	// In case menus are still up?!!
@@ -1608,7 +1622,6 @@ void F_StartContinue(void)
 	keypressed = false;
 	paused = false;
 	CON_ToggleOff();
-	CON_ClearHUD();
 
 	// In case menus are still up?!!
 	M_ClearMenus(true);
@@ -1779,8 +1792,6 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
 
 	F_NewCutscene(cutscenes[cutscenenum]->scene[0].text);
 
-	CON_ClearHUD();
-
 	cutsceneover = false;
 	runningprecutscene = precutscene;
 	precutresetplayer = resetplayer;
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index efecac52420b136c8952b8892d6a4222b457f2bd..7e0b369eb8d55cdfc303388f7d393c8f2aa5ab79 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -4246,10 +4246,43 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
 	}
 }
 
+// This is expecting a pointer to an array containing 4 wallVerts for a sprite
+static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts)
+{
+	if (cv_grspritebillboarding.value && spr && spr->mobj && wallVerts)
+	{
+		float basey = FIXED_TO_FLOAT(spr->mobj->z);
+		float lowy = wallVerts[0].y;
+		if (P_MobjFlip(spr->mobj) == -1)
+		{
+			basey = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height);
+		}
+		// Rotate sprites to fully billboard with the camera
+		// X, Y, AND Z need to be manipulated for the polys to rotate around the
+		// origin, because of how the origin setting works I believe that should
+		// be mobj->z or mobj->z + mobj->height
+		wallVerts[2].y = wallVerts[3].y = (spr->ty - basey) * gr_viewludsin + basey;
+		wallVerts[0].y = wallVerts[1].y = (lowy - basey) * gr_viewludsin + basey;
+		// translate back to be around 0 before translating back
+		wallVerts[3].x += ((spr->ty - basey) * gr_viewludcos) * gr_viewcos;
+		wallVerts[2].x += ((spr->ty - basey) * gr_viewludcos) * gr_viewcos;
+
+		wallVerts[0].x += ((lowy - basey) * gr_viewludcos) * gr_viewcos;
+		wallVerts[1].x += ((lowy - basey) * gr_viewludcos) * gr_viewcos;
+
+		wallVerts[3].z += ((spr->ty - basey) * gr_viewludcos) * gr_viewsin;
+		wallVerts[2].z += ((spr->ty - basey) * gr_viewludcos) * gr_viewsin;
+
+		wallVerts[0].z += ((lowy - basey) * gr_viewludcos) * gr_viewsin;
+		wallVerts[1].z += ((lowy - basey) * gr_viewludcos) * gr_viewsin;
+	}
+}
+
 static void HWR_SplitSprite(gr_vissprite_t *spr)
 {
 	float this_scale = 1.0f;
 	FOutVector wallVerts[4];
+	FOutVector baseWallVerts[4]; // This is what the verts should end up as
 	GLPatch_t *gpatch;
 	FSurfaceInfo Surf;
 	const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES);
@@ -4262,11 +4295,13 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
 	float realtop, realbot, top, bot;
 	float towtop, towbot, towmult;
 	float bheight;
+	float realheight, heightmult;
 	const sector_t *sector = spr->mobj->subsector->sector;
 	const lightlist_t *list = sector->lightlist;
 #ifdef ESLOPE
 	float endrealtop, endrealbot, endtop, endbot;
 	float endbheight;
+	float endrealheight;
 	fixed_t temp;
 	fixed_t v1x, v1y, v2x, v2y;
 #endif
@@ -4299,16 +4334,16 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
 		HWR_DrawSpriteShadow(spr, gpatch, this_scale);
 	}
 
-	wallVerts[0].x = wallVerts[3].x = spr->x1;
-	wallVerts[2].x = wallVerts[1].x = spr->x2;
-	wallVerts[0].z = wallVerts[3].z = spr->z1;
-	wallVerts[1].z = wallVerts[2].z = spr->z2;
+	baseWallVerts[0].x = baseWallVerts[3].x = spr->x1;
+	baseWallVerts[2].x = baseWallVerts[1].x = spr->x2;
+	baseWallVerts[0].z = baseWallVerts[3].z = spr->z1;
+	baseWallVerts[1].z = baseWallVerts[2].z = spr->z2;
 
-	wallVerts[2].y = wallVerts[3].y = spr->ty;
+	baseWallVerts[2].y = baseWallVerts[3].y = spr->ty;
 	if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f)
-		wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale;
+		baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height * this_scale;
 	else
-		wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height;
+		baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height;
 
 	v1x = FLOAT_TO_FIXED(spr->x1);
 	v1y = FLOAT_TO_FIXED(spr->z1);
@@ -4317,44 +4352,56 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
 
 	if (spr->flip)
 	{
-		wallVerts[0].sow = wallVerts[3].sow = gpatch->max_s;
-		wallVerts[2].sow = wallVerts[1].sow = 0;
-	}else{
-		wallVerts[0].sow = wallVerts[3].sow = 0;
-		wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s;
+		baseWallVerts[0].sow = baseWallVerts[3].sow = gpatch->max_s;
+		baseWallVerts[2].sow = baseWallVerts[1].sow = 0;
+	}
+	else
+	{
+		baseWallVerts[0].sow = baseWallVerts[3].sow = 0;
+		baseWallVerts[2].sow = baseWallVerts[1].sow = gpatch->max_s;
 	}
 
 	// flip the texture coords (look familiar?)
 	if (spr->vflip)
 	{
-		wallVerts[3].tow = wallVerts[2].tow = gpatch->max_t;
-		wallVerts[0].tow = wallVerts[1].tow = 0;
-	}else{
-		wallVerts[3].tow = wallVerts[2].tow = 0;
-		wallVerts[0].tow = wallVerts[1].tow = gpatch->max_t;
+		baseWallVerts[3].tow = baseWallVerts[2].tow = gpatch->max_t;
+		baseWallVerts[0].tow = baseWallVerts[1].tow = 0;
+	}
+	else
+	{
+		baseWallVerts[3].tow = baseWallVerts[2].tow = 0;
+		baseWallVerts[0].tow = baseWallVerts[1].tow = gpatch->max_t;
 	}
 
 	// if it has a dispoffset, push it a little towards the camera
 	if (spr->dispoffset) {
 		float co = -gr_viewcos*(0.05f*spr->dispoffset);
 		float si = -gr_viewsin*(0.05f*spr->dispoffset);
-		wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si;
-		wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si;
-		wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co;
-		wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co;
+		baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si;
+		baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si;
+		baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co;
+		baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co;
 	}
 
-	realtop = top = wallVerts[3].y;
-	realbot = bot = wallVerts[0].y;
-	towtop = wallVerts[3].tow;
-	towbot = wallVerts[0].tow;
+	// Let dispoffset work first since this adjust each vertex
+	HWR_RotateSpritePolyToAim(spr, baseWallVerts);
+
+	realtop = top = baseWallVerts[3].y;
+	realbot = bot = baseWallVerts[0].y;
+	towtop = baseWallVerts[3].tow;
+	towbot = baseWallVerts[0].tow;
 	towmult = (towbot - towtop) / (top - bot);
 
 #ifdef ESLOPE
-	endrealtop = endtop = wallVerts[2].y;
-	endrealbot = endbot = wallVerts[1].y;
+	endrealtop = endtop = baseWallVerts[2].y;
+	endrealbot = endbot = baseWallVerts[1].y;
 #endif
 
+	// copy the contents of baseWallVerts into the drawn wallVerts array
+	// baseWallVerts is used to know the final shape to easily get the vertex
+	// co-ordinates
+	memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
+
 	if (!cv_translucency.value) // translucency disabled
 	{
 		Surf.FlatColor.s.alpha = 0xFF;
@@ -4481,12 +4528,53 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
 		wallVerts[2].y = endtop;
 		wallVerts[0].y = bot;
 		wallVerts[1].y = endbot;
+
+		// The x and y only need to be adjusted in the case that it's not a papersprite
+		if (cv_grspritebillboarding.value && spr->mobj)
+		{
+			// Get the x and z of the vertices so billboarding draws correctly
+			realheight = realbot - realtop;
+			endrealheight = endrealbot - endrealtop;
+			heightmult = (realtop - top) / realheight;
+			wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
+			wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
+
+			heightmult = (endrealtop - endtop) / endrealheight;
+			wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
+			wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
+
+			heightmult = (realtop - bot) / realheight;
+			wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
+			wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
+
+			heightmult = (endrealtop - endbot) / endrealheight;
+			wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
+			wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
+		}
 #else
 		wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult);
 		wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult);
 
 		wallVerts[2].y = wallVerts[3].y = top;
 		wallVerts[0].y = wallVerts[1].y = bot;
+
+		// The x and y only need to be adjusted in the case that it's not a papersprite
+		if (cv_grspritebillboarding.value && spr->mobj)
+		{
+			// Get the x and z of the vertices so billboarding draws correctly
+			realheight = realbot - realtop;
+			heightmult = (realtop - top) / realheight;
+			wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
+			wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
+			wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
+			wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
+
+			heightmult = (realtop - bot) / realheight;
+			wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
+			wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
+			wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
+			wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
+		}
 #endif
 
 		if (colormap)
@@ -4655,6 +4743,9 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 		wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co;
 	}
 
+	// Let dispoffset work first since this adjust each vertex
+	HWR_RotateSpritePolyToAim(spr, wallVerts);
+
 	// This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black.
 	// sprite lighting by modulating the RGB components
 	/// \todo coloured
@@ -4736,6 +4827,9 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
 	wallVerts[0].z = wallVerts[3].z = spr->z1;
 	wallVerts[1].z = wallVerts[2].z = spr->z2;
 
+	// Let dispoffset work first since this adjust each vertex
+	HWR_RotateSpritePolyToAim(spr, wallVerts);
+
 	wallVerts[0].sow = wallVerts[3].sow = 0;
 	wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s;
 
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index 59042cf3b1c4c34f030397a8226385af9b726b9b..f86b198a18239bf685c47e014c0680dc6ba6b4c0 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -95,6 +95,7 @@ extern consvar_t cv_grcorrecttricks;
 extern consvar_t cv_voodoocompatibility;
 extern consvar_t cv_grfovchange;
 extern consvar_t cv_grsolvetjoin;
+extern consvar_t cv_grspritebillboarding;
 
 extern float gr_viewwidth, gr_viewheight, gr_baseviewwindowy;
 
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index e34e5c35c620a4f49161973b2d44eb439e791bfd..fdaf36cb2231ac67537fdf23a0618c953e7d814d 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -1072,7 +1072,9 @@ static INT16 typelines = 1; // number of drawfill lines we need when drawing the
 //
 boolean HU_Responder(event_t *ev)
 {
+#ifndef NONET
 	INT32 c=0;
+#endif
 
 	if (ev->type != ev_keydown)
 		return false;
@@ -1099,19 +1101,9 @@ boolean HU_Responder(event_t *ev)
 			return false;
 	}*/	//We don't actually care about that unless we get splitscreen netgames. :V
 
+#ifndef NONET
 	c = (INT32)ev->data1;
 
-	// capslock (now handled outside of chat on so that it works everytime......)
-	if (c && c == KEY_CAPSLOCK) // it's a toggle.
-	{
-		if (capslock)
-			capslock = false;
-		else
-			capslock = true;
-		return true;
-	}
-
-#ifndef NONET
 	if (!chat_on)
 	{
 		// enter chat mode
diff --git a/src/i_tcp.c b/src/i_tcp.c
index f8a65b754becc94aa0d4c76c03216b92db080e5f..11a84cebad5def2d4ae852261540f759a3feffd5 100644
--- a/src/i_tcp.c
+++ b/src/i_tcp.c
@@ -612,7 +612,7 @@ static boolean SOCK_Get(void)
 		if (c != ERRSOCKET)
 		{
 			// find remote node number
-			for (j = 0; j <= MAXNETNODES; j++) //include LAN
+			for (j = 1; j <= MAXNETNODES; j++) //include LAN
 			{
 				if (SOCK_cmpaddr(&fromaddress, &clientaddress[j], 0))
 				{
@@ -1340,8 +1340,12 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
 	while (runp != NULL)
 	{
 		// find ip of the server
-		memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen);
-		runp = NULL;
+		if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0)
+		{
+			memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen);
+			break;
+		}
+		runp = runp->ai_next;
 	}
 	I_freeaddrinfo(ai);
 	return newnode;
diff --git a/src/m_misc.c b/src/m_misc.c
index 7dd0d822c7ff9bd5b7f6c05b35f17dc7fba742c7..fe5215922c73e017cd60ae800453fdade3db3951 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -93,7 +93,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
@@ -792,13 +793,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
@@ -835,20 +836,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)
@@ -857,7 +858,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;
@@ -877,16 +878,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
 }
 
@@ -900,11 +901,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;
@@ -912,9 +908,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 */
@@ -927,57 +923,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)
@@ -1009,6 +969,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
@@ -1026,12 +996,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);
+
+	apng_set_acTL(apng_ptr, apng_info_ptr, apng_ainfo_ptr, PNG_UINT_31_MAX, 0);
 
-	png_write_info(apng_ptr, apng_info_ptr);
+	apng_write_info(apng_ptr, apng_info_ptr, apng_ainfo_ptr);
 
 	apng_frames = 0;
 
@@ -1234,8 +1203,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_inter.c b/src/p_inter.c
index 009a2be1f68f959f149fbf0f250f1bbc6df56e13..29450f6e1d075833d10b199faf87e128b8c040cc 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -2643,7 +2643,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
 	}
 }
 
-static inline void P_SuperDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage)
+static void P_SuperDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage)
 {
 	fixed_t fallbackspeed;
 	angle_t ang;
diff --git a/src/r_main.c b/src/r_main.c
index 94945af5b58e56b791d37f5b16089cd0e8a34d24..08b1ab2f0fb25f79dcdc297ab7e762d302fbb3e2 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1407,6 +1407,7 @@ void R_RegisterEngineStuff(void)
 	CV_RegisterVar(&cv_grcoronasize);
 #endif
 	CV_RegisterVar(&cv_grmd2);
+	CV_RegisterVar(&cv_grspritebillboarding);
 #endif
 
 #ifdef HWRENDER
diff --git a/src/r_segs.c b/src/r_segs.c
index 6d6ba1efd1c0dd7a62cfd130df0e2cc08adfa133..c82554ac865d0edac67b35a7cf212de82d48f53e 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -854,24 +854,26 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			if (leftheight > pfloorleft && rightheight > pfloorright && i+1 < dc_numlights)
 			{
 				lightlist_t *nextlight = &frontsector->lightlist[i+1];
-				if (nextlight->slope ? P_GetZAt(nextlight->slope, ds->leftpos.x, ds->leftpos.y) : nextlight->height > pfloorleft
-				 && nextlight->slope ? P_GetZAt(nextlight->slope, ds->rightpos.x, ds->rightpos.y) : nextlight->height > pfloorright)
+				if ((nextlight->slope ? P_GetZAt(nextlight->slope, ds->leftpos.x, ds->leftpos.y) : nextlight->height) > pfloorleft
+				 && (nextlight->slope ? P_GetZAt(nextlight->slope, ds->rightpos.x, ds->rightpos.y) : nextlight->height) > pfloorright)
 					continue;
 			}
 
 			leftheight -= viewz;
 			rightheight -= viewz;
 
-#define OVERFLOWTEST(height, scale) \
-	overflow_test = (INT64)centeryfrac - (((INT64)height*scale)>>FRACBITS); \
-	if (overflow_test < 0) overflow_test = -overflow_test; \
-	if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) continue;
-
-			OVERFLOWTEST(leftheight, ds->scale1)
-			OVERFLOWTEST(rightheight, ds->scale2)
-
-			rlight->height = (centeryfrac) - FixedMul(leftheight, ds->scale1);
-			rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2);
+#define CLAMPMAX INT32_MAX
+#define CLAMPMIN (-INT32_MAX) // This is not INT32_MIN on purpose! INT32_MIN makes the drawers freak out.
+			// Monster Iestyn (25/03/18): do not skip these lights if they fail overflow test, just clamp them instead so they behave.
+			overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS);
+			if      (overflow_test > (INT64)CLAMPMAX) rlight->height = CLAMPMAX;
+			else if (overflow_test > (INT64)CLAMPMIN) rlight->height = (fixed_t)overflow_test;
+			else                                      rlight->height = CLAMPMIN;
+
+			overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS);
+			if      (overflow_test > (INT64)CLAMPMAX) rlight->heightstep = CLAMPMAX;
+			else if (overflow_test > (INT64)CLAMPMIN) rlight->heightstep = (fixed_t)overflow_test;
+			else                                      rlight->heightstep = CLAMPMIN;
 			rlight->heightstep = (rlight->heightstep-rlight->height)/(range);
 #else
 			if (light->height < *pfloor->bottomheight)
@@ -893,12 +895,16 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 				leftheight -= viewz;
 				rightheight -= viewz;
 
-				OVERFLOWTEST(leftheight, ds->scale1)
-				OVERFLOWTEST(rightheight, ds->scale2)
-#undef OVERFLOWTEST
+				// Monster Iestyn (25/03/18): do not skip these lights if they fail overflow test, just clamp them instead so they behave.
+				overflow_test = (INT64)centeryfrac - (((INT64)leftheight*ds->scale1)>>FRACBITS);
+				if      (overflow_test > (INT64)CLAMPMAX) rlight->botheight = CLAMPMAX;
+				else if (overflow_test > (INT64)CLAMPMIN) rlight->botheight = (fixed_t)overflow_test;
+				else                                      rlight->botheight = CLAMPMIN;
 
-				rlight->botheight = (centeryfrac) - FixedMul(leftheight, ds->scale1);
-				rlight->botheightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2);
+				overflow_test = (INT64)centeryfrac - (((INT64)rightheight*ds->scale2)>>FRACBITS);
+				if      (overflow_test > (INT64)CLAMPMAX) rlight->botheightstep = CLAMPMAX;
+				else if (overflow_test > (INT64)CLAMPMIN) rlight->botheightstep = (fixed_t)overflow_test;
+				else                                      rlight->botheightstep = CLAMPMIN;
 				rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(range);
 #else
 				lheight = *light->caster->bottomheight;// > *pfloor->topheight ? *pfloor->topheight + FRACUNIT : *light->caster->bottomheight;
@@ -1071,9 +1077,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	}
 #endif
 
-#define CLAMPMAX INT32_MAX
-#define CLAMPMIN (-INT32_MAX) // This is not INT32_MIN on purpose! INT32_MIN makes the drawers freak out.
-
 	// draw the columns
 	for (dc_x = x1; dc_x <= x2; dc_x++)
 	{
@@ -3063,8 +3066,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 +3080,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/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index ec5d63ac79c7b1d302fa787f1e409c37caa7c18c..de2157055839476d8599db462d22e2d7cdeb1b20 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 30259d55efd623ca9087209df7ae03fbca10e5dd..1d0f9d314a98ff081671715292b5e4b26d2c54a9 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(//__<bbbb2////3[888hpp                              ",
+"                                 oj}^/_6bbbbgggggggb2///_bgbbbbb631kt                           ",
+"                                (80066bgeeegggggggb22262/bbggeggb66081                          ",
+"         p9^jj              pp8(_2bgggggeeeeeeeegb2~_bgb//6geegged5*'(hp                        ",
+"         ^2<3[7           j^/2bbggggeeeeeeeeeeggb2_({'4eb/2ggge5:!!!>-*{^kt                     ",
+"         &,5b60^         (02<beggggeeeeeeeeeegb62__7}~:5g/_bgd5!))))))=+;20k                    ",
+"         @#:egb3^     pp({4dgggeeeeeeeeeeeeegg6/__3im}+:e//bd:!)))))))))!#;87                   ",
+"        p'-!:dgb3]   7['4egeeeeeeeeeeeeeeeegg2/__[armc,-523<:!)))))))))))!>*{}                  ",
+"       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_</]mrrruvvvn{+))*@->>--###++++++###+;@{(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^&.';,*+=!><k                     ",
+"                               koooook                          hph[~@+>><k                     ",
+"                                ppppp                            tk7^3_,+<j                     ",
+"                                                                     o7^@3j                     ",
+"                                                                        9jj                     ",
+"                                                                         o                      ",
+"                                                                                                ",
+"                                                                                                ",
+"                                                                                                ",
+"                                                                                                ",
+"                                                                                                ",
+"                                                                                                ",
+"                                                                                                ",
+"                                                                                                ",
+"                                                                                                ",
+"                                                                                                "};
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index 04af6a8e1a2fb35b217495d2949959f110266c0d..e43772179562d95f87de7cf5d3b1734840288e4d 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -164,6 +164,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\am_map.h" />
+    <ClInclude Include="..\apng.h" />
     <ClInclude Include="..\blua\lapi.h" />
     <ClInclude Include="..\blua\lauxlib.h" />
     <ClInclude Include="..\blua\lcode.h" />
@@ -316,6 +317,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\am_map.c" />
+    <ClCompile Include="..\apng.c" />
     <ClCompile Include="..\blua\lapi.c" />
     <ClCompile Include="..\blua\lauxlib.c" />
     <ClCompile Include="..\blua\lbaselib.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index ac0b031779bbfe8cb5351cbec18a5d5465a01deb..d67ac63082800b9d77ca3985547859714c61942b 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -294,6 +294,9 @@
     <ClInclude Include="..\lua_script.h">
       <Filter>LUA</Filter>
     </ClInclude>
+    <ClInclude Include="..\apng.h">
+      <Filter>M_Misc</Filter>
+    </ClInclude>
     <ClInclude Include="..\md5.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
diff --git a/src/sdl/Srb2SDL-vc9.vcproj b/src/sdl/Srb2SDL-vc9.vcproj
index d2a268f8d44f501b141ffa4de48eea5fed1e5f32..3898aeba4efc53c9bd06fe38834d164ae31d64c1 100644
--- a/src/sdl/Srb2SDL-vc9.vcproj
+++ b/src/sdl/Srb2SDL-vc9.vcproj
@@ -2834,6 +2834,50 @@
 				RelativePath="..\m_argv.h"
 				>
 			</File>
+			<File
+				RelativePath="..\apng.c"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\apng.h"
+				>
+			</File>
 			<File
 				RelativePath="..\m_bbox.c"
 				>
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index 50c3018aa0603adba67d941deec8dcae38411a57..517c183ee144019fcb32384aef779c5f40cbf005 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -1402,7 +1402,13 @@ static int joy_open2(const char *fname)
 void I_InitJoystick(void)
 {
 	I_ShutdownJoystick();
-	SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
+
+	if (M_CheckParm("-noxinput"))
+		SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
+
+	if (M_CheckParm("-nohidapi"))
+		SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE);
+
 	if (!strcmp(cv_usejoystick.string, "0") || M_CheckParm("-nojoy"))
 		return;
 	if (joy_open(cv_usejoystick.string) != -1)
@@ -1418,7 +1424,13 @@ void I_InitJoystick(void)
 void I_InitJoystick2(void)
 {
 	I_ShutdownJoystick2();
-	SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
+
+	if (M_CheckParm("-noxinput"))
+		SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
+
+	if (M_CheckParm("-nohidapi"))
+		SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE);
+
 	if (!strcmp(cv_usejoystick2.string, "0") || M_CheckParm("-nojoy"))
 		return;
 	if (joy_open2(cv_usejoystick2.string) != -1)
@@ -2045,8 +2057,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/i_video.c b/src/sdl/i_video.c
index dbaa7037ae41f8e5f65af52a16b1cd1334c4ecdf..71d80605005782a7b0c1d8485bb2f3b8fb4caef4 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -580,8 +580,6 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
 			if (cv_usemouse.value) I_StartupMouse();
 		}
 		//else firsttimeonmouse = SDL_FALSE;
-
-		capslock = !!( SDL_GetModState() & KMOD_CAPS );// in case CL changes
 	}
 	else if (!mousefocus && !kbfocus)
 	{
@@ -939,6 +937,8 @@ void I_StartupMouse(void)
 //
 void I_OsPolling(void)
 {
+	SDL_Keymod mod;
+
 	if (consolevent)
 		I_GetConsoleEvents();
 	if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
@@ -951,6 +951,18 @@ void I_OsPolling(void)
 	I_GetMouseEvents();
 
 	I_GetEvent();
+
+	mod = SDL_GetModState();
+	/* Handle here so that our state is always synched with the system. */
+	shiftdown = ctrldown = altdown = 0;
+	capslock = false;
+	if (mod & KMOD_LSHIFT) shiftdown |= 1;
+	if (mod & KMOD_RSHIFT) shiftdown |= 2;
+	if (mod & KMOD_LCTRL)   ctrldown |= 1;
+	if (mod & KMOD_RCTRL)   ctrldown |= 2;
+	if (mod & KMOD_LALT)     altdown |= 1;+	if (mod & KMOD_RALT)     altdown |= 2;
+	if (mod & KMOD_CAPS) capslock = true;
 }
 
 //
diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
index 94a3fbb6307438301e8868127a45668c53af1112..a8ecbf7f85984eaeb63a1b3254f001da6c0d0f32 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/srb2icon.png b/src/sdl/srb2icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..cdee18a8412313410fb4f0f0a132b710c1670c54
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 958cd7d02877eac200c0baee40ec625a093f60a5..99916f58d405351a1cb15bb83063d623b6d67bf2 100644
--- a/src/sdl12/Srb2SDL-vc10.vcxproj
+++ b/src/sdl12/Srb2SDL-vc10.vcxproj
@@ -835,6 +835,16 @@
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="..\apng.c">
+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
     <ClCompile Include="..\m_misc.c">
       <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -1293,6 +1303,7 @@
     <ClInclude Include="filter\interp.h" />
     <ClInclude Include="filter\lq2x.h" />
     <ClInclude Include="..\p5prof.h" />
+    <ClInclude Include="..\apng.h" />
     <ClInclude Include="..\d_clisrv.h" />
     <ClInclude Include="..\d_event.h" />
     <ClInclude Include="..\d_main.h" />
diff --git a/src/sdl12/Srb2SDL-vc9.vcproj b/src/sdl12/Srb2SDL-vc9.vcproj
index d2a268f8d44f501b141ffa4de48eea5fed1e5f32..fa386e381b11ab04d98cfd05e7e747ac34767bc2 100644
--- a/src/sdl12/Srb2SDL-vc9.vcproj
+++ b/src/sdl12/Srb2SDL-vc9.vcproj
@@ -2790,6 +2790,50 @@
 		<Filter
 			Name="M_Misc"
 			>
+			<File
+				RelativePath="..\apng.c"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\apng.h"
+				>
+			</File>
 			<File
 				RelativePath="..\m_argv.c"
 				>
diff --git a/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj
index de12201f5dc080390a9accea387021637c75aee5..1f8e3276a01c5666c76da3a3f8b4a824b4476d60 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 0ab40c45e0bafdfe098f060ec7aa886740924668..69c544c56e0db6c8652e551b2b6a40dd62cdf8ce 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/v_video.c b/src/v_video.c
index cfe7d036032c773fef71a8ff75c1c5180dce5ae8..c3b29e15760e660e2eeceb44cda19f90cf28a9b5 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -81,6 +81,7 @@ consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE| CV_FLOAT, 0, NULL, 0
 static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NULL}};
 // console variables in development
 consvar_t cv_grmd2 = {"gr_md2", "Off", CV_SAVE, CV_MD2, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 #endif
 
 const UINT8 gammatable[5][256] =
diff --git a/src/w_wad.c b/src/w_wad.c
index 88e89974aab83c201d7f2b0fcdd88dca39481645..c4f9ceca8fbc4d2656aa818e5cc3b327c077709d 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;
 	}
@@ -1175,6 +1179,23 @@ void zerr(int ret)
 }
 #endif
 
+#define NO_PNG_LUMPS
+
+#ifdef NO_PNG_LUMPS
+static void ErrorIfPNG(UINT8 *d, size_t s, char *f, char *l)
+{
+    if (s < 67) // http://garethrees.org/2007/11/14/pngcrush/
+        return;
+    // Check for PNG file signature using memcmp
+    // As it may be faster on CPUs with slow unaligned memory access
+    // Ref: http://www.libpng.org/pub/png/spec/1.2/PNG-Rationale.html#R.PNG-file-signature
+    if (memcmp(&d[0], "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8) == 0)
+    {
+        I_Error("W_Wad: Lump \"%s\" in file \"%s\" is a .PNG - please convert to either Doom or Flat (raw) image format.", l, f);
+    }
+}
+#endif
+
 /** Reads bytes from the head of a lump.
   * Note: If the lump is compressed, the whole thing has to be read anyway.
   *
@@ -1214,7 +1235,15 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
 	switch(wadfiles[wad]->lumpinfo[lump].compression)
 	{
 	case CM_NOCOMPRESSION:		// If it's uncompressed, we directly write the data into our destination, and return the bytes read.
+#ifdef NO_PNG_LUMPS
+		{
+			size_t bytesread = fread(dest, 1, size, handle);
+			ErrorIfPNG(dest, bytesread, wadfiles[wad]->filename, l->name2);
+			return bytesread;
+		}
+#else
 		return fread(dest, 1, size, handle);
+#endif
 	case CM_LZF:		// Is it LZF compressed? Used by ZWADs.
 		{
 #ifdef ZWAD
@@ -1249,11 +1278,15 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
 			M_Memcpy(dest, decData + offset, size);
 			Z_Free(rawData);
 			Z_Free(decData);
+#ifdef NO_PNG_LUMPS
+			ErrorIfPNG(dest, size, wadfiles[wad]->filename, l->name2);
+#endif
 			return size;
 #else
 			//I_Error("ZWAD files not supported on this platform.");
 			return 0;
 #endif
+
 		}
 #ifdef HAVE_ZLIB
 	case CM_DEFLATE: // Is it compressed via DEFLATE? Very common in ZIPs/PK3s, also what most doom-related editors support.
@@ -1307,6 +1340,9 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
 			Z_Free(rawData);
 			Z_Free(decData);
 
+#ifdef NO_PNG_LUMPS
+			ErrorIfPNG(dest, size, wadfiles[wad]->filename, l->name2);
+#endif
 			return size;
 		}
 #endif
diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg
index def2fe682e4964a49bf6642c9108d36fdbd61d05..1880abf18bcdc5c686c32a2199aeaa08150eba07 100644
--- a/src/win32/Makefile.cfg
+++ b/src/win32/Makefile.cfg
@@ -24,8 +24,10 @@ ifndef NOASM
 	USEASM=1
 endif
 
+ifndef NONET
 ifndef MINGW64 #miniupnc is broken with MINGW64
 	HAVE_MINIUPNPC=1
+endif
 endif
 
 	OPTS=-DSTDC_HEADERS
diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj
index ca73b12938fde0d7ccef57042413c1308a747d38..774ce5cbe8c7560c592f2b6b97e3db7864221347 100644
--- a/src/win32/Srb2win-vc10.vcxproj
+++ b/src/win32/Srb2win-vc10.vcxproj
@@ -182,6 +182,7 @@
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="..\am_map.c" />
+    <ClCompile Include="..\apng.c" />
     <ClCompile Include="..\blua\lapi.c" />
     <ClCompile Include="..\blua\lauxlib.c" />
     <ClCompile Include="..\blua\lbaselib.c" />
@@ -330,6 +331,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\am_map.h" />
+    <ClInclude Include="..\apng.h" />
     <ClInclude Include="..\blua\lapi.h" />
     <ClInclude Include="..\blua\lauxlib.h" />
     <ClInclude Include="..\blua\lcode.h" />
diff --git a/src/win32/Srb2win-vc9.vcproj b/src/win32/Srb2win-vc9.vcproj
index 24235bc7b158cb8ec8d6dea0ecb38454c7dd2488..a64b8638cde6986a2377440a62bfe060293cb93f 100644
--- a/src/win32/Srb2win-vc9.vcproj
+++ b/src/win32/Srb2win-vc9.vcproj
@@ -2851,6 +2851,50 @@
 				RelativePath="..\m_misc.h"
 				>
 			</File>
+			<File
+				RelativePath="..\apng.c"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\apng.h"
+				>
+			</File>
 			<File
 				RelativePath="..\m_queue.c"
 				>