//==============================================================================
void TextureResource::loadInternal(const CString& filename, 
	ResourceInitializer& rinit)
{
	GlDevice& gl = rinit.m_resources._getGlDevice();
	GlCommandBufferHandle cmdb;
	cmdb.create(&gl); // Always first to avoid assertions (
	                  // because of the check of the allocator)

	GlTextureHandle::Initializer init;
	U layers = 0;
	Bool driverShouldGenMipmaps = false;

	// Load image
	Image* imgPtr = rinit.m_alloc.newInstance<Image>(rinit.m_alloc);
	Image& img = *imgPtr;
	img.load(filename, rinit.m_resources.getMaxTextureSize());
	
	// width + height
	init.m_width = img.getSurface(0, 0).m_width;
	init.m_height = img.getSurface(0, 0).m_height;
	
	// depth
	if(img.getTextureType() == Image::TextureType::_2D_ARRAY 
		|| img.getTextureType() == Image::TextureType::_3D)
	{
		init.m_depth = img.getDepth();
	}
	else
	{
		init.m_depth = 0;
	}

	// target
	switch(img.getTextureType())
	{
	case Image::TextureType::_2D:
		init.m_target = GL_TEXTURE_2D;
		layers = 1;
		break;
	case Image::TextureType::CUBE:
		init.m_target = GL_TEXTURE_CUBE_MAP;
		layers = 6;
		break;
	case Image::TextureType::_2D_ARRAY:
		init.m_target = GL_TEXTURE_2D_ARRAY;
		layers = init.m_depth;
		break;
	case Image::TextureType::_3D:
		init.m_target = GL_TEXTURE_3D;
		layers = init.m_depth;
	default:
		ANKI_ASSERT(0);
	}

	// Internal format
	if(img.getColorFormat() == Image::ColorFormat::RGB8)
	{
		switch(img.getCompression())
		{
		case Image::DataCompression::RAW:
#if DRIVER_CAN_COMPRESS
			init.m_internalFormat = GL_COMPRESSED_RGB;
#else
			init.m_internalFormat = GL_RGB;
#endif
			driverShouldGenMipmaps = true;
			break;
#if ANKI_GL == ANKI_GL_DESKTOP
		case Image::DataCompression::S3TC:
			init.m_internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
			break;
#else
		case Image::DataCompression::ETC:
			init.m_internalFormat = GL_COMPRESSED_RGB8_ETC2;
			break;
#endif
		default:
			ANKI_ASSERT(0);
		}
	}
	else if(img.getColorFormat() == Image::ColorFormat::RGBA8)
	{
		switch(img.getCompression())
		{
		case Image::DataCompression::RAW:
#if DRIVER_CAN_COMPRESS
			init.m_internalFormat = GL_COMPRESSED_RGBA;
#else
			init.m_internalFormat = GL_RGBA;
#endif
			driverShouldGenMipmaps = true;
			break;
#if ANKI_GL == ANKI_GL_DESKTOP
		case Image::DataCompression::S3TC:
			init.m_internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
			break;
#else
		case Image::DataCompression::ETC:
			init.m_internalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC;
			break;
#endif
		default:
			ANKI_ASSERT(0);
		}
	}
	else
	{
		ANKI_ASSERT(0);
	}

	// format
	switch(img.getColorFormat())
	{
	case Image::ColorFormat::RGB8:
		init.m_format = GL_RGB;
		break;
	case Image::ColorFormat::RGBA8:
		init.m_format = GL_RGBA;
		break;
	default:
		ANKI_ASSERT(0);
	}

	// type
	init.m_type = GL_UNSIGNED_BYTE;

	// mipmapsCount
	init.m_mipmapsCount = img.getMipLevelsCount();

	// filteringType
	init.m_filterType = GlTextureHandle::Filter::TRILINEAR;

	// repeat
	init.m_repeat = true;

	// anisotropyLevel
	init.m_anisotropyLevel = rinit.m_resources.getTextureAnisotropy();

	// genMipmaps
	if(init.m_mipmapsCount == 1 || driverShouldGenMipmaps)
	{
		init.m_genMipmaps = true;
	}
	else
	{
		init.m_genMipmaps = false;
	}

	// Now assign the data
	for(U layer = 0; layer < layers; layer++)
	{
		for(U level = 0; level < init.m_mipmapsCount; level++)
		{
			GlClientBufferHandle& buff = init.m_data[level][layer];

			buff.create(
				cmdb, 
				img.getSurface(level, layer).m_data.size(), 
				(void*)&img.getSurface(level, layer).m_data[0]);
		}
	}

	// Add the GL job to create the texture
	m_tex.create(cmdb, init);

	// Add cleanup job
	cmdb.pushBackUserCommand(deleteImageCallback, imgPtr);

	// Finaly enque the GL job chain
	cmdb.flush();

	m_size = UVec3(init.m_width, init.m_height, init.m_depth);
}
//==============================================================================
Error TextureResource::load(const ResourceFilename& filename)
{
	TextureInitInfo init;
	U depth = 0;
	U faces = 0;

	// Load image
	TexUploadTask* task = getManager().getAsyncLoader().newTask<TexUploadTask>(
		getManager().getAsyncLoader().getAllocator());
	ImageLoader& loader = task->m_loader;

	ResourceFilePtr file;
	ANKI_CHECK(openFile(filename, file));

	ANKI_CHECK(loader.load(file, filename, getManager().getMaxTextureSize()));

	// width + height
	const auto& tmpSurf = loader.getSurface(0, 0);
	init.m_width = tmpSurf.m_width;
	init.m_height = tmpSurf.m_height;

	// depth
	if(loader.getTextureType() == ImageLoader::TextureType::_2D_ARRAY
		|| loader.getTextureType() == ImageLoader::TextureType::_3D)
	{
		init.m_depth = loader.getDepth();
	}
	else
	{
		init.m_depth = 1;
	}

	// target
	switch(loader.getTextureType())
	{
	case ImageLoader::TextureType::_2D:
		init.m_type = TextureType::_2D;
		depth = 1;
		faces = 1;
		break;
	case ImageLoader::TextureType::CUBE:
		init.m_type = TextureType::CUBE;
		depth = 1;
		faces = 6;
		break;
	case ImageLoader::TextureType::_2D_ARRAY:
		init.m_type = TextureType::_2D_ARRAY;
		depth = init.m_depth;
		faces = 1;
		break;
	case ImageLoader::TextureType::_3D:
		init.m_type = TextureType::_3D;
		depth = init.m_depth;
		faces = 1;
		break;
	default:
		ANKI_ASSERT(0);
	}

	// Internal format
	init.m_format.m_transform = TransformFormat::UNORM;
	init.m_format.m_srgb = false;

	if(loader.getColorFormat() == ImageLoader::ColorFormat::RGB8)
	{
		switch(loader.getCompression())
		{
		case ImageLoader::DataCompression::RAW:
			init.m_format.m_components = ComponentFormat::R8G8B8;
			break;
#if ANKI_GL == ANKI_GL_DESKTOP
		case ImageLoader::DataCompression::S3TC:
			init.m_format.m_components = ComponentFormat::R8G8B8_S3TC;
			break;
#else
		case ImageLoader::DataCompression::ETC:
			init.m_format.m_components = ComponentFormat::R8G8B8_ETC2;
			break;
#endif
		default:
			ANKI_ASSERT(0);
		}
	}
	else if(loader.getColorFormat() == ImageLoader::ColorFormat::RGBA8)
	{
		switch(loader.getCompression())
		{
		case ImageLoader::DataCompression::RAW:
			init.m_format.m_components = ComponentFormat::R8G8B8A8;
			break;
#if ANKI_GL == ANKI_GL_DESKTOP
		case ImageLoader::DataCompression::S3TC:
			init.m_format.m_components = ComponentFormat::R8G8B8A8_S3TC;
			break;
#else
		case ImageLoader::DataCompression::ETC:
			init.m_format.m_components = ComponentFormat::R8G8B8A8_ETC2;
			break;
#endif
		default:
			ANKI_ASSERT(0);
		}
	}
	else
	{
		ANKI_ASSERT(0);
	}

	// mipmapsCount
	init.m_mipmapsCount = loader.getMipLevelsCount();

	// filteringType
	init.m_sampling.m_minMagFilter = SamplingFilter::LINEAR;
	init.m_sampling.m_mipmapFilter = SamplingFilter::LINEAR;

	// repeat
	init.m_sampling.m_repeat = true;

	// anisotropyLevel
	init.m_sampling.m_anisotropyLevel = getManager().getTextureAnisotropy();

	// Create the texture
	m_tex = getManager().getGrManager().newInstance<Texture>(init);

	// Upload the data asynchronously
	task->m_depth = depth;
	task->m_faces = faces;
	task->m_gr = &getManager().getGrManager();
	task->m_tex = m_tex;

	getManager().getAsyncLoader().submitTask(task);

	// Done
	m_size = UVec3(init.m_width, init.m_height, init.m_depth);
	return ErrorCode::NONE;
}