diff --git a/CMakeLists.txt b/CMakeLists.txt
index b8abe511d42f3bbbf01fd80f525f0978cbb573ca..e23d891cb1948d35458dba2e3e4c57eb0e38edd0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,6 +3,10 @@ project(SRB2
 	VERSION 2.1.14
 	LANGUAGES C)
 
+if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
+	message(FATAL_ERROR "In-source builds will bring you a world of pain. Please make a separate directory to invoke CMake from.")
+endif()
+
 # Set up CMAKE path
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
 
@@ -58,10 +62,6 @@ else()
 	set(SRB2_SYSTEM_BITS 32)
 endif()
 
-if(MSVC)
-	message(WARNING "!! MSVC BUILDS OF SRB2 CANNOT PLAY MULTIPLAYER !! You're more than welcome to try and fix this!")
-endif()
-
 # OS macros
 if (UNIX)
 	add_definitions(-DUNIXCOMMON)
@@ -85,6 +85,9 @@ if(${CMAKE_SYSTEM} MATCHES "Darwin")
 	endif()
 endif()
 
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+
 # Set EXE names so the assets CMakeLists can refer to its target
 set(SRB2_SDL2_EXE_NAME srb2)
 set(SRB2_WIN_EXE_NAME srb2dd)
@@ -98,7 +101,9 @@ add_subdirectory(assets)
 ## config.h generation
 set(GIT_EXECUTABLE "git" CACHE FILEPATH "Path to git binary")
 include(GitUtilities)
-git_describe(SRB2_COMP_REVISION "${CMAKE_CURRENT_SOURCE_DIR}")
+git_describe(SRB2_GIT_DESCRIBE "${CMAKE_SOURCE_DIR}")
+git_current_branch(SRB2_GIT_BRANCH "${CMAKE_SOURCE_DIR}")
+set(SRB2_COMP_REVISION "${SRB2_GIT_DESCRIBE}-<${SRB2_GIT_BRANCH}>")
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/config.h)
 
 ##### PACKAGE CONFIGURATION #####
diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt
index 3ce133c6a67fde3d3ea55170bc7b8b24938fa8a6..292e184c72d20a3d2e2b5295de8dc818d6826a58 100644
--- a/assets/CMakeLists.txt
+++ b/assets/CMakeLists.txt
@@ -26,7 +26,7 @@ endforeach()
 # Installation
 
 if(CLANG)
-	get_target_property(outname ${SRB2_SDL2_EXE_NAME} OUTPUT_NAME)
+	get_target_property(outname SRB2SDL2 OUTPUT_NAME)
 	install(FILES ${SRB2_ASSET_ALL}
 		DESTINATION "${outname}.app/Contents/Resources"
 	)
diff --git a/cmake/Modules/GitUtilities.cmake b/cmake/Modules/GitUtilities.cmake
index de4015b0d1e45be3afd1c858c373db4b3d36277c..683cf9b6b505e788bd3139bf0513b433a3190a2e 100644
--- a/cmake/Modules/GitUtilities.cmake
+++ b/cmake/Modules/GitUtilities.cmake
@@ -14,9 +14,18 @@ function(git_describe variable path)
 		ERROR_QUIET
 		OUTPUT_STRIP_TRAILING_WHITESPACE
 	)
-	#if(NOT result EQUAL 0)
-	#	set(${variable} "GITERROR-${result}-NOTFOUND" CACHE STRING "revision" FORCE)
-	#endif()
 
 	set(${variable} "${output}" PARENT_SCOPE)
 endfunction()
+
+function(git_current_branch variable path)
+	execute_process(COMMAND ${GIT_EXECUTABLE} "symbolic-ref" "--short" "HEAD"
+		WORKING_DIRECTORY "${path}"
+		RESULT_VARIABLE result
+		OUTPUT_VARIABLE output
+		ERROR_QUIET
+		OUTPUT_STRIP_TRAILING_WHITESPACE
+	)
+
+	set(${variable} "${output}" PARENT_SCOPE)
+endfunction()
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 74f97048b3f5332070a14b05cf6f167f79267797..9b5089e3a44853ba4c46d44d4ac797575cba38e7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -34,32 +34,6 @@ set(SRB2_CORE_SOURCES
 	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
@@ -124,27 +98,6 @@ set(SRB2_CORE_HEADERS
 	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
@@ -154,73 +107,97 @@ set(SRB2_CORE_HEADERS
 	w_wad.h
 	y_inter.h
 	z_zone.h
-)
-
-prepend_sources(SRB2_CORE_SOURCES)
-prepend_sources(SRB2_CORE_HEADERS)
 
-set(SRB2_CORE_HEADERS ${SRB2_CORE_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/config.h)
-
-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
+	config.h.in
+	${CMAKE_CURRENT_BINARY_DIR}/config.h
 )
 
-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
+set(SRB2_CORE_RENDER_SOURCES
+	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
+
+	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
 )
 
-prepend_sources(SRB2_HWRENDER_SOURCES)
-prepend_sources(SRB2_HWRENDER_HEADERS)
+set(SRB2_CORE_GAME_SOURCES
+	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
 
-set(SRB2_R_OPENGL_SOURCES
-	hardware/r_opengl/r_opengl.c
+	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
 )
 
-set(SRB2_R_OPENGL_HEADERS
-	hardware/r_opengl/r_opengl.h
-)
+if(NOT CLANG)
+	set(SRB2_CORE_SOURCES ${SRB2_CORE_SOURCES} string.c)
+endif()
 
-prepend_sources(SRB2_R_OPENGL_SOURCES)
-prepend_sources(SRB2_R_OPENGL_HEADERS)
+source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS})
+source_group("Renderer" FILES ${SRB2_CORE_RENDER_SOURCES})
+source_group("Game" FILES ${SRB2_CORE_GAME_SOURCES})
 
 set(SRB2_ASM_SOURCES
-	vid_copy.s
+	${CMAKE_CURRENT_SOURCE_DIR}/vid_copy.s
 )
 
 set(SRB2_NASM_SOURCES
-	tmap_mmx.nas
-	tmap.nas
+	${CMAKE_CURRENT_SOURCE_DIR}/tmap_mmx.nas
+	${CMAKE_CURRENT_SOURCE_DIR}/tmap.nas
 )
 
 if(MSVC)
-	list(APPEND SRB2_NASM_SOURCES tmap_vc.nas)
+	list(APPEND SRB2_NASM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tmap_vc.nas)
 endif()
 
 set(SRB2_NASM_OBJECTS
-	tmap_mmx.obj
-	tmap.obj
+	${CMAKE_CURRENT_BINARY_DIR}/tmap_mmx.obj
+	${CMAKE_CURRENT_BINARY_DIR}/tmap.obj
 )
 
 if(MSVC)
-	list(APPEND SRB2_NASM_OBJECTS tmap_vc.obj)
+	list(APPEND SRB2_NASM_OBJECTS ${CMAKE_CURRENT_BINARY_DIR}/tmap_vc.obj)
 endif()
 
-prepend_sources(SRB2_ASM_SOURCES)
-prepend_sources(SRB2_NASM_SOURCES)
+source_group("Assembly" FILES ${SRB2_ASM_SOURCES} ${SRB2_NASM_SOURCES})
 
 
 ### Configuration
@@ -229,11 +206,11 @@ set(SRB2_CONFIG_HAVE_BLUA ON CACHE BOOL
 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")
+	"Enable zlib support.")
 set(SRB2_CONFIG_HAVE_GME ON CACHE BOOL
-	"Enable GME support")
+	"Enable GME support.")
 set(SRB2_CONFIG_HWRENDER ON CACHE BOOL
-	"Enable hardware rendering through OpenGL")
+	"Enable hardware rendering through OpenGL.")
 set(SRB2_CONFIG_USEASM OFF CACHE BOOL
 	"Enable NASM tmap implementation for software mode speedup.")
 set(SRB2_CONFIG_YASM OFF CACHE BOOL
@@ -264,8 +241,7 @@ if(${SRB2_CONFIG_HAVE_BLUA})
 		lua_script.h
 	)
 
-	prepend_sources(SRB2_LUA_SOURCES)
-	prepend_sources(SRB2_LUA_HEADERS)
+	source_group("LUA" FILES ${SRB2_LUA_SOURCES} ${SRB2_LUA_HEADERS})
 
 	set(SRB2_BLUA_SOURCES
 		blua/lapi.c
@@ -318,8 +294,7 @@ if(${SRB2_CONFIG_HAVE_BLUA})
 		blua/lvm.h
 		blua/lzio.h
 	)
-	prepend_sources(SRB2_BLUA_SOURCES)
-	prepend_sources(SRB2_BLUA_HEADERS)
+	source_group("LUA\\Interpreter" FILES ${SRB2_BLUA_SOURCES} ${SRB2_BLUA_HEADERS})
 endif()
 
 if(${SRB2_CONFIG_HAVE_GME})
@@ -355,6 +330,36 @@ endif()
 
 if(${SRB2_CONFIG_HWRENDER})
 	add_definitions(-DHWRENDER)
+	set(SRB2_HWRENDER_SOURCES
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_bsp.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_cache.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_draw.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_trick.c
+	)
+
+	set (SRB2_HWRENDER_HEADERS
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_data.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_defs.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_dll.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_drv.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_glide.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_glob.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.h
+	)
+
+	set(SRB2_R_OPENGL_SOURCES
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/r_opengl/r_opengl.c
+	)
+
+	set(SRB2_R_OPENGL_HEADERS
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/r_opengl/r_opengl.h
+	)
+
 endif()
 
 if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
@@ -384,10 +389,6 @@ 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
 if(NOT CLANG AND NOT MSVC)
@@ -396,4 +397,23 @@ endif()
 
 add_definitions(-DCMAKECONFIG)
 
+add_library(SRB2Core STATIC
+	${SRB2_CORE_SOURCES}
+	${SRB2_CORE_HEADERS}
+	${SRB2_CORE_RENDER_SOURCES}
+	${SRB2_CORE_GAME_SOURCES}
+	${SRB2_LUA_SOURCES}
+	${SRB2_LUA_HEADERS}
+	${SRB2_BLUA_SOURCES}
+	${SRB2_BLUA_HEADERS}
+)
+
 add_subdirectory(sdl)
+
+if(${CMAKE_SYSTEM} MATCHES Windows)
+	add_subdirectory(win32)
+endif()
+
+if(NOT ${SRB2_SDL2_AVAILABLE} AND NOT ${SRB2_WIN32_AVAILABLE})
+	message(FATAL_ERROR "There are no targets available to build an SRB2 executable. :(")
+endif()
\ No newline at end of file
diff --git a/src/config.h.in b/src/config.h.in
index 7c5b299cfe375b67453121b30f5063c4d70f1e88..2ed7aec3e88d914abcf87843b1d025d23a04b2ae 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -3,6 +3,12 @@
 #ifndef __CONFIG_H__
 #define __CONFIG_H__
 
+/* DO NOT MODIFY config.h DIRECTLY! It will be overwritten by cmake.
+ * If you want to change a configuration option here, modify it in
+ * your CMakeCache.txt. config.h.in is used as a template for CMake
+ * variables, so you can insert them here too.
+ */
+
 #ifdef CMAKECONFIG
 
 #define ASSET_HASH_SRB2_SRB   "${SRB2_ASSET_srb2.srb_HASH}"
@@ -12,6 +18,8 @@
 #define ASSET_HASH_PATCH_DTA  "${SRB2_ASSET_patch.dta_HASH}"
 
 #define SRB2_COMP_REVISION    "${SRB2_COMP_REVISION}"
+#define SRB2_GIT_DESCRIBE     "${SRB2_GIT_DESCRIBE}"
+#define SRB2_GIT_BRANCH       "${SRB2_GIT_BRANCH}"
 
 #define CMAKE_ASSETS_DIR      "${CMAKE_SOURCE_DIR}/assets"
 
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index b4eeeeb5fb1c0e778be6a6a16758e0c116d9ad53..56dcb674d1442ce146c3044333598881bdde6732 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -39,16 +39,13 @@ set(SRB2_SDL2_HEADERS
 	sdlmain.h
 )
 
-prepend_sources(SRB2_SDL2_SOURCES)
-prepend_sources(SRB2_SDL2_HEADERS)
+source_group("Interface Code" FILES ${SRB2_SDL2_SOURCES} ${SRB2_SDL2_HEADERS})
 
 # Dependency
 find_package(SDL2)
 
 if(${SDL2_FOUND})
 	set(SRB2_SDL2_TOTAL_SOURCES
-		${SRB2_CORE_SOURCES}
-		${SRB2_CORE_HEADERS}
 		${SRB2_SDL2_SOURCES}
 		${SRB2_SDL2_HEADERS}
 	)
@@ -60,15 +57,9 @@ if(${SDL2_FOUND})
 			${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}
-		)
+		source_group("Hardware" FILES ${SRB2_HWRENDER_SOURCES} ${SRB2_HWRENDER_HEADERS})
+		source_group("Hardware\\OpenGL Renderer" FILES ${SRB2_R_OPENGL_SOURCES} ${SRB2_R_OPENGL_HEADERS})
 	endif()
 
 	if(${SRB2_USEASM})
@@ -85,7 +76,6 @@ if(${SDL2_FOUND})
 			set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES LANGUAGE C)
 			set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
 		endif()
-
 	endif()
 
 	if(${CMAKE_SYSTEM} MATCHES Windows)
@@ -94,39 +84,36 @@ if(${SDL2_FOUND})
 			${CMAKE_SOURCE_DIR}/src/win32/Srb2win.rc
 		)
 	endif()
-	if(NOT CLANG)
-		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
-			${CMAKE_SOURCE_DIR}/src/string.c
-		)
-	endif()
 
 	if(${CMAKE_SYSTEM} MATCHES Darwin)
 		set(MACOSX_BUNDLE_ICON_FILE Srb2mac.icns)
 		set_source_files_properties(macosx/Srb2mac.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
-		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+		set(SRB2_SDL2_MAC_SOURCES
 			macosx/mac_alert.c
 			macosx/mac_alert.h
 			macosx/mac_resources.c
 			macosx/mac_resources.h
 			macosx/Srb2mac.icns
 		)
+		source_group("Interface Code\\OSX Compatibility" FILES ${SRB2_SDL2_MAC_SOURCES})
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES} ${SRB2_SDL2_MAC_SOURCES})
 	endif()
 
+	add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
+	set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME ${SRB2_SDL2_EXE_NAME})
+
 	if(CLANG)
-		add_executable(${SRB2_SDL2_EXE_NAME} MACOSX_BUNDLE ${SRB2_SDL2_TOTAL_SOURCES})
-		add_framework(CoreFoundation ${SRB2_SDL2_EXE_NAME})
-		add_framework(SDL2 ${SRB2_SDL2_EXE_NAME})
-		add_framework(SDL2_mixer ${SRB2_SDL2_EXE_NAME})
-		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+		add_framework(CoreFoundation SRB2SDL2)
+		add_framework(SDL2 SRB2SDL2)
+		add_framework(SDL2_mixer SRB2SDL2)
+		target_link_libraries(SRB2SDL2 PRIVATE
 			${PNG_LIBRARIES}
 			${ZLIB_LIBRARIES}
 			${OPENGL_LIBRARIES}
 		)
-		set_target_properties(${SRB2_SDL2_EXE_NAME} PROPERTIES OUTPUT_NAME "Sonic Robo Blast 2")
+		set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME "Sonic Robo Blast 2")
 	else()
-		add_executable(${SRB2_SDL2_EXE_NAME} WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
-
-		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_link_libraries(SRB2SDL2 PRIVATE
 			${SDL2_LIBRARIES}
 			${SDL2_MIXER_LIBRARIES}
 			${PNG_LIBRARIES}
@@ -135,14 +122,15 @@ if(${SDL2_FOUND})
 		)
 
 		if(${CMAKE_SYSTEM} MATCHES Linux)
-			target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+			target_link_libraries(SRB2SDL2 PRIVATE
 				m
 				rt
 			)
 		endif()
-
 	endif()
 
+	target_link_libraries(SRB2SDL2 PRIVATE SRB2Core)
+
 	if(${SRB2_USEASM})
 		if(${SRB2_CONFIG_YASM})
 			set(ASM_ASSEMBLER_TEMP ${CMAKE_ASM_YASM_COMPILER})
@@ -159,7 +147,7 @@ if(${SDL2_FOUND})
 			foreach(ASMFILE ${SRB2_NASM_SOURCES})
 				get_filename_component(ASMFILE_NAME ${ASMFILE} NAME_WE)
 				set(ASMFILE_NAME ${ASMFILE_NAME}.obj)
-				add_custom_command(TARGET ${SRB2_SDL2_EXE_NAME} PRE_LINK
+				add_custom_command(TARGET SRB2SDL2 PRE_LINK
 					COMMAND ${ASM_ASSEMBLER_TEMP} ARGS -f ${ASM_ASSEMBLER_OBJFORMAT} -o ${CMAKE_CURRENT_BINARY_DIR}/${ASMFILE_NAME} ${ASMFILE}
 					COMMENT "assemble ${ASMFILE_NAME}."
 				)
@@ -167,23 +155,23 @@ if(${SDL2_FOUND})
 		endif()
 	endif()
 
-	set_target_properties(${SRB2_SDL2_EXE_NAME} PROPERTIES VERSION ${SRB2_VERSION})
+	set_target_properties(SRB2SDL2 PROPERTIES VERSION ${SRB2_VERSION})
 
 	if(${CMAKE_SYSTEM} MATCHES Windows)
-		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_link_libraries(SRB2SDL2 PRIVATE
 			ws2_32
 		)
-		target_compile_options(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_compile_options(SRB2SDL2 PRIVATE
 			-U_WINDOWS
 		)
 	endif()
 
 	if(MSVC)
 		find_package(SDL2_MAIN REQUIRED)
-		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_link_libraries(SRB2SDL2 PRIVATE
 			${SDL2_MAIN_LIBRARIES}
 		)
-		target_compile_options(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_compile_options(SRB2SDL2 PRIVATE
 			/Umain
 			/D_CRT_SECURE_NO_WARNINGS # something about string functions.
 			/D_CRT_NONSTDC_NO_DEPRECATE
@@ -192,7 +180,7 @@ if(${SDL2_FOUND})
 		)
 	endif()
 
-	target_include_directories(${SRB2_SDL2_EXE_NAME} PRIVATE
+	target_include_directories(SRB2SDL2 PRIVATE
 		${SDL2_INCLUDE_DIRS}
 		${SDL2_MIXER_INCLUDE_DIRS}
 		${PNG_INCLUDE_DIRS}
@@ -201,10 +189,10 @@ if(${SDL2_FOUND})
 	)
 
 	if(${SRB2_HAVE_MIXER})
-		target_compile_definitions(${SRB2_SDL2_EXE_NAME} PRIVATE -DHAVE_MIXER -DSOUND=SOUND_MIXER)
+		target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MIXER -DSOUND=SOUND_MIXER)
 	endif()
 
-	target_compile_definitions(${SRB2_SDL2_EXE_NAME} PRIVATE
+	target_compile_definitions(SRB2SDL2 PRIVATE
 		-DHAVE_SDL
 	)
 
@@ -212,21 +200,21 @@ if(${SDL2_FOUND})
 	if(CMAKE_COMPILER_IS_GNUCC)
 		if(${CMAKE_BUILD_TYPE} MATCHES Debug)
 			message(STATUS "Will make separate debug symbols in *.debug")
-			add_custom_command(TARGET ${SRB2_SDL2_EXE_NAME} POST_BUILD
-				COMMAND ${OBJCOPY} --only-keep-debug $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}> $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}>.debug
-				COMMAND ${OBJCOPY} --strip-debug $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}>
-				COMMAND ${OBJCOPY} --add-gnu-debuglink=$<TARGET_FILE_NAME:${SRB2_SDL2_EXE_NAME}>.debug $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}>
+			add_custom_command(TARGET SRB2SDL2 POST_BUILD
+				COMMAND ${OBJCOPY} --only-keep-debug $<TARGET_FILE:SRB2SDL2> $<TARGET_FILE:SRB2SDL2>.debug
+				COMMAND ${OBJCOPY} --strip-debug $<TARGET_FILE:SRB2SDL2>
+				COMMAND ${OBJCOPY} --add-gnu-debuglink=$<TARGET_FILE_NAME:SRB2SDL2>.debug $<TARGET_FILE:SRB2SDL2>
 			)
 		endif()
 	endif()
 
 	#### Installation ####
 	if (CLANG)
-		install(TARGETS ${SRB2_SDL2_EXE_NAME}
+		install(TARGETS SRB2SDL2
 			BUNDLE DESTINATION .
 		)
 	else()
-		install(TARGETS ${SRB2_SDL2_EXE_NAME} ${SRB2_SDL2_EXE_NAME}
+		install(TARGETS SRB2SDL2 SRB2SDL2
 			RUNTIME DESTINATION .
 		)
 	endif()
@@ -257,10 +245,10 @@ if(${SDL2_FOUND})
 
 		# We also want to copy those DLLs to build directories on MSVC.
 		# So we'll add a post_build step.
-		copy_files_to_build_dir(${SRB2_SDL2_EXE_NAME} win_extra_dll_list)
+		copy_files_to_build_dir(SRB2SDL2 win_extra_dll_list)
 	endif()
 
-	
+
 	# Mac bundle fixup
 	if(CLANG)
 		install(CODE "
@@ -271,6 +259,9 @@ if(${SDL2_FOUND})
 			)"
 		)
 	endif()
+
+	set(SRB2_SDL2_AVAILABLE YES PARENT_SCOPE)
 else()
-	message(WARNING "SDL2 wasn't found, so ${SRB2_SDL2_EXE_NAME} won't be available")
-endif()
+	message(WARNING "SDL2 was not found, so the SDL2 target will not be available.")
+	set(SRB2_SDL2_AVAILABLE NO PARENT_SCOPE)
+endif()
\ No newline at end of file
diff --git a/src/win32/CMakeLists.txt b/src/win32/CMakeLists.txt
index 94c198299add6162c63a69324207ba048d73cf01..39b01588b28c622a65f40ea63f9b2e541df220ec 100644
--- a/src/win32/CMakeLists.txt
+++ b/src/win32/CMakeLists.txt
@@ -1,11 +1,18 @@
-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
+file(GLOB SRB2_WIN_SOURCES *.c *.h *.rc)
+
+if(${SRB2_CONFIG_HWRENDER})
+	set(SRB2_WIN_SOURCES ${SRB2_WIN_SOURCES} ${SRB2_HWRENDER_SOURCES} ${SRB2_HWRENDER_HEADERS})
+	set(SRB2_WIN_SOURCES ${SRB2_WIN_SOURCES} ${SRB2_R_OPENGL_SOURCES} ${SRB2_R_OPENGL_HEADERS})
+endif()
+
+add_executable(SRB2DD EXCLUDE_FROM_ALL WIN32
+	${SRB2_WIN_SOURCES}
+)
+
+target_compile_definitions(SRB2DD PRIVATE
 	-D_WINDOWS
-)
\ No newline at end of file
+)
+
+set_target_properties(SRB2DD PROPERTIES OUTPUT_NAME ${SRB2_WIN_EXE_NAME})
+
+target_link_libraries(SRB2DD PRIVATE SRB2Core)