diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0cffa367ecdfe4ad8dd473a4a216e371bd231b89..30ef1338aca426b148d12b68006cb48895436f33 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,173 +1,43 @@
-#
-# Simple CMakeLists for Sonic Robo Blast 2
-#
-PROJECT(SRB2)
-
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
-
-#
-# Dependencies
-#
-FIND_PACKAGE(SDL)
-FIND_PACKAGE(SDL_mixer)
-FIND_PACKAGE(PNG)
-
-#
-# Common stuff
-#
-
-# not added defines:
-# -DHAVE_PNG - does not build (incorrect use of PNG_EXPORT etc.)
-ADD_DEFINITIONS(-DDIRECTFULLSCREEN -DSDL -DHAVE_MIXER -DNOHW -DHW3SOUND -DHAVE_BLUA -DNOASM)
-
-SET(SDL_DIR sdl) # may be set to SDL2 optionally
-
-SET(COMMON_SRCS
-	src/${SDL_DIR}/dosstr.c
-	src/${SDL_DIR}/endtxt.c
-	src/${SDL_DIR}/hwsym_sdl.c
-	src/${SDL_DIR}/i_cdmus.c
-	src/${SDL_DIR}/i_main.c
-	src/${SDL_DIR}/i_net.c
-	src/${SDL_DIR}/i_system.c
-	src/${SDL_DIR}/i_video.c
-	src/${SDL_DIR}/mixer_sound.c
-	src/am_map.c
-	src/b_bot.c
-	src/blua/lapi.c
-	src/blua/lauxlib.c
-	src/blua/lbaselib.c
-	src/blua/lcode.c
-	src/blua/ldebug.c
-	src/blua/ldo.c
-	src/blua/ldump.c
-	src/blua/lfunc.c
-	src/blua/lgc.c
-	src/blua/linit.c
-	src/blua/llex.c
-	src/blua/lmem.c
-	src/blua/lobject.c
-	src/blua/lopcodes.c
-	src/blua/lparser.c
-	src/blua/lstate.c
-	src/blua/lstring.c
-	src/blua/lstrlib.c
-	src/blua/ltable.c
-	src/blua/ltablib.c
-	src/blua/ltm.c
-	src/blua/lundump.c
-	src/blua/lvm.c
-	src/blua/lzio.c
-	src/command.c
-	src/comptime.c
-	src/console.c
-	src/d_clisrv.c
-	src/d_main.c
-	src/d_net.c
-	src/d_netcmd.c
-	src/d_netfil.c
-	src/dehacked.c
-	src/f_finale.c
-	src/f_wipe.c
-	src/filesrch.c
-	src/g_game.c
-	src/g_input.c
-	src/hardware/hw3sound.c
-	src/hu_stuff.c
-	src/i_tcp.c
-	src/info.c
-	src/lua_baselib.c
-	src/lua_consolelib.c
-	src/lua_hooklib.c
-	src/lua_hudlib.c
-	src/lua_infolib.c
-	src/lua_maplib.c
-	src/lua_mathlib.c
-	src/lua_mobjlib.c
-	src/lua_playerlib.c
-	src/lua_script.c
-	src/lua_skinlib.c
-	src/lua_thinkerlib.c
-	src/lzf.c
-	src/m_anigif.c
-	src/m_argv.c
-	src/m_bbox.c
-	src/m_cheat.c
-	src/m_cond.c
-	src/m_fixed.c
-	src/m_menu.c
-	src/m_misc.c
-	src/m_queue.c
-	src/m_random.c
-	src/md5.c
-	src/mserv.c
-	src/p_ceilng.c
-	src/p_enemy.c
-	src/p_fab.c
-	src/p_floor.c
-	src/p_inter.c
-	src/p_lights.c
-	src/p_map.c
-	src/p_maputl.c
-	src/p_mobj.c
-	src/p_polyobj.c
-	src/p_saveg.c
-	src/p_setup.c
-	src/p_sight.c
-	src/p_spec.c
-	src/p_telept.c
-	src/p_tick.c
-	src/p_user.c
-	src/r_bsp.c
-	src/r_data.c
-	src/r_draw.c
-	src/r_main.c
-	src/r_plane.c
-	src/r_segs.c
-	src/r_sky.c
-	src/r_splats.c
-	src/r_things.c
-	src/s_sound.c
-	src/screen.c
-	src/sounds.c
-	src/st_stuff.c
-	src/string.c
-	src/tables.c
-	src/v_video.c
-	src/w_wad.c
-	src/y_inter.c
-	src/z_zone.c
-)
-
-#
-# Platform-specific stuff
-#
-
-MACRO(EXTRALIB NAME)
-	FIND_LIBRARY(${NAME}_LIBRARY NAMES ${NAME})
-	IF(${NAME}_LIBRARY)
-		MESSAGE(STATUS "Found lib${NAME}: ${${NAME}_LIBRARY}")
-		SET(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} ${${NAME}_LIBRARY})
-	ELSE(${NAME}_LIBRARY)
-		MESSAGE(FATAL_ERROR "Could not find lib${NAME}!")
-	ENDIF(${NAME}_LIBRARY)
-ENDMACRO(EXTRALIB)
-
-IF(${CMAKE_SYSTEM} MATCHES "FreeBSD")
-	ADD_DEFINITIONS(-DUNIXCOMMON -DLINUX -DFREEBSD)
-	EXTRALIB(kvm)
-ELSEIF(${CMAKE_SYSTEM} MATCHES "Linux")
-	ADD_DEFINITIONS(-DUNIXCOMMON -DLINUX)
-	EXTRALIB(m)
-	EXTRALIB(rt)
-ELSE(${CMAKE_SYSTEM} MATCHES "FreeBSD")
-	ADD_DEFINITIONS(-DUNIXCOMMON -DLINUX)
-	MESSAGE(WARNING "No specific settings for you system, it may be not supported!")
-ENDIF(${CMAKE_SYSTEM} MATCHES "FreeBSD")
-
-#
-# Targets
-#
-INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIRS} ${SDL_INCLUDE_DIR} ${SDL_MIXER_INCLUDE_DIRS})
-ADD_EXECUTABLE(SRB2 ${COMMON_SRCS})
-TARGET_LINK_LIBRARIES(SRB2 ${SDL_LIBRARY} ${SDL_MIXER_LIBRARIES} ${EXTRA_LIBRARIES})
+cmake_minimum_required(VERSION 3.0)
+project(SRB2
+	VERSION 2.1.14)
+
+# Set up CMAKE path
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+
+### Useful functions
+
+# Prepend sources with current source directory
+function(prepend_sources SOURCE_FILES)
+	foreach(SOURCE_FILE ${${SOURCE_FILES}})
+		set(MODIFIED ${MODIFIED} ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE})
+	endforeach()
+	set(${SOURCE_FILES} ${MODIFIED} PARENT_SCOPE)
+endfunction()
+
+# 64-bit check
+if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+	message(STATUS "Target is 64-bit")
+	set(SRB2_SYSTEM_BITS 64)
+else()
+	set(SRB2_SYSTEM_BITS 32)
+endif()
+
+# DO NOT ALLOW MSVC!
+if(MSVC)
+	message(FATAL_ERROR "MSVC is not supported!")
+endif()
+
+# OS macros
+if (UNIX)
+	add_definitions(-DUNIXCOMMON)
+endif()
+if(${CMAKE_SYSTEM} MATCHES "Linux")
+	add_definitions(-DLINUX)
+	if(${SRB2_SYSTEM_BITS} EQUAL 64)
+		add_definitions(-DLINUX64)
+	endif()
+endif()
+# TODO support MacOSX builds
+
+add_subdirectory(src/)
diff --git a/cmake/Modules/FindSDL2.cmake b/cmake/Modules/FindSDL2.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..faa556a883aae61ac482c304f32200a996b982de
--- /dev/null
+++ b/cmake/Modules/FindSDL2.cmake
@@ -0,0 +1,34 @@
+# Find SDL2
+# Once done, this will define
+# 
+#  SDL2_FOUND - system has SDL2
+#  SDL2_INCLUDE_DIRS - SDL2 include directories
+#  SDL2_LIBRARIES - link libraries
+
+include(LibFindMacros)
+
+libfind_pkg_check_modules(SDL2_PKGCONF SDL2)
+
+# includes
+find_path(SDL2_INCLUDE_DIR
+	NAMES SDL.h
+	PATHS
+		${SDL2_PKGCONF_INCLUDE_DIRS}
+		"/usr/include/SDL2"
+		"/usr/local/include/SDL2"
+)
+
+# library
+find_library(SDL2_LIBRARY
+	NAMES SDL2
+	PATHS
+		${SDL2_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+
+# set include dir variables
+set(SDL2_PROCESS_INCLUDES SDL2_INCLUDE_DIR)
+set(SDL2_PROCESS_LIBS SDL2_LIBRARY)
+libfind_process(SDL2)
diff --git a/cmake/Modules/LibFindMacros.cmake b/cmake/Modules/LibFindMacros.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..f6800aa7bd277e85ffa4297d27fbc980f0fda281
--- /dev/null
+++ b/cmake/Modules/LibFindMacros.cmake
@@ -0,0 +1,265 @@
+# Version 2.2
+# Public Domain, originally written by Lasse Kärkkäinen <tronic>
+# Maintained at https://github.com/Tronic/cmake-modules
+# Please send your improvements as pull requests on Github.
+
+# Find another package and make it a dependency of the current package.
+# This also automatically forwards the "REQUIRED" argument.
+# Usage: libfind_package(<prefix> <another package> [extra args to find_package])
+macro (libfind_package PREFIX PKG)
+  set(${PREFIX}_args ${PKG} ${ARGN})
+  if (${PREFIX}_FIND_REQUIRED)
+    set(${PREFIX}_args ${${PREFIX}_args} REQUIRED)
+  endif()
+  find_package(${${PREFIX}_args})
+  set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG})
+  unset(${PREFIX}_args)
+endmacro()
+
+# A simple wrapper to make pkg-config searches a bit easier.
+# Works the same as CMake's internal pkg_check_modules but is always quiet.
+macro (libfind_pkg_check_modules)
+  find_package(PkgConfig QUIET)
+  if (PKG_CONFIG_FOUND)
+    pkg_check_modules(${ARGN} QUIET)
+  endif()
+endmacro()
+
+# Avoid useless copy&pasta by doing what most simple libraries do anyway:
+# pkg-config, find headers, find library.
+# Usage: libfind_pkg_detect(<prefix> <pkg-config args> FIND_PATH <name> [other args] FIND_LIBRARY <name> [other args])
+# E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2)
+function (libfind_pkg_detect PREFIX)
+  # Parse arguments
+  set(argname pkgargs)
+  foreach (i ${ARGN})
+    if ("${i}" STREQUAL "FIND_PATH")
+      set(argname pathargs)
+    elseif ("${i}" STREQUAL "FIND_LIBRARY")
+      set(argname libraryargs)
+    else()
+      set(${argname} ${${argname}} ${i})
+    endif()
+  endforeach()
+  if (NOT pkgargs)
+    message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.")
+  endif()
+  # Find library
+  libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs})
+  if (pathargs)
+    find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS})
+  endif()
+  if (libraryargs)
+    find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS})
+  endif()
+endfunction()
+
+# Extracts a version #define from a version.h file, output stored to <PREFIX>_VERSION.
+# Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR)
+# Fourth argument "QUIET" may be used for silently testing different define names.
+# This function does nothing if the version variable is already defined.
+function (libfind_version_header PREFIX VERSION_H DEFINE_NAME)
+  # Skip processing if we already have a version or if the include dir was not found
+  if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR)
+    return()
+  endif()
+  set(quiet ${${PREFIX}_FIND_QUIETLY})
+  # Process optional arguments
+  foreach(arg ${ARGN})
+    if (arg STREQUAL "QUIET")
+      set(quiet TRUE)
+    else()
+      message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.")
+    endif()
+  endforeach()
+  # Read the header and parse for version number
+  set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+  if (NOT EXISTS ${filename})
+    if (NOT quiet)
+      message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+    endif()
+    return()
+  endif()
+  file(READ "${filename}" header)
+  string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}")
+  # No regex match?
+  if (match STREQUAL header)
+    if (NOT quiet)
+      message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"<version>\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+    endif()
+    return()
+  endif()
+  # Export the version string
+  set(${PREFIX}_VERSION "${match}" PARENT_SCOPE)
+endfunction()
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+function (libfind_process PREFIX)
+  # Skip processing if already processed during this configuration run
+  if (${PREFIX}_FOUND)
+    return()
+  endif()
+
+  set(found TRUE)  # Start with the assumption that the package was found
+
+  # Did we find any files? Did we miss includes? These are for formatting better error messages.
+  set(some_files FALSE)
+  set(missing_headers FALSE)
+
+  # Shorthands for some variables that we need often
+  set(quiet ${${PREFIX}_FIND_QUIETLY})
+  set(required ${${PREFIX}_FIND_REQUIRED})
+  set(exactver ${${PREFIX}_FIND_VERSION_EXACT})
+  set(findver "${${PREFIX}_FIND_VERSION}")
+  set(version "${${PREFIX}_VERSION}")
+
+  # Lists of config option names (all, includes, libs)
+  unset(configopts)
+  set(includeopts ${${PREFIX}_PROCESS_INCLUDES})
+  set(libraryopts ${${PREFIX}_PROCESS_LIBS})
+
+  # Process deps to add to 
+  foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES})
+    if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS)
+      # The package seems to export option lists that we can use, woohoo!
+      list(APPEND includeopts ${${i}_INCLUDE_OPTS})
+      list(APPEND libraryopts ${${i}_LIBRARY_OPTS})
+    else()
+      # If plural forms don't exist or they equal singular forms
+      if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR
+          ({i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES))
+        # Singular forms can be used
+        if (DEFINED ${i}_INCLUDE_DIR)
+          list(APPEND includeopts ${i}_INCLUDE_DIR)
+        endif()
+        if (DEFINED ${i}_LIBRARY)
+          list(APPEND libraryopts ${i}_LIBRARY)
+        endif()
+      else()
+        # Oh no, we don't know the option names
+        message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!")
+      endif()
+    endif()
+  endforeach()
+  
+  if (includeopts)
+    list(REMOVE_DUPLICATES includeopts)
+  endif()
+  
+  if (libraryopts)
+    list(REMOVE_DUPLICATES libraryopts)
+  endif()
+
+  string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}")
+  if (NOT tmp STREQUAL "${includeopts} ${libraryopts}")
+    message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).")
+  endif()
+
+  # Include/library names separated by spaces (notice: not CMake lists)
+  unset(includes)
+  unset(libs)
+
+  # Process all includes and set found false if any are missing
+  foreach (i ${includeopts})
+    list(APPEND configopts ${i})
+    if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+      list(APPEND includes "${${i}}")
+    else()
+      set(found FALSE)
+      set(missing_headers TRUE)
+    endif()
+  endforeach()
+
+  # Process all libraries and set found false if any are missing
+  foreach (i ${libraryopts})
+    list(APPEND configopts ${i})
+    if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+      list(APPEND libs "${${i}}")
+    else()
+      set (found FALSE)
+    endif()
+  endforeach()
+
+  # Version checks
+  if (found AND findver)
+    if (NOT version)
+      message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.")
+    elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver))
+      set(found FALSE)
+      set(version_unsuitable TRUE)
+    endif()
+  endif()
+
+  # If all-OK, hide all config options, export variables, print status and exit
+  if (found)
+    foreach (i ${configopts})
+      mark_as_advanced(${i})
+    endforeach()
+    if (NOT quiet)
+      message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+      if (LIBFIND_DEBUG)
+        message(STATUS "  ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}")
+        message(STATUS "  ${PREFIX}_INCLUDE_OPTS=${includeopts}")
+        message(STATUS "  ${PREFIX}_INCLUDE_DIRS=${includes}")
+        message(STATUS "  ${PREFIX}_LIBRARY_OPTS=${libraryopts}")
+        message(STATUS "  ${PREFIX}_LIBRARIES=${libs}")
+      endif()
+      set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE)
+      set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE)
+      set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE)
+      set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE)
+      set (${PREFIX}_FOUND TRUE PARENT_SCOPE)
+    endif()
+    return()    
+  endif()
+
+  # Format messages for debug info and the type of error
+  set(vars "Relevant CMake configuration variables:\n")
+  foreach (i ${configopts})
+    mark_as_advanced(CLEAR ${i})
+    set(val ${${i}})
+    if ("${val}" STREQUAL "${i}-NOTFOUND")
+      set (val "<not found>")
+    elseif (val AND NOT EXISTS ${val})
+      set (val "${val}  (does not exist)")
+    else()
+      set(some_files TRUE)
+    endif()
+    set(vars "${vars}  ${i}=${val}\n")
+  endforeach()
+  set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n")
+  if (version_unsuitable)
+    set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but")
+    if (exactver)
+      set(msg "${msg} only version ${findver} is acceptable.")
+    else()
+      set(msg "${msg} version ${findver} is the minimum requirement.")
+    endif()
+  else()
+    if (missing_headers)
+      set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?")
+    elseif (some_files)
+      set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?")
+      if(findver)
+        set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).")
+      endif()
+    else()
+      set(msg "We were unable to find package ${PREFIX}.")
+    endif()
+  endif()
+
+  # Fatal error out if REQUIRED
+  if (required)
+    set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.")
+    message(FATAL_ERROR "${msg}\n${vars}")
+  endif()
+  # Otherwise just print a nasty warning
+  if (NOT quiet)
+    message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}")
+  endif()
+endfunction()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e9f52321a8655e6847bc2bc1d7ff425f6dfd5b63
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,347 @@
+# SRB2 Core
+
+# Core sources
+set(SRB2_CORE_SOURCES
+	am_map.c
+	b_bot.c
+	command.c
+	comptime.c
+	console.c
+	d_clisrv.c
+	d_main.c
+	d_net.c
+	d_netcmd.c
+	d_netfil.c
+	dehacked.c
+	f_finale.c
+	f_wipe.c
+	filesrch.c
+	g_game.c
+	g_input.c
+	hu_stuff.c
+	i_tcp.c
+	info.c
+	lzf.c
+	m_anigif.c
+	m_argv.c
+	m_bbox.c
+	m_cheat.c
+	m_cond.c
+	m_fixed.c
+	m_menu.c
+	m_misc.c
+	m_queue.c
+	m_random.c
+	md5.c
+	mserv.c
+	p_ceilng.c
+	p_enemy.c
+	p_fab.c
+	p_floor.c
+	p_inter.c
+	p_lights.c
+	p_map.c
+	p_maputl.c
+	p_mobj.c
+	p_polyobj.c
+	p_saveg.c
+	p_setup.c
+	p_sight.c
+	p_spec.c
+	p_telept.c
+	p_tick.c
+	p_user.c
+	r_bsp.c
+	r_data.c
+	r_draw.c
+	r_main.c
+	r_plane.c
+	r_segs.c
+	r_sky.c
+	r_splats.c
+	r_things.c
+	s_sound.c
+	screen.c
+	sounds.c
+	st_stuff.c
+	string.c
+	tables.c
+	v_video.c
+	w_wad.c
+	y_inter.c
+	z_zone.c
+)
+
+set(SRB2_CORE_HEADERS
+	am_map.h
+	b_bot.h
+	byteptr.h
+	command.h
+	comptime.h
+	console.h
+	d_clisrv.h
+	d_event.h
+	d_main.h
+	d_net.h
+	d_netcmd.h
+	d_netfil.h
+	d_player.h
+	d_think.h
+	d_ticcmd.h
+	dehacked.h
+	doomdata.h
+	doomdef.h
+	doomstat.h
+	doomtype.h
+	endian.h
+	f_finale.h
+	fastcmp.h
+	filesrch.h
+	g_game.h
+	g_input.h
+	g_state.h
+	hu_stuff.h
+	i_joy.h
+	i_net.h
+	i_sound.h
+	i_system.h
+	i_tcp.h
+	i_video.h
+	info.h
+	keys.h
+	lzf.h
+	m_anigif.h
+	m_argv.h
+	m_bbox.h
+	m_cheat.h
+	m_cond.h
+	m_dllist.h
+	m_fixed.h
+	m_menu.h
+	m_misc.h
+	m_queue.h
+	m_random.h
+	m_swap.h
+	md5.h
+	mserv.h
+	p5prof.h
+	p_local.h
+	p_maputl.h
+	p_mobj.h
+	p_polyobj.h
+	p_pspr.h
+	p_saveg.h
+	p_setup.h
+	p_spec.h
+	p_tick.h
+	r_bsp.h
+	r_data.h
+	r_defs.h
+	r_draw.h
+	r_local.h
+	r_main.h
+	r_plane.h
+	r_segs.h
+	r_sky.h
+	r_splats.h
+	r_state.h
+	r_things.h
+	s_sound.h
+	screen.h
+	sounds.h
+	st_stuff.h
+	tables.h
+	v_video.h
+	w_wad.h
+	y_inter.h
+	z_zone.h
+)
+
+prepend_sources(SRB2_CORE_SOURCES)
+prepend_sources(SRB2_CORE_HEADERS)
+
+set(SRB2_HWRENDER_SOURCES
+	hardware/hw_bsp.c
+	hardware/hw_cache.c
+	hardware/hw_draw.c
+	hardware/hw_light.c
+	hardware/hw_main.c
+	hardware/hw_md2.c
+	hardware/hw_trick.c
+)
+
+set (SRB2_HWRENDER_HEADERS
+	hardware/hw_data.h
+	hardware/hw_defs.h
+	hardware/hw_dll.h
+	hardware/hw_drv.h
+	hardware/hw_glide.h
+	hardware/hw_glob.h
+	hardware/hw_light.h
+	hardware/hw_main.h
+	hardware/hw_md2.h
+)
+
+prepend_sources(SRB2_HWRENDER_SOURCES)
+prepend_sources(SRB2_HWRENDER_HEADERS)
+
+set(SRB2_R_OPENGL_SOURCES
+	hardware/r_opengl/r_opengl.c
+)
+
+set(SRB2_R_OPENGL_HEADERS
+	hardware/r_opengl/r_opengl.h
+)
+
+prepend_sources(SRB2_R_OPENGL_SOURCES)
+prepend_sources(SRB2_R_OPENGL_HEADERS)
+
+### Configuration
+set(SRB2_CONFIG_HAVE_BLUA ON CACHE BOOL
+	"Enable Lua interpreter support")
+set(SRB2_CONFIG_HAVE_PNG ON CACHE BOOL
+	"Enable PNG support. Depends on zlib, so will be disabled if you don't enable that too.")
+set(SRB2_CONFIG_HAVE_ZLIB ON CACHE BOOL
+	"Enable zlib support")
+set(SRB2_CONFIG_HAVE_LIBGME ON CACHE BOOL
+	"Enable GME support")
+set(SRB2_CONFIG_HWRENDER ON CACHE BOOL
+	"Enable hardware rendering through OpenGL")
+set(SRB2_CONFIG_USEASM OFF CACHE BOOL
+	"Enable nasm-implemented blit functions for moderate speedup")
+
+if(${SRB2_CONFIG_HAVE_BLUA})
+	add_definitions(-DHAVE_BLUA)
+	set(SRB2_LUA_SOURCES
+		lua_baselib.c
+		lua_consolelib.c
+		lua_hooklib.c
+		lua_hudlib.c
+		lua_infolib.c
+		lua_maplib.c
+		lua_mathlib.c
+		lua_mobjlib.c
+		lua_playerlib.c
+		lua_script.c
+		lua_skinlib.c
+		lua_thinkerlib.c
+	)
+	set(SRB2_LUA_HEADERS
+		lua_hook.h
+		lua_hud.h
+		lua_libs.h
+		lua_script.h
+	)
+
+	prepend_sources(SRB2_LUA_SOURCES)
+	prepend_sources(SRB2_LUA_HEADERS)
+
+	set(SRB2_BLUA_SOURCES
+		blua/lapi.c
+		blua/lauxlib.c
+		blua/lbaselib.c
+		blua/lcode.c
+		blua/ldebug.c
+		blua/ldo.c
+		blua/ldump.c
+		blua/lfunc.c
+		blua/lgc.c
+		blua/linit.c
+		blua/llex.c
+		blua/lmem.c
+		blua/lobject.c
+		blua/lopcodes.c
+		blua/lparser.c
+		blua/lstate.c
+		blua/lstring.c
+		blua/lstrlib.c
+		blua/ltable.c
+		blua/ltablib.c
+		blua/ltm.c
+		blua/lundump.c
+		blua/lvm.c
+		blua/lzio.c
+	)
+	set(SRB2_BLUA_HEADERS
+		blua/lapi.h
+		blua/lauxlib.h
+		blua/lcode.h
+		blua/ldebug.h
+		blua/ldo.h
+		blua/lfunc.h
+		blua/lgc.h
+		blua/llex.h
+		blua/llimits.h
+		blua/lmem.h
+		blua/lobject.h
+		blua/lopcodes.h
+		blua/lparser.h
+		blua/lstate.h
+		blua/lstring.h
+		blua/ltable.h
+		blua/ltm.h
+		blua/lua.h
+		blua/luaconf.h
+		blua/lualib.h
+		blua/lundump.h
+		blua/lvm.h
+		blua/lzio.h
+	)
+	prepend_sources(SRB2_BLUA_SOURCES)
+	prepend_sources(SRB2_BLUA_HEADERS)
+endif()
+
+if(${SRB2_CONFIG_HAVE_LIBGME})
+	# ???
+endif()
+
+if(${SRB2_CONFIG_HAVE_ZLIB})
+	find_package(ZLIB)
+	if(${ZLIB_FOUND})
+		set(SRB2_HAVE_ZLIB ON)
+	else()
+		message(WARNING "You have specified that ZLIB is available but it was not found. SRB2 may not compile correctly.")
+	endif()
+endif()
+
+if(${SRB2_CONFIG_HAVE_PNG} AND ${SRB2_CONFIG_HAVE_ZLIB})
+	if (${ZLIB_FOUND})
+		find_package(PNG)
+		if(${PNG_FOUND})
+			set(SRB2_HAVE_PNG ON)
+			add_definitions(-DHAVE_PNG)
+			add_definitions(-D_LARGEFILE64_SOURCE)
+		else()
+			message(WARNING "You have specified that PNG is available but it was not found. SRB2 may not compile correctly.")
+		endif()
+	endif()
+endif()
+
+if(${SRB2_CONFIG_HWRENDER})
+	find_package(OpenGL)
+	if(${OPENGL_FOUND})
+		add_definitions(-DHWRENDER)
+	else()
+		message(WARNING "You have specified HWRENDER but opengl was not found. Not setting HWRENDER.")
+	endif()
+endif()
+
+if(${SRB2_CONFIG_USEASM})
+	set(SRB2_USEASM ON)
+	add_definitions(-DUSEASM)
+else()
+	set(SRB2_USEASM OFF)
+	add_definitions(-DNOASM -DNONX86)
+endif()
+
+# Targets
+
+if(${CMAKE_SYSTEM} MATCHES Windows)
+	add_subdirectory(win32)
+endif()
+
+# Compatibility flag with later versions of GCC
+# We should really fix our code to not need this
+add_compile_options(-mno-ms-bitfields)
+
+add_subdirectory(sdl)
diff --git a/src/Makefile b/src/Makefile
index d4cc64a4b6ff79da6672ee10df9ef30f574aca40..a1a8804e708b5ff1fa82918c23fea23895a126f2 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -585,6 +585,8 @@ $(BIN)/$(EXENAME): $(POS) $(OBJS)
 	-$(MKDIR) $(BIN)
 	@echo Linking $(EXENAME)...
 	$(LD) $(LDFLAGS) $(OBJS) -o $(BIN)/$(EXENAME) $(LIBS)
+	@echo $(LD) $(LDFLAGS) $(OBJS) -o $(BIN)/$(EXENAME) $(LIBS)
+	@echo $(CFLAGS)
 ifndef VALGRIND
 ifndef NOOBJDUMP
 	@echo Dumping debugging info
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..66dfeb998912fc3a62eb3dc87cf820a2e5b2bb78
--- /dev/null
+++ b/src/sdl/CMakeLists.txt
@@ -0,0 +1,111 @@
+# Declare SDL2 interface sources
+
+set(SRB2_CONFIG_SDL2_USEMIXER ON CACHE BOOL "Use SDL2_mixer or regular sdl sound")
+
+if(${SRB2_CONFIG_SDL2_USEMIXER})
+	set(SRB2_SDL2_SOUNDIMPL mixer_sound.c)
+else()
+	set(SRB2_SDL2_SOUNDIMPL sdl_sound.c)
+endif()
+
+set(SRB2_SDL2_SOURCES
+	dosstr.c
+	endtxt.c
+	hwsym_sdl.c
+	i_cdmus.c
+	i_main.c
+	i_net.c
+	i_system.c
+	i_ttf.c
+	i_video.c
+	#IMG_xpm.c
+	ogl_sdl.c
+
+	${SRB2_SDL2_SOUNDIMPL}
+)
+
+set(SRB2_SDL2_HEADERS
+	endtxt.h
+	hwsym_sdl.h
+	i_ttf.h
+	ogl_sdl.h
+	sdlmain.h
+)
+
+prepend_sources(SRB2_SDL2_SOURCES)
+prepend_sources(SRB2_SDL2_HEADERS)
+
+# Binary name
+set(SRB2_SDL2_EXE_NAME srb2sdl2)
+if(${CMAKE_SYSTEM} MATCHES "Windows")
+	set(SRB2_SDL2_EXE_NAME srb2win)
+endif()
+
+# Dependency
+find_package(SDL2)
+
+if(${SDL2_FOUND})
+	set(SRB2_SDL2_TOTAL_SOURCES
+		${SRB2_CORE_SOURCES}
+		${SRB2_CORE_HEADERS}
+		${SRB2_SDL2_SOURCES}
+		${SRB2_SDL2_HEADERS}
+	)
+
+	if(${SRB2_CONFIG_HWRENDER} AND ${OPENGL_FOUND})
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+			${SRB2_HWRENDER_SOURCES}
+			${SRB2_HWRENDER_HEADERS}
+			${SRB2_R_OPENGL_SOURCES}
+			${SRB2_R_OPENGL_HEADERS}
+		)
+	endif()
+
+	if(${SRB2_CONFIG_HAVE_BLUA})
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+			${SRB2_LUA_SOURCES}
+			${SRB2_LUA_HEADERS}
+			${SRB2_BLUA_SOURCES}
+			${SRB2_BLUA_HEADERS}
+		)
+	endif()
+
+	if(${CMAKE_SYSTEM} MATCHES Windows)
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+			${CMAKE_SOURCE_DIR}/src/win32/win_dbg.c
+		)
+	endif()
+
+	add_executable(${SRB2_SDL2_EXE_NAME} WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
+
+	target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+		${SDL2_LIBRARIES}
+		${PNG_LIBRARIES}
+		${ZLIB_LIBRARIES}
+		${OPENGL_LIBRARIES}
+	)
+
+	if(${CMAKE_SYSTEM} MATCHES Windows)
+		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+			ws2_32
+		)
+		target_compile_options(${SRB2_SDL2_EXE_NAME} PRIVATE
+			-U_WINDOWS
+		)
+	endif()
+
+	target_include_directories(${SRB2_SDL2_EXE_NAME} PRIVATE
+		${SDL2_INCLUDE_DIRS}
+		${SDL2_MAIN_INCLUDE_DIRS}
+		${PNG_INCLUDE_DIRS}
+		${ZLIB_INCLUDE_DIRS}
+		${OPENGL_INCLUDE_DIRS}
+	)
+
+	target_compile_definitions(${SRB2_SDL2_EXE_NAME} PRIVATE
+		-DHAVE_SDL
+		-DNDEBUG
+	)
+else()
+	message(WARNING "SDL2 wasn't found, so ${SRB2_SDL2_EXE_NAME} won't be available")
+endif()
diff --git a/src/win32/CMakeLists.txt b/src/win32/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4800852c908140a107cfbfc5f0dafd47ff730c83
--- /dev/null
+++ b/src/win32/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(SRB2_WIN_EXE_NAME srb2dd)
+
+add_executable(${SRB2_WIN_EXE_NAME} EXCLUDE_FROM_ALL
+	${SRB2_CORE_SOURCES}
+	${SRB2_CORE_HEADERS}
+	${SRB2_LUA_SOURCES}
+	${SRB2_LUA_HEADERS}
+	${SRB2_BLUA_SOURCES}
+	${SRB2_BLUA_HEADERS})
+
+target_compile_definitions(${SRB2_WIN_EXE_NAME} PRIVATE
+	-D_WINDOWS
+)
\ No newline at end of file