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.
		
		
		
		
		
			
		
			
				
					
					
						
							137 lines
						
					
					
						
							3.8 KiB
						
					
					
				
			
		
		
	
	
							137 lines
						
					
					
						
							3.8 KiB
						
					
					
				#include "../gl.hpp" | 
						|
#include "file.hpp" | 
						|
#include <cstdio> | 
						|
#include <cassert> | 
						|
 | 
						|
namespace gli{ | 
						|
namespace detail | 
						|
{ | 
						|
	static unsigned char const FOURCC_KTX10[] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}; | 
						|
	static unsigned char const FOURCC_KTX20[] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}; | 
						|
 | 
						|
	struct ktx_header10 | 
						|
	{ | 
						|
		std::uint32_t Endianness; | 
						|
		std::uint32_t GLType; | 
						|
		std::uint32_t GLTypeSize; | 
						|
		std::uint32_t GLFormat; | 
						|
		std::uint32_t GLInternalFormat; | 
						|
		std::uint32_t GLBaseInternalFormat; | 
						|
		std::uint32_t PixelWidth; | 
						|
		std::uint32_t PixelHeight; | 
						|
		std::uint32_t PixelDepth; | 
						|
		std::uint32_t NumberOfArrayElements; | 
						|
		std::uint32_t NumberOfFaces; | 
						|
		std::uint32_t NumberOfMipmapLevels; | 
						|
		std::uint32_t BytesOfKeyValueData; | 
						|
	}; | 
						|
 | 
						|
	inline target get_target(ktx_header10 const& Header) | 
						|
	{ | 
						|
		if(Header.NumberOfFaces > 1) | 
						|
		{ | 
						|
			if(Header.NumberOfArrayElements > 0) | 
						|
				return TARGET_CUBE_ARRAY; | 
						|
			else | 
						|
				return TARGET_CUBE; | 
						|
		} | 
						|
		else if(Header.NumberOfArrayElements > 0) | 
						|
		{ | 
						|
			if(Header.PixelHeight == 0) | 
						|
				return TARGET_1D_ARRAY; | 
						|
			else | 
						|
				return TARGET_2D_ARRAY; | 
						|
		} | 
						|
		else if(Header.PixelHeight == 0) | 
						|
			return TARGET_1D; | 
						|
		else if(Header.PixelDepth > 0) | 
						|
			return TARGET_3D; | 
						|
		else | 
						|
			return TARGET_2D; | 
						|
	} | 
						|
 | 
						|
	inline texture load_ktx10(char const* Data, std::size_t Size) | 
						|
	{ | 
						|
		detail::ktx_header10 const & Header(*reinterpret_cast<detail::ktx_header10 const*>(Data)); | 
						|
 | 
						|
		size_t Offset = sizeof(detail::ktx_header10); | 
						|
 | 
						|
		// Skip key value data | 
						|
		Offset += Header.BytesOfKeyValueData; | 
						|
 | 
						|
		gl GL(gl::PROFILE_KTX); | 
						|
		gli::format const Format = GL.find( | 
						|
			static_cast<gli::gl::internal_format>(Header.GLInternalFormat), | 
						|
			static_cast<gli::gl::external_format>(Header.GLFormat), | 
						|
			static_cast<gli::gl::type_format>(Header.GLType)); | 
						|
		GLI_ASSERT(Format != static_cast<format>(gli::FORMAT_INVALID)); | 
						|
		 | 
						|
		texture::size_type const BlockSize = block_size(Format); | 
						|
 | 
						|
		texture Texture( | 
						|
			detail::get_target(Header), | 
						|
			Format, | 
						|
			texture::extent_type( | 
						|
				Header.PixelWidth, | 
						|
				std::max<texture::size_type>(Header.PixelHeight, 1), | 
						|
				std::max<texture::size_type>(Header.PixelDepth, 1)), | 
						|
			std::max<texture::size_type>(Header.NumberOfArrayElements, 1), | 
						|
			std::max<texture::size_type>(Header.NumberOfFaces, 1), | 
						|
			std::max<texture::size_type>(Header.NumberOfMipmapLevels, 1)); | 
						|
 | 
						|
		for(texture::size_type Level = 0, Levels = Texture.levels(); Level < Levels; ++Level) | 
						|
		{ | 
						|
			Offset += sizeof(std::uint32_t); | 
						|
 | 
						|
			for(texture::size_type Layer = 0, Layers = Texture.layers(); Layer < Layers; ++Layer) | 
						|
			for(texture::size_type Face = 0, Faces = Texture.faces(); Face < Faces; ++Face) | 
						|
			{ | 
						|
				texture::size_type const FaceSize = Texture.size(Level); | 
						|
 | 
						|
				std::memcpy(Texture.data(Layer, Face, Level), Data + Offset, FaceSize); | 
						|
 | 
						|
				Offset += std::max(BlockSize, glm::ceilMultiple(FaceSize, static_cast<texture::size_type>(4))); | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		return Texture; | 
						|
	} | 
						|
}//namespace detail | 
						|
 | 
						|
	inline texture load_ktx(char const* Data, std::size_t Size) | 
						|
	{ | 
						|
		GLI_ASSERT(Data && (Size >= sizeof(detail::ktx_header10))); | 
						|
 | 
						|
		// KTX10 | 
						|
		{ | 
						|
			if(memcmp(Data, detail::FOURCC_KTX10, sizeof(detail::FOURCC_KTX10)) == 0) | 
						|
				return detail::load_ktx10(Data + sizeof(detail::FOURCC_KTX10), Size - sizeof(detail::FOURCC_KTX10)); | 
						|
		} | 
						|
 | 
						|
		return texture(); | 
						|
	} | 
						|
 | 
						|
	inline texture load_ktx(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_ktx(&Data[0], Data.size()); | 
						|
	} | 
						|
 | 
						|
	inline texture load_ktx(std::string const& Filename) | 
						|
	{ | 
						|
		return load_ktx(Filename.c_str()); | 
						|
	} | 
						|
}//namespace gli
 | 
						|
 |