#include <psemek/wgpu/render_pass_encoder.hpp>
#include <psemek/wgpu/detail/string_view.hpp>
#include <psemek/wgpu/external/webgpu.h>
#include <psemek/wgpu/external/wgpu.h>

namespace psemek::wgpu
{

	void render_pass_encoder::set_pipeline(render_pipeline const & pipeline)
	{
		wgpuRenderPassEncoderSetPipeline((WGPURenderPassEncoder)get(), (WGPURenderPipeline)pipeline.get());
	}

	void render_pass_encoder::set_bind_group(std::uint32_t group_index, bind_group const & group, std::vector<std::uint32_t> const & dynamic_offsets)
	{
		wgpuRenderPassEncoderSetBindGroup((WGPURenderPassEncoder)get(), group_index, (WGPUBindGroup)group.get(), dynamic_offsets.size(), dynamic_offsets.data());
	}

	void render_pass_encoder::set_vertex_buffer(std::uint32_t slot, buffer const & buffer, std::uint64_t offset, std::uint64_t size)
	{
		wgpuRenderPassEncoderSetVertexBuffer((WGPURenderPassEncoder)get(), slot, (WGPUBuffer)buffer.get(), offset, size);
	}

	void render_pass_encoder::set_index_buffer(buffer const & buffer, index_format format, std::uint64_t offset, std::uint64_t size)
	{
		wgpuRenderPassEncoderSetIndexBuffer((WGPURenderPassEncoder)get(), (WGPUBuffer)buffer.get(), (WGPUIndexFormat)format, offset, size);
	}

	void render_pass_encoder::set_viewport(math::box<float, 3> const & viewport)
	{
		wgpuRenderPassEncoderSetViewport((WGPURenderPassEncoder)get(), viewport[0].min, viewport[1].min, viewport[0].length(), viewport[1].length(), viewport[2].min, viewport[2].max);
	}

	void render_pass_encoder::set_scissor_rect(math::box<std::uint32_t, 2> const & rect)
	{
		wgpuRenderPassEncoderSetScissorRect((WGPURenderPassEncoder)get(), rect[0].min, rect[1].min, rect[0].length(), rect[1].length());
	}

	void render_pass_encoder::set_blend_constant(math::vector<double, 4> const & color)
	{
		static_assert(sizeof(WGPUColor) == sizeof(color));
		wgpuRenderPassEncoderSetBlendConstant((WGPURenderPassEncoder)get(), (WGPUColor const *)(&color));
	}

	void render_pass_encoder::set_stencil_reference(std::uint32_t reference)
	{
		wgpuRenderPassEncoderSetStencilReference((WGPURenderPassEncoder)get(), reference);
	}

	void render_pass_encoder::set_push_constants(shader_stage stages, std::uint32_t offset, util::span<char const> data)
	{
		wgpuRenderPassEncoderSetPushConstants((WGPURenderPassEncoder)get(), (WGPUShaderStage)stages, offset, data.size(), data.data());
	}

	void render_pass_encoder::draw(std::uint32_t vertex_count, std::uint32_t instance_count, std::uint32_t first_vertex, std::uint32_t first_instance)
	{
		wgpuRenderPassEncoderDraw((WGPURenderPassEncoder)get(), vertex_count, instance_count, first_vertex, first_instance);
	}

	void render_pass_encoder::draw_indexed(std::uint32_t index_count, std::uint32_t instance_count, std::uint32_t first_index, std::uint32_t base_vertex, std::uint32_t first_instance)
	{
		wgpuRenderPassEncoderDrawIndexed((WGPURenderPassEncoder)get(), index_count, instance_count, first_index, base_vertex, first_instance);
	}

	void render_pass_encoder::draw_indirect(buffer const & indirect_buffer, std::uint64_t offset)
	{
		wgpuRenderPassEncoderDrawIndirect((WGPURenderPassEncoder)get(), (WGPUBuffer)indirect_buffer.get(), offset);
	}

	void render_pass_encoder::draw_indexed_indirect(buffer const & indirect_buffer, std::uint64_t offset)
	{
		wgpuRenderPassEncoderDrawIndexedIndirect((WGPURenderPassEncoder)get(), (WGPUBuffer)indirect_buffer.get(), offset);
	}

	void render_pass_encoder::multi_draw_indirect(buffer const & indirect_buffer, std::uint64_t offset, std::uint32_t count)
	{
		wgpuRenderPassEncoderMultiDrawIndirect((WGPURenderPassEncoder)get(), (WGPUBuffer)indirect_buffer.get(), offset, count);
	}

	void render_pass_encoder::multi_draw_indexed_indirect(buffer const & indirect_buffer, std::uint64_t offset, std::uint32_t count)
	{
		wgpuRenderPassEncoderMultiDrawIndexedIndirect((WGPURenderPassEncoder)get(), (WGPUBuffer)indirect_buffer.get(), offset, count);
	}

	void render_pass_encoder::multi_draw_indirect_count(buffer const & indirect_buffer, std::uint64_t offset, buffer const & count_buffer, std::uint64_t count_offset, std::uint32_t max_count)
	{
		wgpuRenderPassEncoderMultiDrawIndirectCount((WGPURenderPassEncoder)get(), (WGPUBuffer)indirect_buffer.get(), offset, (WGPUBuffer)count_buffer.get(), count_offset, max_count);
	}

	void render_pass_encoder::multi_draw_indexed_indirect_count(buffer const & indirect_buffer, std::uint64_t offset, buffer const & count_buffer, std::uint64_t count_offset, std::uint32_t max_count)
	{
		wgpuRenderPassEncoderMultiDrawIndexedIndirectCount((WGPURenderPassEncoder)get(), (WGPUBuffer)indirect_buffer.get(), offset, (WGPUBuffer)count_buffer.get(), count_offset, max_count);
	}

	void render_pass_encoder::execute_bundles(std::vector<render_bundle> const & bundles)
	{
		static_assert(sizeof(WGPURenderBundle) == sizeof(render_bundle));
		wgpuRenderPassEncoderExecuteBundles((WGPURenderPassEncoder)get(), bundles.size(), (WGPURenderBundle const *)bundles.data());
	}

	void render_pass_encoder::begin_occlusion_query(std::uint32_t query_index)
	{
		wgpuRenderPassEncoderBeginOcclusionQuery((WGPURenderPassEncoder)get(), query_index);
	}

	void render_pass_encoder::end_occlusion_query()
	{
		wgpuRenderPassEncoderEndOcclusionQuery((WGPURenderPassEncoder)get());
	}

	void render_pass_encoder::write_timestamp(query_set const & query_set, std::uint32_t query_index)
	{
		wgpuRenderPassEncoderWriteTimestamp((WGPURenderPassEncoder)get(), (WGPUQuerySet)query_set.get(), query_index);
	}

	void render_pass_encoder::insert_debug_marker(std::string_view marker_label)
	{
		wgpuRenderPassEncoderInsertDebugMarker((WGPURenderPassEncoder)get(), detail::to_string_view(marker_label));
	}

	void render_pass_encoder::push_debug_group(std::string_view group_label)
	{
		wgpuRenderPassEncoderPushDebugGroup((WGPURenderPassEncoder)get(), detail::to_string_view(group_label));
	}

	void render_pass_encoder::pop_debug_group()
	{
		wgpuRenderPassEncoderPopDebugGroup((WGPURenderPassEncoder)get());
	}

	void render_pass_encoder::end()
	{
		wgpuRenderPassEncoderEnd((WGPURenderPassEncoder)get());
	}

	void render_pass_encoder::set_label(std::string const & label)
	{
		wgpuRenderPassEncoderSetLabel((WGPURenderPassEncoder)get(), detail::to_string_view(label));
	}

	void render_pass_encoder::reference(void * ptr)
	{
		wgpuRenderPassEncoderAddRef((WGPURenderPassEncoder)ptr);
	}

	void render_pass_encoder::release(void * ptr)
	{
		wgpuRenderPassEncoderRelease((WGPURenderPassEncoder)ptr);
	}

}
