#pragma once

#include <psemek/gfx/texture.hpp>
#include <psemek/math/box.hpp>

#include <cstdint>

namespace psemek::gfx
{

	template <std::size_t D, GLenum Target>
	struct basic_texture_view
	{
		basic_texture<D, Target> const * texture = nullptr;
		math::box<float, D> part; // in pixels

		basic_texture_view(basic_texture<D, Target> const * texture = nullptr);
		basic_texture_view(basic_texture<D, Target> const * texture, math::box<float, D> const & part);

		math::vector<float, D> size() const { return part.dimensions(); }

		float width() const
		{
			return part[0].length();
		}

		float height() const
		{
			if constexpr (D >= 2)
				return part[1].length();
			else
				return 1;
		}

		float depth() const
		{
			if constexpr (D >= 3)
				return part[2].length();
			else
				return 1;
		}

		explicit operator bool() const { return texture != nullptr; }
	};

	template <std::size_t D, GLenum Target>
	basic_texture_view<D, Target>::basic_texture_view(basic_texture<D, Target> const * texture)
		: texture(texture)
	{
		if (texture)
		{
			static const auto zero = math::point<float, D>::zero();
			part = math::span(zero, zero + math::cast<float>(texture->size()));
		}
	}

	template <std::size_t D, GLenum Target>
	basic_texture_view<D, Target>::basic_texture_view(basic_texture<D, Target> const * texture, math::box<float, D> const & part)
		: texture(texture)
		, part(part)
	{}

	using texture_view_1d       = basic_texture_view<1, gl::TEXTURE_1D>;
	using texture_view_1d_array = basic_texture_view<2, gl::TEXTURE_1D_ARRAY>;
	using texture_view_2d       = basic_texture_view<2, gl::TEXTURE_2D>;
	using texture_view_2d_array = basic_texture_view<3, gl::TEXTURE_2D_ARRAY>;
	using texture_view_3d       = basic_texture_view<3, gl::TEXTURE_3D>;

}
