diff --git a/README.md b/README.md
index c45910f251efbd0c47ce3715ab0b8e83bc2685d2..f73ca45d3b0a5d94f9f9449a151cfc479f2caaa1 100644
--- a/README.md
+++ b/README.md
@@ -43,13 +43,14 @@ the framework if used. You can configure/adjust the build using CMake if necessa
  - [Algorithm](modules/algorithm/README.md)
  - [Asset-Loader](modules/asset_loader/README.md)
  - [Camera](modules/asset_loader/README.md)
- - [GUI](modules/gui/README.md)
  - [Effects](modules/effects/README.md)
  - [Geometry](modules/geometry/README.md)
+ - [GUI](modules/gui/README.md)
  - [Material](modules/material/README.md)
  - [Meshlet](modules/meshlet/README.md)
  - [Scene](modules/scene/README.md)
  - [Shader-Compiler](modules/shader_compiler/README.md)
+ - [Tone-Mapping](modules/tone_mapping/README.md)
  - [Upscaling](modules/upscaling/README.md)
 
 ### Projects (optional):
diff --git a/include/vkcv/File.hpp b/include/vkcv/File.hpp
index 51491b1b04a2a658f410e4872f7661237ca913b2..f6895d41bbefbedd2d6e9ac2c012c4f2a5ae3bb1 100644
--- a/include/vkcv/File.hpp
+++ b/include/vkcv/File.hpp
@@ -6,6 +6,7 @@
  */
 
 #include <filesystem>
+#include <vector>
 
 namespace vkcv {
 
@@ -22,5 +23,69 @@ namespace vkcv {
 	 * @return A unique path for a temporary directory
 	 */
 	std::filesystem::path generateTemporaryDirectoryPath();
+	
+	/**
+	 * @brief Write content data from a vector to a file at
+	 * a given path.
+	 *
+	 * @param[in] path Path of file
+	 * @param[in] content Custom data vector
+	 * @return True on success, false otherwise
+	 */
+	bool writeContentToFile(const std::filesystem::path &path,
+							const std::vector<char>& content);
+	
+	/**
+	 * @brief Write binary data from a vector to a file at
+	 * a given path.
+	 *
+	 * @param[in] path Path of file
+	 * @param[in] binary Custom binary vector
+	 * @return True on success, false otherwise
+	 */
+	bool writeBinaryToFile(const std::filesystem::path &path,
+						   const std::vector<uint32_t>& binary);
+	
+	/**
+	 * @brief Write text to a file at a given path.
+	 *
+	 * @param[in] path Path of file
+	 * @param[in] text Custom text as string
+	 * @return True on success, false otherwise
+	 */
+	bool writeTextToFile(const std::filesystem::path &path,
+						 const std::string& text);
+	
+	/**
+	 * @brief Read content data from a file at a given path
+	 * into a vector.
+	 *
+	 * @param[in] path Path of file
+	 * @param[in] content Custom data vector reference
+	 * @return True on success, false otherwise
+	 */
+	bool readContentFromFile(const std::filesystem::path &path,
+							 std::vector<char>& content);
+	
+	/**
+	 * @brief Read binary data from a file at a given path
+	 * into a vector.
+	 *
+	 * @param[in] path Path of file
+	 * @param[in] content Custom binary vector reference
+	 * @return True on success, false otherwise
+	 */
+	bool readBinaryFromFile(const std::filesystem::path &path,
+							std::vector<uint32_t>& binary);
+	
+	/**
+	 * @brief Read text from a file at a given path.
+	 *
+	 * @param[in] path Path of file
+	 * @param[in] text Custom text as string reference
+	 * @return True on success, false otherwise
+	 */
+	bool readTextFromFile(const std::filesystem::path &path,
+						  std::string& text);
 
 } // namespace vkcv
diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp
index 11156fdb5111da53df53ba7cbe80fa130d45b060..c14a36310ad7170251764e47f113df8869038da6 100644
--- a/include/vkcv/ShaderProgram.hpp
+++ b/include/vkcv/ShaderProgram.hpp
@@ -8,7 +8,6 @@
 
 #include <algorithm>
 #include <filesystem>
-#include <fstream>
 #include <iostream>
 #include <spirv_cross.hpp>
 #include <unordered_map>
diff --git a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp
index 051ae80d8d98e2ca5ce54f20d1e047b2151e87ca..21ea671ce93ebacaddf5c60bf24919455b63598e 100644
--- a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp
+++ b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp
@@ -96,53 +96,6 @@ namespace vkcv::algorithm {
 		return descriptorBindings;
 	}
 	
-	static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) {
-		std::ofstream file (shaderPath.string(), std::ios::out);
-		
-		if (!file.is_open()) {
-			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str());
-			return false;
-		}
-		
-		file.seekp(0);
-		file.write(code.c_str(), static_cast<std::streamsize>(code.length()));
-		file.close();
-		
-		return true;
-	}
-	
-	static bool compileSPDShader(vkcv::shader::GLSLCompiler& compiler,
-								 const std::string &source,
-								 const shader::ShaderCompiledFunction& compiled) {
-		std::filesystem::path directory = generateTemporaryDirectoryPath();
-		
-		if (!std::filesystem::create_directory(directory)) {
-			vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.string().c_str());
-			return false;
-		}
-		
-		if (!writeShaderCode(directory / "ffx_a.h", FFX_A_H_SHADER)) {
-			return false;
-		}
-		
-		if (!writeShaderCode(directory / "ffx_spd.h", FFX_SPD_H_SHADER)) {
-			return false;
-		}
-		
-		return compiler.compileSource(
-				vkcv::ShaderStage::COMPUTE,
-				source.c_str(),
-				[&directory, &compiled] (vkcv::ShaderStage shaderStage,
-										 const std::filesystem::path& path) {
-					if (compiled) {
-						compiled(shaderStage, path);
-					}
-					
-					std::filesystem::remove_all(directory);
-				}, directory
-		);
-	}
-	
 	SinglePassDownsampler::SinglePassDownsampler(Core &core,
 												 const SamplerHandle &sampler) :
 		 vkcv::Downsampler(core),
@@ -215,23 +168,19 @@ namespace vkcv::algorithm {
 		}
 		
 		ShaderProgram program;
-		if (m_sampler) {
-			compileSPDShader(
-					compiler,
-					SPDINTEGRATIONLINEARSAMPLER_GLSL_SHADER,
-					[&program](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
-						program.addShader(shaderStage, path);
-					}
-			);
-		} else {
-			compileSPDShader(
-					compiler,
+		compiler.compileSourceWithHeaders(
+				ShaderStage::COMPUTE,
+				m_sampler?
+					SPDINTEGRATIONLINEARSAMPLER_GLSL_SHADER :
 					SPDINTEGRATION_GLSL_SHADER,
-					[&program](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
-						program.addShader(shaderStage, path);
-					}
-			);
-		}
+				{
+					{ "ffx_a.h", FFX_A_H_SHADER },
+					{ "ffx_spd.h", FFX_SPD_H_SHADER }
+				},
+				[&program](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+					program.addShader(shaderStage, path);
+				}
+		);
 		
 		m_pipeline = m_core.createComputePipeline(ComputePipelineConfig(
 			program,
diff --git a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp
index 133b380095abc6c729ef94da675cc9f394475ab4..6f096ecd6d1f613587a17535a212e64396f254b1 100644
--- a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp
+++ b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp
@@ -150,7 +150,7 @@ namespace vkcv::effects {
 		ShaderProgram program;
 		compiler.compileSource(
 				vkcv::ShaderStage::COMPUTE,
-				shaderSource.c_str(),
+				shaderSource,
 				[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
 					program.addShader(shaderStage, path);
 				},
diff --git a/modules/effects/src/vkcv/effects/GammaCorrectionEffect.cpp b/modules/effects/src/vkcv/effects/GammaCorrectionEffect.cpp
index 088a3dbd97ae9654cdbfe6355b4837310c51bddc..d97df3fdc596cc53d37054745ff510c58f2d57ac 100644
--- a/modules/effects/src/vkcv/effects/GammaCorrectionEffect.cpp
+++ b/modules/effects/src/vkcv/effects/GammaCorrectionEffect.cpp
@@ -41,7 +41,7 @@ namespace vkcv::effects {
 		
 		compiler.compileSource(
 			ShaderStage::COMPUTE,
-			GAMMACORRECTION_COMP_SHADER.c_str(),
+			GAMMACORRECTION_COMP_SHADER,
 			[&program](ShaderStage stage, const std::filesystem::path &path) {
 				program.addShader(stage, path);
 			}
diff --git a/modules/shader_compiler/config/GLSLANG.cmake b/modules/shader_compiler/config/GLSLANG.cmake
index 98bd45497f9d7ed5196dbed486921f8e6ada12da..86bab2d3a770f62fddaac68168ea23977565598c 100644
--- a/modules/shader_compiler/config/GLSLANG.cmake
+++ b/modules/shader_compiler/config/GLSLANG.cmake
@@ -10,7 +10,7 @@ if (${glslang_status})
 	set(ENABLE_GLSLANG_WEBMIN_DEVEL OFF CACHE INTERNAL "")
 	set(ENABLE_EMSCRIPTEN_SINGLE_FILE OFF CACHE INTERNAL "")
 	set(ENABLE_EMSCRIPTEN_ENVIRONMENT_NODE OFF CACHE INTERNAL "")
-	set(ENABLE_HLSL OFF CACHE INTERNAL "")
+	set(ENABLE_HLSL ON CACHE INTERNAL "")
 	set(ENABLE_RTTI OFF CACHE INTERNAL "")
 	set(ENABLE_EXCEPTIONS OFF CACHE INTERNAL "")
 	set(ENABLE_OPT OFF CACHE INTERNAL "")
diff --git a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp
index 8096e9e22c7e7df4d48e0e658fa3e70842bb7db6..e30cdb34437d79699fbaecd660efc6852d580edb 100644
--- a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp
+++ b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp
@@ -48,9 +48,30 @@ namespace vkcv::shader {
          * @param[in] includePath Include path for shaders
          * @return Result if the compilation succeeds
          */
-		virtual bool compileSource(ShaderStage shaderStage, const char* shaderSource,
+		virtual bool compileSource(ShaderStage shaderStage,
+								   const std::string& shaderSource,
 								   const ShaderCompiledFunction& compiled,
 								   const std::filesystem::path& includePath) = 0;
+		
+		/**
+		 * Compile a shader from source for a target stage with some included headers
+		 * as source as well and an event function called if the compilation completes.
+		 *
+		 * The included shaders will be stored temporarily for shader compilation in
+		 * a directory which gets used as include path. So these files can be used via
+		 * include instructions in the shader source code as if they were stored in the
+		 * same directory.
+		 *
+		 * @param[in] shaderStage Shader pipeline stage
+		 * @param[in] shaderSource Source of shader
+		 * @param[in] shaderHeaders Headers of shader
+		 * @param[in] compiled Shader compilation event
+		 * @return Result if the compilation succeeds
+		 */
+		bool compileSourceWithHeaders(ShaderStage shaderStage,
+									  const std::string& shaderSource,
+									  const std::unordered_map<std::filesystem::path, std::string>& shaderHeaders,
+									  const ShaderCompiledFunction& compiled);
 
         /**
          * Compile a shader from a specific file path for a target stage with
@@ -81,8 +102,7 @@ namespace vkcv::shader {
          * @param[in] update Flag to update shaders during runtime
          */
 		void compileProgram(ShaderProgram& program,
-							const std::unordered_map<ShaderStage,
-							const std::filesystem::path>& stages,
+							const std::unordered_map<ShaderStage, const std::filesystem::path>& stages,
 							const ShaderProgramCompiledFunction& compiled,
 							const std::filesystem::path& includePath = "",
 							bool update = false);
diff --git a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp
index 48b3024fc62fc3c2f9a0975384298d82d3e8b3ea..cebc8bb73297de07899d611b7bf467a93f2bffca 100644
--- a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp
+++ b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp
@@ -45,7 +45,7 @@ namespace vkcv::shader {
          * @return Result if the compilation succeeds
          */
 		bool compileSource(ShaderStage shaderStage,
-						   const char* shaderSource,
+						   const std::string& shaderSource,
 						   const ShaderCompiledFunction& compiled,
 						   const std::filesystem::path& includePath = "") override;
 		
diff --git a/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp
index 79a86cf580f1de30e20e9b4e7eaff37f4896cddb..837b9b1dd5aea34386ac4060068ff61b22823f91 100644
--- a/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp
+++ b/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp
@@ -16,25 +16,6 @@ namespace vkcv::shader {
 	 * An abstract class to handle Glslang runtime shader compilation.
 	 */
 	class GlslangCompiler : public Compiler {
-	protected:
-		/**
-		 *
-		 *
-		 * @param[in] shaderPath Filepath of shader
-		 * @param[out] spirv
-		 * @return
-		 */
-		static bool writeSpirvCode(const std::filesystem::path &shaderPath,
-								   const std::vector<uint32_t>& spirv);
-		
-		/**
-		 *
-		 *
-		 * @param[in] shaderPath Filepath of shader
-		 * @return
-		 */
-		static std::vector<char> readShaderCode(const std::filesystem::path &shaderPath);
-		
 	public:
 		/**
 		 * The constructor of a runtime Glslang shader compiler instance.
diff --git a/modules/shader_compiler/include/vkcv/shader/HLSLCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/HLSLCompiler.hpp
index 9baf2cbfdd7ad65fe5bb050e8749c39e96d83d4e..dad4c38b50b5fe8a774484ece5f5f92b900665f6 100644
--- a/modules/shader_compiler/include/vkcv/shader/HLSLCompiler.hpp
+++ b/modules/shader_compiler/include/vkcv/shader/HLSLCompiler.hpp
@@ -42,7 +42,7 @@ namespace vkcv::shader {
 		 * @return Result if the compilation succeeds
 		 */
 		bool compileSource(ShaderStage shaderStage,
-						   const char* shaderSource,
+						   const std::string& shaderSource,
 						   const ShaderCompiledFunction& compiled,
 						   const std::filesystem::path& includePath = "") override;
 		
diff --git a/modules/shader_compiler/src/vkcv/shader/Compiler.cpp b/modules/shader_compiler/src/vkcv/shader/Compiler.cpp
index dcf9e5167c2b2fdd251e4e245a8ea7a6d7e62712..c7935f8905bb86b5f93c9f5fe98f2f6e3a6e85c2 100644
--- a/modules/shader_compiler/src/vkcv/shader/Compiler.cpp
+++ b/modules/shader_compiler/src/vkcv/shader/Compiler.cpp
@@ -1,8 +1,46 @@
 
 #include "vkcv/shader/Compiler.hpp"
 
+#include <vkcv/File.hpp>
+#include <vkcv/Logger.hpp>
+
 namespace vkcv::shader {
 	
+	bool Compiler::compileSourceWithHeaders(ShaderStage shaderStage,
+											const std::string &shaderSource,
+											const std::unordered_map<std::filesystem::path, std::string> &shaderHeaders,
+											const ShaderCompiledFunction &compiled) {
+		const std::filesystem::path directory = generateTemporaryDirectoryPath();
+		
+		if (!std::filesystem::create_directory(directory)) {
+			vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.c_str());
+			return false;
+		}
+		
+		for (const auto& header : shaderHeaders) {
+			if (header.first.has_parent_path()) {
+				std::filesystem::create_directories(directory / header.first.parent_path());
+			}
+			
+			if (!writeTextToFile(directory / header.first, header.second)) {
+				return false;
+			}
+		}
+		
+		return compileSource(
+				shaderStage,
+				shaderSource,
+				[&directory, &compiled] (vkcv::ShaderStage shaderStage,
+										 const std::filesystem::path& path) {
+					if (compiled) {
+						compiled(shaderStage, path);
+					}
+					
+					std::filesystem::remove_all(directory);
+				}, directory
+		);
+	}
+	
 	void Compiler::compileProgram(ShaderProgram& program,
 								  const std::unordered_map<ShaderStage, const std::filesystem::path>& stages,
 								  const ShaderProgramCompiledFunction& compiled,
diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp
index 0f423557be7b91999dafce089abec6b98a538228..a3856076817380c67275b92a3a8239bdff667f5b 100644
--- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp
+++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp
@@ -153,7 +153,7 @@ namespace vkcv::shader {
 	}
 	
 	bool GLSLCompiler::compileSource(ShaderStage shaderStage,
-									 const char* shaderSource,
+									 const std::string& shaderSource,
 									 const ShaderCompiledFunction &compiled,
 									 const std::filesystem::path& includePath) {
 		const EShLanguage language = findShaderLanguage(shaderStage);
@@ -166,12 +166,12 @@ namespace vkcv::shader {
 		glslang::TShader shader (language);
 		switch (m_target) {
 			case GLSLCompileTarget::SUBGROUP_OP:
-				shader.setEnvClient(glslang::EShClientVulkan,glslang::EShTargetVulkan_1_1);
-				shader.setEnvTarget(glslang::EShTargetSpv,glslang::EShTargetSpv_1_3);
+				shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_1);
+				shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3);
 				break;
 			case GLSLCompileTarget::RAY_TRACING:
-				shader.setEnvClient(glslang::EShClientVulkan,glslang::EShTargetVulkan_1_2);
-				shader.setEnvTarget(glslang::EShTargetSpv,glslang::EShTargetSpv_1_4);
+				shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_2);
+				shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4);
 				break;
 			default:
 				break;
@@ -257,7 +257,7 @@ namespace vkcv::shader {
 		
 		const std::filesystem::path tmp_path = generateTemporaryFilePath();
 		
-		if (!writeSpirvCode(tmp_path, spirv)) {
+		if (!writeBinaryToFile(tmp_path, spirv)) {
 			vkcv_log(LogLevel::ERROR, "Spir-V could not be written to disk");
 			return false;
 		}
diff --git a/modules/shader_compiler/src/vkcv/shader/GlslangCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GlslangCompiler.cpp
index 9ee6952b067d182a5a92a034b07d695cbac7606b..1f20daaeaf98aaec251f163961b5bf377d760757 100644
--- a/modules/shader_compiler/src/vkcv/shader/GlslangCompiler.cpp
+++ b/modules/shader_compiler/src/vkcv/shader/GlslangCompiler.cpp
@@ -1,9 +1,9 @@
 
 #include "vkcv/shader/GlslangCompiler.hpp"
 
+#include <vkcv/File.hpp>
 #include <vkcv/Logger.hpp>
 
-#include <fstream>
 #include <glslang/SPIRV/GlslangToSpv.h>
 
 namespace vkcv::shader {
@@ -35,57 +35,22 @@ namespace vkcv::shader {
 		return *this;
 	}
 	
-	bool GlslangCompiler::writeSpirvCode(const std::filesystem::path &shaderPath,
-										 const std::vector<uint32_t>& spirv) {
-		std::ofstream file (shaderPath.string(), std::ios::out | std::ios::binary);
-		
-		if (!file.is_open()) {
-			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str());
-			return false;
-		}
-		
-		const auto fileSize = static_cast<std::streamsize>(
-				sizeof(uint32_t) * spirv.size()
-		);
-		
-		file.seekp(0);
-		file.write(reinterpret_cast<const char*>(spirv.data()), fileSize);
-		file.close();
-		
-		return true;
-	}
-	
-	std::vector<char> GlslangCompiler::readShaderCode(const std::filesystem::path &shaderPath) {
-		std::ifstream file (shaderPath.string(), std::ios::ate);
-		
-		if (!file.is_open()) {
-			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str());
-			return std::vector<char>{};
-		}
-		
-		std::streamsize fileSize = file.tellg();
-		std::vector<char> buffer (fileSize + 1);
-		
-		file.seekg(0);
-		file.read(buffer.data(), fileSize);
-		file.close();
-		
-		buffer[fileSize] = '\0';
-		return buffer;
-	}
-	
 	void GlslangCompiler::compile(ShaderStage shaderStage,
 								  const std::filesystem::path &shaderPath,
 								  const ShaderCompiledFunction &compiled,
 								  const std::filesystem::path &includePath,
 								  bool update) {
-		const std::vector<char> code = readShaderCode(shaderPath);
-		bool result;
+		std::string shaderCode;
+		bool result = readTextFromFile(shaderPath, shaderCode);
+		
+		if (!result) {
+			vkcv_log(LogLevel::ERROR, "Loading shader failed: (%s)", shaderPath.string().c_str());
+		}
 		
 		if (!includePath.empty()) {
-			result = compileSource(shaderStage, code.data(), compiled, includePath);
+			result = compileSource(shaderStage, shaderCode, compiled, includePath);
 		} else {
-			result = compileSource(shaderStage, code.data(), compiled, shaderPath.parent_path());
+			result = compileSource(shaderStage, shaderCode, compiled, shaderPath.parent_path());
 		}
 		
 		if (!result) {
diff --git a/modules/shader_compiler/src/vkcv/shader/HLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/HLSLCompiler.cpp
index 6724d008d34e45ac6cbcdde7ec523de25f2bbef1..629f941cdb5fa5e59d6f419374fff4d424aaafaa 100644
--- a/modules/shader_compiler/src/vkcv/shader/HLSLCompiler.cpp
+++ b/modules/shader_compiler/src/vkcv/shader/HLSLCompiler.cpp
@@ -153,7 +153,7 @@ namespace vkcv::shader {
 	}
 	
 	bool HLSLCompiler::compileSource(ShaderStage shaderStage,
-									 const char* shaderSource,
+									 const std::string& shaderSource,
 									 const ShaderCompiledFunction &compiled,
 									 const std::filesystem::path& includePath) {
 		const EShLanguage language = findShaderLanguage(shaderStage);
@@ -164,11 +164,22 @@ namespace vkcv::shader {
 		}
 		
 		glslang::TShader shader (language);
+		shader.setEntryPoint("main");
+		
 		switch (m_target) {
 			default:
+				shader.setEnvClient(glslang::EShClientNone, glslang::EShTargetVulkan_1_1);
+				shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3);
 				break;
 		}
 		
+		shader.setEnvInput(
+				glslang::EShSourceHlsl,
+				language,
+				glslang::EShClientNone,
+				100
+		);
+		
 		glslang::TProgram program;
 		std::string source (shaderSource);
 		
@@ -204,7 +215,12 @@ namespace vkcv::shader {
 		
 		const auto messages = (EShMessages)(
 				EShMsgSpvRules |
-				EShMsgVulkanRules
+				EShMsgVulkanRules |
+				EShMsgReadHlsl |
+				EShMsgHlslOffsets |
+				EShMsgHlslEnable16BitTypes |
+				EShMsgHlslLegalization |
+				EShMsgHlslDX9Compatible
 		);
 		
 		std::string preprocessedHLSL;
@@ -249,7 +265,7 @@ namespace vkcv::shader {
 		
 		const std::filesystem::path tmp_path = generateTemporaryFilePath();
 		
-		if (!writeSpirvCode(tmp_path, spirv)) {
+		if (!writeBinaryToFile(tmp_path, spirv)) {
 			vkcv_log(LogLevel::ERROR, "Spir-V could not be written to disk");
 			return false;
 		}
diff --git a/modules/tone_mapping/README.md b/modules/tone_mapping/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..8a883001adb624b9eed89239e53abce42f93fca5
--- /dev/null
+++ b/modules/tone_mapping/README.md
@@ -0,0 +1,15 @@
+# Tone Mapping
+
+A VkCV module to use tone mapping on images in realtime after rendering
+
+## Build
+
+### Dependencies (required):
+
+| Name of dependency                                       | Used as submodule |
+|----------------------------------------------------------|-------------------|
+| [glsl-tone-map](https://github.com/dmnsgn/glsl-tone-map) | ✅                 |
+
+## Docs
+
+Here is a [link](https://userpages.uni-koblenz.de/~vkcv/doc/group__vkcv__tone.html) to this module.
diff --git a/modules/tone_mapping/src/vkcv/tone/ToneMapping.cpp b/modules/tone_mapping/src/vkcv/tone/ToneMapping.cpp
index 3323d8797c34afd2890c433c5849bd8fdf9c807e..7150d17210a7ca7047fd01f2ed3d37b37686a86c 100644
--- a/modules/tone_mapping/src/vkcv/tone/ToneMapping.cpp
+++ b/modules/tone_mapping/src/vkcv/tone/ToneMapping.cpp
@@ -65,7 +65,7 @@ namespace vkcv::tone {
 		
 		compiler.compileSource(
 				ShaderStage::COMPUTE,
-				stream.str().c_str(),
+				stream.str(),
 				[&](ShaderStage stage, const std::filesystem::path &path) {
 					program.addShader(stage, path);
 				}
diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
index bacb4ce0814ff0caec0c3d4d353ecf5019e0eda4..dd92b42a79c4320a464986b9337ed4bb87580a6e 100644
--- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
+++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
@@ -13,7 +13,6 @@
 #include "FSR_Pass.glsl.hxx"
 
 #include <vkcv/File.hpp>
-#include <vkcv/Logger.hpp>
 #include <vkcv/shader/GLSLCompiler.hpp>
 
 namespace vkcv::upscaling {
@@ -107,52 +106,6 @@ namespace vkcv::upscaling {
 	    return descriptorBindings;
 	}
 	
-	static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) {
-		std::ofstream file (shaderPath.string(), std::ios::out);
-		
-		if (!file.is_open()) {
-			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str());
-			return false;
-		}
-		
-		file.seekp(0);
-		file.write(code.c_str(), static_cast<std::streamsize>(code.length()));
-		file.close();
-		
-		return true;
-	}
-	
-	static bool compileFSRShader(vkcv::shader::GLSLCompiler& compiler,
-								 const shader::ShaderCompiledFunction& compiled) {
-		std::filesystem::path directory = generateTemporaryDirectoryPath();
-		
-		if (!std::filesystem::create_directory(directory)) {
-			vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.string().c_str());
-			return false;
-		}
-		
-		if (!writeShaderCode(directory / "ffx_a.h", FFX_A_H_SHADER)) {
-			return false;
-		}
-		
-		if (!writeShaderCode(directory / "ffx_fsr1.h", FFX_FSR1_H_SHADER)) {
-			return false;
-		}
-		
-		return compiler.compileSource(
-				vkcv::ShaderStage::COMPUTE,
-				FSR_PASS_GLSL_SHADER.c_str(),
-				[&directory, &compiled] (vkcv::ShaderStage shaderStage,
-										 const std::filesystem::path& path) {
-				if (compiled) {
-					compiled(shaderStage, path);
-				}
-				
-				std::filesystem::remove_all(directory);
-			}, directory
-		);
-	}
-	
 	FSRUpscaling::FSRUpscaling(Core& core) :
 	Upscaling(core),
 	m_easuPipeline(),
@@ -216,12 +169,20 @@ namespace vkcv::upscaling {
 		
 		{
 			ShaderProgram program;
-			compileFSRShader(easuCompiler, [&program](vkcv::ShaderStage shaderStage,
-				const std::filesystem::path& path) {
-				program.addShader(shaderStage, path);
-			});
+			easuCompiler.compileSourceWithHeaders(
+					ShaderStage::COMPUTE,
+					FSR_PASS_GLSL_SHADER,
+					{
+						{ "ffx_a.h", FFX_A_H_SHADER },
+						{ "ffx_fsr1.h", FFX_FSR1_H_SHADER }
+					},
+					[&program](vkcv::ShaderStage shaderStage,
+							   const std::filesystem::path& path) {
+						program.addShader(shaderStage, path);
+					}
+			);
 
-			m_easuPipeline = m_core.createComputePipeline({program,{
+			m_easuPipeline = m_core.createComputePipeline({ program, {
 				m_easuDescriptorSetLayout
 			}});
 
@@ -238,10 +199,18 @@ namespace vkcv::upscaling {
 		
 		{
 			ShaderProgram program;
-			compileFSRShader(rcasCompiler, [&program](vkcv::ShaderStage shaderStage,
-					const std::filesystem::path& path) {
-				program.addShader(shaderStage, path);
-			});
+			rcasCompiler.compileSourceWithHeaders(
+					ShaderStage::COMPUTE,
+					FSR_PASS_GLSL_SHADER,
+					{
+							{ "ffx_a.h", FFX_A_H_SHADER },
+							{ "ffx_fsr1.h", FFX_FSR1_H_SHADER }
+					},
+					[&program](vkcv::ShaderStage shaderStage,
+							   const std::filesystem::path& path) {
+						program.addShader(shaderStage, path);
+					}
+			);
 
 			m_rcasPipeline = m_core.createComputePipeline({ program, {
 				m_rcasDescriptorSetLayout
diff --git a/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp
index 8c3a973e6914f4cb9b31eef1acf805e6448237eb..40eb63ff4ffe867dce4b2a4dd4c95e5965360bff 100644
--- a/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp
+++ b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp
@@ -89,48 +89,6 @@ namespace vkcv::upscaling {
 		return image.getHandle();
 	}
 	
-	static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) {
-		std::ofstream file (shaderPath.string(), std::ios::out);
-		
-		if (!file.is_open()) {
-			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str());
-			return false;
-		}
-		
-		file.seekp(0);
-		file.write(code.c_str(), static_cast<std::streamsize>(code.length()));
-		file.close();
-		
-		return true;
-	}
-	
-	static bool compileNISShader(vkcv::shader::GLSLCompiler& compiler,
-								 const shader::ShaderCompiledFunction& compiled) {
-		std::filesystem::path directory = generateTemporaryDirectoryPath();
-		
-		if (!std::filesystem::create_directory(directory)) {
-			vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.string().c_str());
-			return false;
-		}
-		
-		if (!writeShaderCode(directory / "NIS_Scaler.h", NIS_SCALER_H_SHADER)) {
-			return false;
-		}
-		
-		return compiler.compileSource(
-				vkcv::ShaderStage::COMPUTE,
-				NIS_MAIN_GLSL_SHADER.c_str(),
-				[&directory, &compiled] (vkcv::ShaderStage shaderStage,
-										 const std::filesystem::path& path) {
-				if (compiled) {
-					compiled(shaderStage, path);
-				}
-				
-				std::filesystem::remove_all(directory);
-			}, directory
-		);
-	}
-	
 	NISUpscaling::NISUpscaling(Core &core) :
 	Upscaling(core),
 	m_scalerPipeline(),
@@ -178,16 +136,22 @@ namespace vkcv::upscaling {
 		
 		{
 			ShaderProgram program;
-			compileNISShader(scalerCompiler, [&program](vkcv::ShaderStage shaderStage,
-														const std::filesystem::path& path) {
-				program.addShader(shaderStage, path);
-			});
+			scalerCompiler.compileSourceWithHeaders(
+					ShaderStage::COMPUTE,
+					NIS_MAIN_GLSL_SHADER,
+					{
+						{ "NIS_Scaler.h", NIS_SCALER_H_SHADER }
+					},
+					[&program](vkcv::ShaderStage shaderStage,
+							   const std::filesystem::path& path) {
+						program.addShader(shaderStage, path);
+					}
+			);
 			
 			m_scalerPipeline = m_core.createComputePipeline({program,{
 					m_scalerDescriptorSetLayout
 			}});
 			
-			
 			DescriptorWrites writes;
 			writes.writeUniformBuffer(
 					0, m_scalerConstants.getHandle(), true
diff --git a/src/vkcv/File.cpp b/src/vkcv/File.cpp
index f840fdb06850d6943864ef119883996a461a13fe..32ded3e5dba876ed0c973f80ac3eb4203d0d68b2 100644
--- a/src/vkcv/File.cpp
+++ b/src/vkcv/File.cpp
@@ -9,6 +9,8 @@
 #include <unistd.h>
 #endif
 
+#include <fstream>
+
 #include "vkcv/Logger.hpp"
 
 namespace vkcv {
@@ -54,5 +56,124 @@ namespace vkcv {
 
 		return tmp / name;
 	}
+	
+	bool writeContentToFile(const std::filesystem::path &path,
+							const std::vector<char>& content) {
+		std::ofstream file (path.string(), std::ios::out);
+		
+		if (!file.is_open()) {
+			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str());
+			return false;
+		}
+		
+		file.seekp(0);
+		file.write(content.data(), static_cast<std::streamsize>(content.size()));
+		file.close();
+		
+		return true;
+	}
+	
+	bool writeBinaryToFile(const std::filesystem::path &path,
+						   const std::vector<uint32_t>& binary) {
+		std::ofstream file (path.string(), std::ios::out);
+		
+		if (!file.is_open()) {
+			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str());
+			return false;
+		}
+		
+		file.seekp(0);
+		file.write(
+				reinterpret_cast<const char*>(binary.data()),
+				static_cast<std::streamsize>(binary.size() * sizeof(uint32_t))
+		);
+		file.close();
+		
+		return true;
+	}
+	
+	bool writeTextToFile(const std::filesystem::path &path,
+						 const std::string& text) {
+		std::ofstream file (path.string(), std::ios::out);
+		
+		if (!file.is_open()) {
+			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str());
+			return false;
+		}
+		
+		file.seekp(0);
+		file.write(text.c_str(), static_cast<std::streamsize>(text.length()));
+		file.close();
+		
+		return true;
+	}
+	
+	bool readContentFromFile(const std::filesystem::path &path,
+							 std::vector<char>& content) {
+		std::ifstream file (path.string(), std::ios::ate);
+		
+		if (!file.is_open()) {
+			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str());
+			return false;
+		}
+		
+		const std::streamsize fileSize = file.tellg();
+		content.resize(fileSize);
+		
+		file.seekg(0);
+		file.read(content.data(), fileSize);
+		file.close();
+		
+		return true;
+	}
+	
+	bool readBinaryFromFile(const std::filesystem::path &path,
+							std::vector<uint32_t>& binary) {
+		std::ifstream file (path.string(), std::ios::ate);
+		
+		if (!file.is_open()) {
+			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str());
+			return false;
+		}
+		
+		const std::streamsize fileSize = file.tellg();
+		
+		if (fileSize % sizeof(uint32_t) != 0) {
+			vkcv_log(LogLevel::ERROR, "The file is not a valid binary: %s", path.c_str());
+			return false;
+		}
+		
+		binary.resize(fileSize / sizeof(uint32_t));
+		
+		file.seekg(0);
+		file.read(
+				reinterpret_cast<char*>(binary.data()),
+				static_cast<std::streamsize>(binary.size() * sizeof(uint32_t))
+		);
+		file.close();
+		
+		return true;
+	}
+	
+	bool readTextFromFile(const std::filesystem::path &path,
+						  std::string& text) {
+		std::ifstream file (path.string(), std::ios::ate);
+		
+		if (!file.is_open()) {
+			vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str());
+			return false;
+		}
+		
+		const std::streamsize fileSize = file.tellg();
+		std::vector<char> buffer (fileSize);
+		buffer.resize(fileSize);
+		
+		file.seekg(0);
+		file.read(buffer.data(), fileSize);
+		file.close();
+		
+		text = std::string(buffer.data(), buffer.size());
+		return true;
+	}
 
 } // namespace vkcv
diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp
index 508f4de536fc193f9b213c87e7de7e3fe0679959..099af639a798938cf6de7a128b72bf9dbe7f7660 100644
--- a/src/vkcv/ShaderProgram.cpp
+++ b/src/vkcv/ShaderProgram.cpp
@@ -5,38 +5,11 @@
  */
 
 #include "vkcv/ShaderProgram.hpp"
+
+#include "vkcv/File.hpp"
 #include "vkcv/Logger.hpp"
 
 namespace vkcv {
-	/**
-	 * Reads the file of a given shader code.
-	 * Only used within the class.
-	 * @param[in] relative path to the shader code
-	 * @return vector of chars as a buffer for the code
-	 */
-	std::vector<uint32_t> readShaderCode(const std::filesystem::path &shaderPath) {
-		std::ifstream file(shaderPath.string(), std::ios::ate | std::ios::binary);
-
-		if (!file.is_open()) {
-			vkcv_log(LogLevel::ERROR, "The file could not be opened: %s", shaderPath.c_str());
-			return std::vector<uint32_t>();
-		}
-
-		size_t fileSize = (size_t)file.tellg();
-
-		if (fileSize % sizeof(uint32_t) != 0) {
-			vkcv_log(LogLevel::ERROR, "The file is not a valid shader: %s", shaderPath.c_str());
-			return std::vector<uint32_t>();
-		}
-
-		std::vector<uint32_t> buffer(fileSize / sizeof(uint32_t));
-
-		file.seekg(0);
-		file.read(reinterpret_cast<char*>(buffer.data()), fileSize);
-		file.close();
-
-		return buffer;
-	}
 
 	VertexAttachmentFormat convertFormat(spirv_cross::SPIRType::BaseType basetype,
 										 uint32_t vecsize) {
@@ -85,15 +58,14 @@ namespace vkcv {
 			vkcv_log(LogLevel::WARNING, "Overwriting existing shader stage");
 		}
 
-		const std::vector<uint32_t> shaderCode = readShaderCode(path);
-
-		if (shaderCode.empty()) {
+		std::vector<uint32_t> shaderCode;
+		if ((!readBinaryFromFile(path, shaderCode)) || (shaderCode.empty())) {
 			return false;
-		} else {
-			m_Shaders.insert(std::make_pair(stage, shaderCode));
-			reflectShader(stage);
-			return true;
 		}
+		
+		m_Shaders.insert(std::make_pair(stage, shaderCode));
+		reflectShader(stage);
+		return true;
 	}
 
 	const std::vector<uint32_t> &ShaderProgram::getShaderBinary(ShaderStage stage) const {