You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							324 lines
						
					
					
						
							11 KiB
						
					
					
				
			
		
		
	
	
							324 lines
						
					
					
						
							11 KiB
						
					
					
				| #include "../dx.hpp" | |
| #include "file.hpp" | |
| #include <cstdio> | |
| #include <cassert> | |
|  | |
| namespace gli{ | |
| namespace detail | |
| { | |
| 	static char const FOURCC_DDS[] = {'D', 'D', 'S', ' '}; | |
| 
 | |
| 	enum dds_cubemap_flag | |
| 	{ | |
| 		DDSCAPS2_CUBEMAP				= 0x00000200, | |
| 		DDSCAPS2_CUBEMAP_POSITIVEX		= 0x00000400, | |
| 		DDSCAPS2_CUBEMAP_NEGATIVEX		= 0x00000800, | |
| 		DDSCAPS2_CUBEMAP_POSITIVEY		= 0x00001000, | |
| 		DDSCAPS2_CUBEMAP_NEGATIVEY		= 0x00002000, | |
| 		DDSCAPS2_CUBEMAP_POSITIVEZ		= 0x00004000, | |
| 		DDSCAPS2_CUBEMAP_NEGATIVEZ		= 0x00008000, | |
| 		DDSCAPS2_VOLUME					= 0x00200000 | |
| 	}; | |
| 
 | |
| 	enum | |
| 	{ | |
| 		DDSCAPS2_CUBEMAP_ALLFACES = DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_NEGATIVEX | DDSCAPS2_CUBEMAP_POSITIVEY | DDSCAPS2_CUBEMAP_NEGATIVEY | DDSCAPS2_CUBEMAP_POSITIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEZ | |
| 	}; | |
| 
 | |
| 	enum dds_flag | |
| 	{ | |
| 		DDSD_CAPS			= 0x00000001, | |
| 		DDSD_HEIGHT			= 0x00000002, | |
| 		DDSD_WIDTH			= 0x00000004, | |
| 		DDSD_PITCH			= 0x00000008, | |
| 		DDSD_PIXELFORMAT	= 0x00001000, | |
| 		DDSD_MIPMAPCOUNT	= 0x00020000, | |
| 		DDSD_LINEARSIZE		= 0x00080000, | |
| 		DDSD_DEPTH			= 0x00800000 | |
| 	}; | |
| 
 | |
| 	enum dds_surface_flag | |
| 	{ | |
| 		DDSCAPS_COMPLEX				= 0x00000008, | |
| 		DDSCAPS_MIPMAP				= 0x00400000, | |
| 		DDSCAPS_TEXTURE				= 0x00001000 | |
| 	}; | |
| 
 | |
| 	struct dds_pixel_format | |
| 	{ | |
| 		std::uint32_t size; // 32 | |
| 		dx::ddpf flags; | |
| 		dx::d3dfmt fourCC; | |
| 		std::uint32_t bpp; | |
| 		glm::u32vec4 Mask; | |
| 	}; | |
| 
 | |
| 	struct dds_header | |
| 	{ | |
| 		std::uint32_t Size; | |
| 		std::uint32_t Flags; | |
| 		std::uint32_t Height; | |
| 		std::uint32_t Width; | |
| 		std::uint32_t Pitch; | |
| 		std::uint32_t Depth; | |
| 		std::uint32_t MipMapLevels; | |
| 		std::uint32_t Reserved1[11]; | |
| 		dds_pixel_format Format; | |
| 		std::uint32_t SurfaceFlags; | |
| 		std::uint32_t CubemapFlags; | |
| 		std::uint32_t Reserved2[3]; | |
| 	}; | |
| 
 | |
| 	static_assert(sizeof(dds_header) == 124, "DDS Header size mismatch"); | |
| 
 | |
| 	enum d3d10_resource_dimension | |
| 	{ | |
| 		D3D10_RESOURCE_DIMENSION_UNKNOWN     = 0, | |
| 		D3D10_RESOURCE_DIMENSION_BUFFER      = 1, | |
| 		D3D10_RESOURCE_DIMENSION_TEXTURE1D   = 2, | |
| 		D3D10_RESOURCE_DIMENSION_TEXTURE2D   = 3, | |
| 		D3D10_RESOURCE_DIMENSION_TEXTURE3D   = 4  | |
| 	}; | |
| 
 | |
| 	enum d3d10_resource_misc_flag | |
| 	{ | |
| 		D3D10_RESOURCE_MISC_GENERATE_MIPS		= 0x01, | |
| 		D3D10_RESOURCE_MISC_SHARED				= 0x02, | |
| 		D3D10_RESOURCE_MISC_TEXTURECUBE			= 0x04, | |
| 		D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX	= 0x10, | |
| 		D3D10_RESOURCE_MISC_GDI_COMPATIBLE		= 0x20, | |
| 	}; | |
| 
 | |
| 	enum dds_alpha_mode | |
| 	{ | |
| 		DDS_ALPHA_MODE_UNKNOWN					= 0x0, | |
| 		DDS_ALPHA_MODE_STRAIGHT					= 0x1, | |
| 		DDS_ALPHA_MODE_PREMULTIPLIED			= 0x2, | |
| 		DDS_ALPHA_MODE_OPAQUE					= 0x3, | |
| 		DDS_ALPHA_MODE_CUSTOM					= 0x4 | |
| 	}; | |
| 
 | |
| 	struct dds_header10 | |
| 	{ | |
| 		dds_header10() : | |
| 			Format(dx::DXGI_FORMAT_UNKNOWN), | |
| 			ResourceDimension(D3D10_RESOURCE_DIMENSION_UNKNOWN), | |
| 			MiscFlag(0), | |
| 			ArraySize(0), | |
| 			AlphaFlags(DDS_ALPHA_MODE_UNKNOWN) | |
| 		{} | |
| 
 | |
| 		dx::dxgiFormat				Format; | |
| 		d3d10_resource_dimension	ResourceDimension; | |
| 		std::uint32_t				MiscFlag; // D3D10_RESOURCE_MISC_GENERATE_MIPS | |
| 		std::uint32_t				ArraySize; | |
| 		dds_alpha_mode				AlphaFlags; // Should be 0 whenever possible to avoid D3D utility library to fail | |
| 	}; | |
| 
 | |
| 	static_assert(sizeof(dds_header10) == 20, "DDS DX10 Extended Header size mismatch"); | |
| 
 | |
| 	inline target get_target(dds_header const& Header, dds_header10 const& Header10) | |
| 	{ | |
| 		if(Header.CubemapFlags & detail::DDSCAPS2_CUBEMAP) | |
| 		{ | |
| 			if(Header10.ArraySize > 1) | |
| 				return TARGET_CUBE_ARRAY; | |
| 			else | |
| 				return TARGET_CUBE; | |
| 		} | |
| 		else if(Header10.ArraySize > 1) | |
| 		{ | |
| 			if(Header.Flags & detail::DDSD_HEIGHT) | |
| 				return TARGET_2D_ARRAY; | |
| 			else | |
| 				return TARGET_1D_ARRAY; | |
| 		} | |
| 		else if(Header10.ResourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE1D) | |
| 			return TARGET_1D; | |
| 		else if(Header10.ResourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE3D || Header.Flags & detail::DDSD_DEPTH || Header.CubemapFlags & detail::DDSCAPS2_VOLUME) | |
| 			return TARGET_3D; | |
| 		else | |
| 			return TARGET_2D; | |
| 	} | |
| 
 | |
| 	// Some formats have multiple fourcc values. This function allows remapping to the default fourcc value of a format | |
| 	inline dx::d3dfmt remap_four_cc(dx::d3dfmt FourCC) | |
| 	{ | |
| 		switch(FourCC) | |
| 		{ | |
| 		default: | |
| 			return FourCC; | |
| 		case dx::D3DFMT_BC4U: | |
| 			return dx::D3DFMT_ATI1; | |
| 		case dx::D3DFMT_BC4S: | |
| 			return dx::D3DFMT_AT1N; | |
| 		case dx::D3DFMT_BC5U: | |
| 			return dx::D3DFMT_ATI2; | |
| 		case dx::D3DFMT_BC5S: | |
| 			return dx::D3DFMT_AT2N; | |
| 		} | |
| 	} | |
| }//namespace detail | |
|  | |
| 	inline texture load_dds(char const * Data, std::size_t Size) | |
| 	{ | |
| 		GLI_ASSERT(Data && (Size >= sizeof(detail::FOURCC_DDS))); | |
| 
 | |
| 		if(strncmp(Data, detail::FOURCC_DDS, 4) != 0) | |
| 			return texture(); | |
| 		std::size_t Offset = sizeof(detail::FOURCC_DDS); | |
| 
 | |
| 		GLI_ASSERT(Size >= sizeof(detail::dds_header)); | |
| 
 | |
| 		detail::dds_header const & Header(*reinterpret_cast<detail::dds_header const *>(Data + Offset)); | |
| 		Offset += sizeof(detail::dds_header); | |
| 
 | |
| 		detail::dds_header10 Header10; | |
| 		if((Header.Format.flags & dx::DDPF_FOURCC) && (Header.Format.fourCC == dx::D3DFMT_DX10 || Header.Format.fourCC == dx::D3DFMT_GLI1)) | |
| 		{ | |
| 			std::memcpy(&Header10, Data + Offset, sizeof(Header10)); | |
| 			Offset += sizeof(detail::dds_header10); | |
| 		} | |
| 
 | |
| 		dx DX; | |
| 
 | |
| 		gli::format Format(static_cast<gli::format>(gli::FORMAT_INVALID)); | |
| 		if((Header.Format.flags & (dx::DDPF_RGB | dx::DDPF_ALPHAPIXELS | dx::DDPF_ALPHA | dx::DDPF_YUV | dx::DDPF_LUMINANCE)) && Format == static_cast<format>(gli::FORMAT_INVALID) && Header.Format.bpp != 0) | |
| 		{ | |
| 			switch(Header.Format.bpp) | |
| 			{ | |
| 				default: | |
| 					GLI_ASSERT(0); | |
| 					break; | |
| 				case 8: | |
| 				{ | |
| 					if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RG4_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_RG4_UNORM_PACK8; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_L8_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_L8_UNORM_PACK8; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_A8_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_A8_UNORM_PACK8; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_R8_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_R8_UNORM_PACK8; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RG3B2_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_RG3B2_UNORM_PACK8; | |
| 					else | |
| 						GLI_ASSERT(0); | |
| 					break; | |
| 				} | |
| 				case 16: | |
| 				{ | |
| 					if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGBA4_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_RGBA4_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGRA4_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_BGRA4_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_R5G6B5_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_R5G6B5_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_B5G6R5_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_B5G6R5_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGB5A1_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_RGB5A1_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGR5A1_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_BGR5A1_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_LA8_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_LA8_UNORM_PACK8; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RG8_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_RG8_UNORM_PACK8; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_L16_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_L16_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_A16_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_A16_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_R16_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_R16_UNORM_PACK16; | |
| 					else | |
| 						GLI_ASSERT(0); | |
| 					break; | |
| 				} | |
| 				case 24: | |
| 				{ | |
| 					if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGB8_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_RGB8_UNORM_PACK8; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGR8_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_BGR8_UNORM_PACK8; | |
| 					else | |
| 						GLI_ASSERT(0); | |
| 					break; | |
| 				} | |
| 				case 32: | |
| 				{ | |
| 					if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGR8_UNORM_PACK32).Mask))) | |
| 						Format = FORMAT_BGR8_UNORM_PACK32; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGRA8_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_BGRA8_UNORM_PACK8; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGBA8_UNORM_PACK8).Mask))) | |
| 						Format = FORMAT_RGBA8_UNORM_PACK8; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGB10A2_UNORM_PACK32).Mask))) | |
| 						Format = FORMAT_RGB10A2_UNORM_PACK32; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_LA16_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_LA16_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RG16_UNORM_PACK16).Mask))) | |
| 						Format = FORMAT_RG16_UNORM_PACK16; | |
| 					else if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_R32_SFLOAT_PACK32).Mask))) | |
| 						Format = FORMAT_R32_SFLOAT_PACK32; | |
| 					else | |
| 						GLI_ASSERT(0); | |
| 					break; | |
| 				} | |
| 			} | |
| 		} | |
| 		else if((Header.Format.flags & dx::DDPF_FOURCC) && (Header.Format.fourCC != dx::D3DFMT_DX10) && (Header.Format.fourCC != dx::D3DFMT_GLI1) && (Format == static_cast<format>(gli::FORMAT_INVALID))) | |
| 		{ | |
| 			dx::d3dfmt const FourCC = detail::remap_four_cc(Header.Format.fourCC); | |
| 			Format = DX.find(FourCC); | |
| 		} | |
| 		else if(Header.Format.fourCC == dx::D3DFMT_DX10 || Header.Format.fourCC == dx::D3DFMT_GLI1) | |
| 			Format = DX.find(Header.Format.fourCC, Header10.Format); | |
| 
 | |
| 		GLI_ASSERT(Format != static_cast<format>(gli::FORMAT_INVALID)); | |
| 
 | |
| 		size_t const MipMapCount = (Header.Flags & detail::DDSD_MIPMAPCOUNT) ? Header.MipMapLevels : 1; | |
| 		size_t FaceCount = 1; | |
| 		if(Header.CubemapFlags & detail::DDSCAPS2_CUBEMAP) | |
| 			FaceCount = int(glm::bitCount(Header.CubemapFlags & detail::DDSCAPS2_CUBEMAP_ALLFACES)); | |
| 
 | |
| 		size_t DepthCount = 1; | |
| 		if(Header.CubemapFlags & detail::DDSCAPS2_VOLUME) | |
| 			DepthCount = Header.Depth; | |
| 
 | |
| 		texture Texture( | |
| 			get_target(Header, Header10), Format, | |
| 			texture::extent_type(Header.Width, Header.Height, DepthCount), | |
| 			std::max<texture::size_type>(Header10.ArraySize, 1), FaceCount, MipMapCount); | |
| 
 | |
| 		std::size_t const SourceSize = Offset + Texture.size(); | |
| 		GLI_ASSERT(SourceSize == Size); | |
| 
 | |
| 		std::memcpy(Texture.data(), Data + Offset, Texture.size()); | |
| 
 | |
| 		return Texture; | |
| 	} | |
| 
 | |
| 	inline texture load_dds(char const * Filename) | |
| 	{ | |
| 		FILE* File = detail::open_file(Filename, "rb"); | |
| 		if(!File) | |
| 			return texture(); | |
| 
 | |
| 		long Beg = std::ftell(File); | |
| 		std::fseek(File, 0, SEEK_END); | |
| 		long End = std::ftell(File); | |
| 		std::fseek(File, 0, SEEK_SET); | |
| 
 | |
| 		std::vector<char> Data(static_cast<std::size_t>(End - Beg)); | |
| 
 | |
| 		std::fread(&Data[0], 1, Data.size(), File); | |
| 		std::fclose(File); | |
| 
 | |
| 		return load_dds(&Data[0], Data.size()); | |
| 	} | |
| 
 | |
| 	inline texture load_dds(std::string const & Filename) | |
| 	{ | |
| 		return load_dds(Filename.c_str()); | |
| 	} | |
| }//namespace gli
 | |
| 
 |