diff --git a/config/Sources.cmake b/config/Sources.cmake
index eeb281c9e37c35e42e078d6137c115a210fc1107..fefdb6d8c8400d50424fdb3c95d732c6c4ce08e2 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -27,7 +27,7 @@ set(vkcv_sources
 		${vkcv_include}/vkcv/Image.hpp
 		${vkcv_source}/vkcv/Image.cpp
 
-		${vkcv_include}/vkcv/ImageManager.hpp
+		${vkcv_source}/vkcv/ImageManager.hpp
 		${vkcv_source}/vkcv/ImageManager.cpp
 
 		${vkcv_include}/vkcv/SwapChain.hpp
diff --git a/include/vkcv/BufferManager.hpp b/include/vkcv/BufferManager.hpp
index 0df3030167cea3d109f47ad932978cce08a7c63e..4b12f47ba8497bd09260d24523c28f207f64a98c 100644
--- a/include/vkcv/BufferManager.hpp
+++ b/include/vkcv/BufferManager.hpp
@@ -25,16 +25,15 @@ namespace vkcv
 	class BufferManager
 	{
 		friend class Core;
-		friend class ImageManager;
 	private:
 		
 		struct Buffer
 		{
 			vk::Buffer m_handle;
 			vk::DeviceMemory m_memory;
-			size_t m_size;
+			size_t m_size = 0;
 			void* m_mapped = nullptr;
-			bool m_mappable;
+			bool m_mappable = false;
 		};
 		
 		Core* m_core;
@@ -56,7 +55,7 @@ namespace vkcv
 		
 		/**
 		 * Creates and allocates a new buffer and returns its
-		 * unique buffer handle id.
+		 * unique buffer handle.
 		 *
 		 * @param type Type of buffer
 		 * @param size Size of buffer in bytes
@@ -67,7 +66,7 @@ namespace vkcv
 		
 		/**
 		 * Returns the Vulkan buffer handle of a buffer
-		 * represented by a given buffer handle id.
+		 * represented by a given buffer handle.
 		 *
 		 * @param handle Buffer handle
 		 * @return Vulkan buffer handle
@@ -75,6 +74,16 @@ namespace vkcv
 		[[nodiscard]]
 		vk::Buffer getBuffer(const BufferHandle& handle) const;
 		
+		/**
+		 * Returns the size of a buffer represented
+		 * by a given buffer handle.
+		 *
+		 * @param handle Buffer handle
+		 * @return Size of the buffer
+		 */
+		[[nodiscard]]
+		size_t getBufferSize(const BufferHandle& handle) const;
+		
 		/**
 		 * Returns the Vulkan device memory handle of a buffer
 		 * represented by a given buffer handle id.
@@ -87,7 +96,7 @@ namespace vkcv
 		
 		/**
 		 * Fills a buffer represented by a given buffer
-		 * handle id with custom data.
+		 * handle with custom data.
 		 *
 		 * @param handle Buffer handle
 		 * @param data Pointer to data
@@ -98,7 +107,7 @@ namespace vkcv
 		
 		/**
 		 * Maps memory to a buffer represented by a given
-		 * buffer handle id and returns it.
+		 * buffer handle and returns it.
 		 *
 		 * @param handle Buffer handle
 		 * @param offset Offset of mapping in bytes
@@ -109,7 +118,7 @@ namespace vkcv
 		
 		/**
 		 * Unmaps memory from a buffer represented by a given
-		 * buffer handle id.
+		 * buffer handle.
 		 *
 		 * @param handle Buffer handle
 		 */
@@ -117,7 +126,7 @@ namespace vkcv
 	
 		/**
 		 * Destroys and deallocates buffer represented by a given
-		 * buffer handle id.
+		 * buffer handle.
 		 *
 		 * @param handle Buffer handle
 		 */
diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp
index 7b500ea514f1034e9822f9c12936b5e63ba3225e..1fd6573976b1f5aab572eb982cc0c61eff01a9e9 100644
--- a/include/vkcv/Handles.hpp
+++ b/include/vkcv/Handles.hpp
@@ -64,4 +64,10 @@ namespace vkcv
 		using Handle::Handle;
 	};
 	
+	class ImageHandle : public Handle {
+		friend class ImageManager;
+	private:
+		using Handle::Handle;
+	};
+	
 }
diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp
index 5ebaf9211c47d9994bd17d560204484eb9dad1c5..1c162cdc4a9494d484d97ab39613144571a26283 100644
--- a/include/vkcv/Image.hpp
+++ b/include/vkcv/Image.hpp
@@ -6,12 +6,17 @@
  */
 #include "vulkan/vulkan.hpp"
 
+#include "Handles.hpp"
+
 namespace vkcv {
 	
 	class ImageManager;
 	class Image {
 	public:
-		static Image create(ImageManager* manager, uint32_t width, uint32_t height);
+		static Image create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth);
+		
+		[[nodiscard]]
+		vk::Format getFormat() const;
 		
 		[[nodiscard]]
 		uint32_t getWidth() const;
@@ -19,18 +24,25 @@ namespace vkcv {
 		[[nodiscard]]
 		uint32_t getHeight() const;
 		
+		[[nodiscard]]
+		uint32_t getDepth() const;
+		
 		[[nodiscard]]
 		vk::ImageLayout getLayout() const;
 		
 		void switchLayout(vk::ImageLayout newLayout);
+		
+		void fill(void* data, size_t size = SIZE_MAX);
 	private:
 		ImageManager* const m_manager;
-		const uint64_t m_handle_id;
+		const ImageHandle m_handle;
+		const vk::Format m_format;
 		const uint32_t m_width;
 		const uint32_t m_height;
+		const uint32_t m_depth;
 		vk::ImageLayout m_layout;
 
-		Image(ImageManager* manager, uint64_t id, uint32_t width, uint32_t height);
+		Image(ImageManager* manager, const ImageHandle& handle, vk::Format format, uint32_t width, uint32_t height, uint32_t depth);
 	};
 	
 }
diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp
index 8ad4aa934be26207f8a0de5ef4c88ce45f6432f9..a6ec80085424a25a6f4285254253829fc5b59257 100644
--- a/src/vkcv/BufferManager.cpp
+++ b/src/vkcv/BufferManager.cpp
@@ -194,6 +194,18 @@ namespace vkcv {
 		return buffer.m_handle;
 	}
 	
+	size_t BufferManager::getBufferSize(const BufferHandle &handle) const {
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_buffers.size()) {
+			return 0;
+		}
+		
+		auto& buffer = m_buffers[id];
+		
+		return buffer.m_size;
+	}
+	
 	vk::DeviceMemory BufferManager::getDeviceMemory(const BufferHandle& handle) const {
 		const uint64_t id = handle.getId();
 		
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index f65f0f6f371e549aea3cac3269aebab7c82d5f3b..ecadba04f1230e6d0531851e862b44aca978bdb6 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -10,7 +10,7 @@
 #include "PassManager.hpp"
 #include "PipelineManager.hpp"
 #include "vkcv/BufferManager.hpp"
-#include "vkcv/ImageManager.hpp"
+#include "ImageManager.hpp"
 #include "DescriptorManager.hpp"
 #include "Surface.hpp"
 #include "ImageLayoutTransitions.hpp"
@@ -96,14 +96,14 @@ namespace vkcv
             m_PipelineManager{std::make_unique<PipelineManager>(m_Context.m_Device)},
             m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)),
 			m_BufferManager{std::unique_ptr<BufferManager>(new BufferManager())},
-			m_ImageManager{std::unique_ptr<ImageManager>(new ImageManager())},
+			m_ImageManager{std::unique_ptr<ImageManager>(new ImageManager(*m_BufferManager))},
             m_CommandResources(commandResources),
             m_SyncResources(syncResources)
 	{
     	m_BufferManager->m_core = this;
     	m_BufferManager->init();
-		m_ImageManager->m_core = this;
-		m_ImageManager->init(m_BufferManager.get());
+    	
+    	m_ImageManager->m_core = this;
 	}
 
 	Core::~Core() noexcept {
diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp
index 3ba5206d3dd7d1c300377e3ac1f51e8b5549258e..c4341b4f173028afa5dce98383b2ae34833ee2fa 100644
--- a/src/vkcv/Image.cpp
+++ b/src/vkcv/Image.cpp
@@ -4,13 +4,17 @@
  * @brief class for image handles
  */
 #include "vkcv/Image.hpp"
-#include "vkcv/ImageManager.hpp"
+#include "ImageManager.hpp"
 
 namespace vkcv{
 	
-	Image Image::create(ImageManager* manager, uint32_t width, uint32_t height)
+	Image Image::create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth)
 	{
-		return Image(manager, manager->createImage(width, height), width, height);
+		return Image(manager, manager->createImage(width, height, depth, format), format, width, height, depth);
+	}
+	
+	vk::Format Image::getFormat() const {
+		return m_format;
 	}
 	
 	uint32_t Image::getWidth() const {
@@ -21,21 +25,32 @@ namespace vkcv{
 		return m_height;
 	}
 	
+	uint32_t Image::getDepth() const {
+		return m_depth;
+	}
+	
 	vk::ImageLayout Image::getLayout() const {
 		return m_layout;
 	}
 
 	void Image::switchLayout(vk::ImageLayout newLayout)
 	{
-		m_manager->switchImageLayout(m_handle_id, m_layout, newLayout);
+		m_manager->switchImageLayout(m_handle, m_layout, newLayout);
 		m_layout = newLayout;
 	}
 	
-	Image::Image(ImageManager* manager, uint64_t id, uint32_t width, uint32_t height) :
+	void Image::fill(void *data, size_t size) {
+		m_manager->fillImage(m_handle, data, size);
+	}
+	
+	Image::Image(ImageManager* manager, const ImageHandle& handle,
+			  	 vk::Format format, uint32_t width, uint32_t height, uint32_t depth) :
 		m_manager(manager),
-		m_handle_id(id),
+		m_handle(handle),
+		m_format(format),
 		m_width(width),
 		m_height(height),
+		m_depth(depth),
 		m_layout(vk::ImageLayout::eUndefined)
 	{
 	}
diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp
index 7f06edc9bcb5244f00370af439f4143a7be4257b..188bbebd0ddc64dc0fad72a1bc93c2ed89fffeee 100644
--- a/src/vkcv/ImageManager.cpp
+++ b/src/vkcv/ImageManager.cpp
@@ -3,7 +3,7 @@
  * @file vkcv/ImageManager.cpp
  * @brief class creating and managing images
  */
-#include "vkcv/ImageManager.hpp"
+#include "ImageManager.hpp"
 #include "vkcv/Core.hpp"
 
 namespace vkcv {
@@ -33,34 +33,24 @@ namespace vkcv {
 		// failed to find memory type
 		return -1;
 	}
-	
-	void ImageManager::init(BufferManager* bufferManager)
-	{
-		if (!m_core) {
-			return;
-		}
-		uint64_t stagingID = bufferManager->createBuffer(BufferType::STAGING, 1024 * 1024, BufferMemoryType::HOST_VISIBLE);
-		m_stagingBuffer = bufferManager->m_buffers[stagingID].m_handle;
-	}
 
-	ImageManager::ImageManager() noexcept :
-		m_core(nullptr), m_images()
+	ImageManager::ImageManager(BufferManager& bufferManager) noexcept :
+		m_core(nullptr), m_bufferManager(bufferManager), m_images()
 	{
 	}
 
 	ImageManager::~ImageManager() noexcept {
-		for (size_t id = 0; id < m_images.size(); id++) {
-			destroyImage(id);
+		for (uint64_t id = 0; id < m_images.size(); id++) {
+			destroyImage(ImageHandle(id));
 		}
 	}
 
-	uint64_t ImageManager::createImage(uint32_t width, uint32_t height)
+	ImageHandle ImageManager::createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format)
 	{
 		vk::ImageCreateFlags createFlags;
 		vk::ImageUsageFlags imageUsageFlags = (vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst);
 		
-		vk::Format format = vk::Format::eR8G8B8A8Unorm; // TODO
-		uint32_t channels = 3; // TODO
+		format = vk::Format::eR8G8B8A8Unorm; // TODO
 
 		const vk::Device& device = m_core->getContext().getDevice();
 
@@ -96,11 +86,11 @@ namespace vkcv {
 		device.bindImageMemory(image, memory, 0);
 
 		const uint64_t id = m_images.size();
-		m_images.push_back({ image, memory, width * height * channels });
-		return id;
+		m_images.push_back({ image, memory, width, height, depth, format });
+		return ImageHandle(id);
 	}
 
-	void ImageManager::switchImageLayout(uint64_t id, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) {
+	void ImageManager::switchImageLayout(const ImageHandle& handle, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) {
 		//alternativly we could use switch case for every variable to set
 		vk::AccessFlags sourceAccessMask;
 		vk::PipelineStageFlags sourceStage;
@@ -125,14 +115,20 @@ namespace vkcv {
 		}
 		
 		vk::ImageSubresourceRange imageSubresourceRange(
-				vk::ImageAspectFlagBits::eColor ,
+				vk::ImageAspectFlagBits::eColor,
 				0,
 				1,
 				0,
 				1
 		);
 		
-		ImageManager::Image image = m_images[id];
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_images.size()) {
+			return;
+		}
+		
+		auto& image = m_images[id];
 		
 		vk::ImageMemoryBarrier imageMemoryBarrier(
 			sourceAccessMask,
@@ -163,121 +159,86 @@ namespace vkcv {
 			nullptr
 		);
 	}
-
-	struct ImageStagingStepInfo {
-		void* data;
-		size_t size;
-		uint32_t width;
-		uint32_t height;
-
-		vk::Image image;
-		vk::Buffer stagingBuffer;
-		vk::DeviceMemory stagingMemory;
-
-		size_t stagingLimit;
-		size_t stagingPosition;
-	};
-
-	void copyStagingToImage(Core* core, ImageStagingStepInfo info)
-	{
-		/*
-		* Alte implementation
-		vk::BufferImageCopy copyRegion(0, width, height);
-
-		SubmitInfo submitInfo;
-		submitInfo.queueType = QueueType::Transfer; //not sure
-		core->submitCommands(
-			submitInfo,
-			[buffer, image, copyRegion](const vk::CommandBuffer& commandBuffer) {
-				commandBuffer.copyBufferToImage(
-					buffer,
-					image, vk::ImageLayout::eTransferDstOptimal,
-					copyRegion
-				);
-			},
-			[]() {}
-			);
-		*/
-
-		const size_t remaining = info.size - info.stagingPosition;
-		const size_t mapped_size = std::min(remaining, info.stagingLimit);
-
-		const vk::Device& device = core->getContext().getDevice();
-
-		void* mapped = device.mapMemory(info.stagingMemory, 0, mapped_size);
-		memcpy(mapped, reinterpret_cast<char*>(info.data) + info.stagingPosition, mapped_size);
-		device.unmapMemory(info.stagingMemory);
-
-		SubmitInfo submitInfo;
-		submitInfo.queueType = QueueType::Transfer;
-
-		core->submitCommands(
-			submitInfo,
-			[&info, &mapped_size](const vk::CommandBuffer& commandBuffer) {
-				/*
-				const vk::BufferImageCopy region(
-					info.offset, //bufferOffset
-					info.size, //bufferRowlength
-					0, //bufferImageHeight
-					vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor,0,0,1),//soubresource layer
-					vk::Offset2D(info.offset,0), //imageoffset
-					vk::Extent3D(info.width,info.height,1) //extend3d
-				);
-				
-				commandBuffer.copyBufferToImage(
-					info.stagingBuffer,
-					info.image,
-					vk::ImageLayout::eTransferDstOptimal,
-					region);
-				*/
-			},
-			[&core, &info, &mapped_size, &remaining]() {
-				if (mapped_size < remaining) {
-					info.stagingPosition += mapped_size;
-
-					copyStagingToImage(
-						core,
-						info
-					);
-				}
-			}
-			);
-	}
-	void ImageManager::fillImage(uint64_t id, void* data, size_t size)
+	
+	void ImageManager::fillImage(const ImageHandle& handle, void* data, size_t size)
 	{
 		if (size == 0) {
 			size = SIZE_MAX;
 		}
 		
+		const uint64_t id = handle.getId();
+		
 		if (id >= m_images.size()) {
 			return;
 		}
 		
 		auto& image = m_images[id];
 		
-		switchImageLayout(id, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
+		switchImageLayout(
+				handle,
+				vk::ImageLayout::eUndefined,
+				vk::ImageLayout::eTransferDstOptimal
+		);
 		
-		const size_t max_size = std::min(size, image.m_size);
+		uint32_t channels = 3; // TODO
+		const size_t image_size = (
+				image.m_width * image.m_height * image.m_depth * channels * sizeof(char)
+		);
 		
-		//const size_t max_size = std::min(size, image.m_size - offset);
-		ImageStagingStepInfo info;
-		info.data = data;
-		info.size = max_size;
-
-		info.image = image.m_handle;
-		info.stagingBuffer = m_stagingBuffer;
-		info.stagingMemory = m_stagingMemory;
-
-		const vk::MemoryRequirements stagingRequirements = m_core->getContext().getDevice().getBufferMemoryRequirements(m_stagingBuffer);
-		info.stagingLimit = stagingRequirements.size; //TODO
-		info.stagingPosition = 0;
-
-		copyStagingToImage(m_core, info);
-		switchImageLayout(id, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
+		const size_t max_size = std::min(size, image_size);
+		
+		BufferHandle bufferHandle = m_bufferManager.createBuffer(
+				BufferType::STAGING, max_size, BufferMemoryType::HOST_VISIBLE
+		);
+		
+		m_bufferManager.fillBuffer(bufferHandle, data, max_size, 0);
+		
+		vk::Buffer stagingBuffer = m_bufferManager.getBuffer(bufferHandle);
+		
+		SubmitInfo submitInfo;
+		submitInfo.queueType = QueueType::Transfer;
+		
+		m_core->submitCommands(
+				submitInfo,
+				[&image, &stagingBuffer](const vk::CommandBuffer& commandBuffer) {
+					const vk::BufferImageCopy region (
+							0,
+							0,
+							0,
+							vk::ImageSubresourceLayers(
+									vk::ImageAspectFlagBits::eColor,
+									0,
+									0,
+									1
+							),
+							vk::Offset3D(0, 0, 0),
+							vk::Extent3D(image.m_width, image.m_height, image.m_depth)
+					);
+					
+					commandBuffer.copyBufferToImage(
+							stagingBuffer,
+							image.m_handle,
+							vk::ImageLayout::eTransferDstOptimal,
+							1,
+							&region
+					);
+				},
+				[&]() {
+					switchImageLayout(
+							handle,
+							vk::ImageLayout::eTransferDstOptimal,
+							vk::ImageLayout::eShaderReadOnlyOptimal
+					);
+					
+					m_bufferManager.destroyBuffer(bufferHandle);
+				}
+		);
 	}
 
-	void ImageManager::destroyImage(uint64_t id)
+	void ImageManager::destroyImage(const ImageHandle& handle)
 	{
+		const uint64_t id = handle.getId();
+		
 		if (id >= m_images.size()) {
 			return;
 		}
diff --git a/include/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp
similarity index 52%
rename from include/vkcv/ImageManager.hpp
rename to src/vkcv/ImageManager.hpp
index dc38ef08e107d4823b24bb091e4b90df8cd74954..22a4301977392876e520cecc6ccbfd7982cb3d59 100644
--- a/include/vkcv/ImageManager.hpp
+++ b/src/vkcv/ImageManager.hpp
@@ -7,9 +7,11 @@
 #include <vector>
 #include <vulkan/vulkan.hpp>
 
+#include "vkcv/BufferManager.hpp"
+#include "vkcv/Handles.hpp"
+
 namespace vkcv {
-	class Core;
-	class BufferManager;
+	
 	class ImageManager
 	{
 		friend class Core;
@@ -18,16 +20,19 @@ namespace vkcv {
 		{
 			vk::Image m_handle;
 			vk::DeviceMemory m_memory;
-			size_t m_size;
+			uint32_t m_width = 0;
+			uint32_t m_height = 0;
+			uint32_t m_depth = 0;
+			vk::Format m_format;
 		};
 		
 		Core* m_core;
-		vk::Buffer m_stagingBuffer;
-		vk::DeviceMemory m_stagingMemory;
-
+		BufferManager& m_bufferManager;
+		
 		std::vector<Image> m_images;
-		void init(BufferManager* bufferManager);
-		ImageManager() noexcept;
+		
+		ImageManager(BufferManager& bufferManager) noexcept;
+		
 	public:
 		~ImageManager() noexcept;
 		ImageManager(ImageManager&& other) = delete;
@@ -36,17 +41,18 @@ namespace vkcv {
 		ImageManager& operator=(ImageManager&& other) = delete;
 		ImageManager& operator=(const ImageManager& other) = delete;
 		
-		void switchImageLayout(uint64_t id, vk::ImageLayout oldLayout, vk::ImageLayout newLayout);
-		void fillImage(uint64_t id, void* data, size_t size);
+		void switchImageLayout(const ImageHandle& handle, vk::ImageLayout oldLayout, vk::ImageLayout newLayout);
+		void fillImage(const ImageHandle& handle, void* data, size_t size);
 
-		uint64_t createImage(uint32_t width, uint32_t height);
+		ImageHandle createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format);
 
 		/**
 		 * Destroys and deallocates image represented by a given
-		 * buffer handle id.
+		 * buffer handle.
 		 *
-		 * @param id Buffer handle id
+		 * @param handle Image handle
 		 */
-		void destroyImage(uint64_t id);
+		void destroyImage(const ImageHandle& handle);
+		
 	};
 }
\ No newline at end of file