#pragma once
#include "c-opast.hh"
#include "c-sync.hh"

struct T_Rendertarget;

namespace ops {

enum E_OpType
{
	OP_END ,
	//
	OP_CALL ,
	OP_RET ,
	//
	OP_SKIP ,
	OP_COND_SKIP ,
	//
	OP_RES_STACK ,
	OP_PUSH ,
	OP_POP ,
	OP_DUP ,
	//
	OP_LOAD ,
	OP_STORE ,
	OP_SLOAD ,
	OP_CONST ,
	OP_OFFSET ,
	//
	OP_GET_INPUT ,
	//
	OP_FP_LOAD ,
	OP_FP_STORE ,
	OP_FP_SLOAD ,
	OP_FP_SSTORE ,
	OP_FP_SSTORE_INT ,
	//
	OP_FP_CMP ,
	OP_FP_ADD ,
	OP_FP_SUB ,
	OP_FP_MUL ,
	OP_FP_DIV ,
	OP_FP_POW ,
	//
	OP_FP_NEG ,
	OP_FP_INV ,
	OP_FP_NOT ,
	OP_FP_SIN ,
	OP_FP_COS ,
	OP_FP_TAN ,
	OP_FP_SQRT ,
	OP_FP_EXP ,
	OP_FP_LN ,
	//
	OP_GEN_ASSETS ,
	OP_INIT_PIPELINE ,
	OP_INIT_PROGRAM ,
	OP_INIT_SAMPLER ,
	OP_INIT_TEXTURE ,
	OP_FB_ATTACH ,
	//
	OP_USE_FRAMEBUFFER ,
	OP_FB_TOGGLE ,
	OP_USE_PIPELINE ,
	OP_USE_PROGRAM ,
	OP_USE_TEXTURE ,
	OP_UNIFORMS ,
	OP_VIEWPORT ,
	OP_IMAGE ,
	//
	OP_FULLSCREEN ,
	OP_COMPUTE ,
	OP_CLEAR ,
	//
	OP_UI_PENTER ,
	OP_UI_PEXIT ,
	OP_UI_INPUT_DFT ,
	OP_UI_INPUT_OVR ,
	OP_UI_ODBG ,
};

M_LSHIFT_OP( T_StringBuilder , E_OpType );
uint32_t ArgumentsFor( E_OpType op ) noexcept;
int32_t DeltaMainStack( E_OpType op ) noexcept;
int32_t DeltaFPUStack( E_OpType op ) noexcept;


struct T_Op
{
	static constexpr int MAX_ARGS = 2;

	E_OpType op;
	ebcl::T_SRDLocation location;
	uint32_t args[ MAX_ARGS ];

	T_Op( const E_OpType op ,
			ebcl::T_SRDLocation const& location ,
			const uint32_t arg0 = 0 ) noexcept
		: op( op ) , location( location ) ,
			args{ arg0 }
	{ }

	T_Op( const E_OpType op ,
			ebcl::T_SRDLocation const& location ,
			std::initializer_list< uint32_t > a ) noexcept
		: op( op ) , location( location )
	{
		assert( a.size( ) <= MAX_ARGS );
		auto it = a.begin( );
		for ( auto i = 0u ; i < a.size( ) ; i ++ , ++it ) {
			args[ i ] = *it;
		}
	}
};
M_LSHIFT_OP( T_StringBuilder , T_Op const& );


union T_OpValue
{
	int32_t i;
	uint32_t u;
	float f;

	constexpr T_OpValue( ) : i{ 0 } {}
	constexpr T_OpValue( uint32_t u ) : u{ u } {}
	constexpr T_OpValue( float f ) : f{ f } {}
};

struct T_OpProgram
{
	T_MultiArray< T_Op > ops;		// All operations
	uint32_t init ,				// Index of initialisation function
		 frame;				// Index of frame rendering function

	T_Array< T_OpValue > constants;		// Constants values
	uint32_t nVariables{ 0 };		// Amount of variables

	T_Array< T_String > inputs;		// Input definitions

	uint32_t nPrograms{ 0 } ,		// Amount of programs
		 nFramebuffers{ 0 } ,		// Amount of framebuffers
		 nPipelines{ 0 } ,		// Amount of pipelines
		 nSamplers{ 0 } ,		// Amount of samplers
		 nTextures{ 0 };		// Amount of textures
	T_Array< T_FSPath > progNames;		// GLSL program files

	T_Array< T_String > uiStrings;		// UI strings for profiling, etc.
	T_Array< P_SyncOverrideSection > overrides;
						// Override definitions for the UI
};
using P_OpProgram = T_OwnPtr< T_OpProgram >;

} // namespace ops