//================================================================
// E3D
//
// - Cg definitions
//
// AUTHOR:  Gabor Nagy
// DATE:    2024-Nov-03 17:22:23
//
// Copyright (C) 2014-2026 by Gabor Nagy. All rights reserved.
//================================================================
#ifndef _E3D_Cg_h
#define _E3D_Cg_h

#ifdef __APPLE__
#include <cgGL.h>
#else
#include <Cg/cgGL.h>
#endif

#include <E3D/Rendering.h>
#include <E3D/SL.h>

#include <E3D/GL/Draw.h>
#include "../PGPURenderer.h"

#define E3dThisShaderVariant  E3dCgShaderVariant
#define E3dThisVertexProgram  E3dCgVertexProgram

//=====================================================
// Resolve a uniform parameter from a Cg file
//=====================================================
#define E3dSLM_GetNamedParameterFrag(pMaterial, pShaderVariant, pParameterName, pParameterOut, pErrorOnFail) do\
{\
	E3dSL_DebugRec.ParameterName = pParameterName;\
	E3dCgFragmentProgram*  lFragmentProgram = (E3dCgFragmentProgram*)pShaderVariant->FragmentProgram;\
	pParameterOut = cgGetNamedParameter(lFragmentProgram->Program, pParameterName);if(pErrorOnFail && !E3dSLParameterValid(pParameterOut))\
	{\
		pShaderVariant->CreationResult = E_UNDEFINED_SYMBOL;\
		const E3dMaterial*  lMaterial = pMaterial;\
		E3dShader*    lShader = lMaterial->Shader;\
		App_Log(ELogWARNING, "Cg", "Material [%s:%s] : Unable to resolve FragmentProgram uniform parameter '%s' from shader '%s'.", lShader->Class->Name, lMaterial->Name, pParameterName, pShaderVariant->Signature);\
/*		return(NULL);*/\
	}\
} while(0)


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif


#if E3dGL_FLOAT_BITS == 64
	#define E3dSLSetMatrix3x3Parameterc  cgGLSetMatrixParameterdc
	#define E3dSLSetMatrix3x3Parameterr  cgGLSetMatrixParameterdr
	#define E3dSLSetMatrix4x4Parameterc  cgGLSetMatrixParameterdc
	#define E3dSLSetMatrix4x4Parameterr  cgGLSetMatrixParameterdr
#else
	#if E3dGL_FLOAT_BITS == 32
		#define E3dSLSetMatrix3x3Parameterc  cgGLSetMatrixParameterfc
		#define E3dSLSetMatrix3x3Parameterr  cgGLSetMatrixParameterfr
		#define E3dSLSetMatrix4x4Parameterc  cgGLSetMatrixParameterfc
		#define E3dSLSetMatrix4x4Parameterr  cgGLSetMatrixParameterfr
	#else
ERROR
	#endif
#endif




//========================================================
// Resolve a uniform parameter from a vertex program
//========================================================
#define E3dSLM_GetNamedParameterVP(pVertexProgram, pParameterName, pParameterOut) do\
{\
	pParameterOut = cgGetNamedParameter(pVertexProgram->Program, pParameterName);\
} while(0)


//========================================================
// Resolve a uniform parameter from a VertexProgram
//========================================================
#define E3dSLM_GetNamedParameterVPErrorCheck(pStageProgram, pParameterName, pParameterOut, pFileName) do\
{\
	pParameterOut = cgGetNamedParameter(pStageProgram->Program, pParameterName);if(!E3dSLParameterValid(pParameterOut))\
	{\
		const char*  lFileName = pFileName;\
		if(E3dSL_DebugRec.Material)\
		{\
			E3dMaterial*  lMaterial = E3dSL_DebugRec.Material;\
			E3dShader*    lShader = lMaterial->Shader;\
			if(lFileName) App_Log(ELogWARNING, "Cg", "Material [%s : %s] : Unable to resolve VertexProgram parameter '%s' from file '%s'", lShader->Class->Name, lMaterial->Name, pParameterName, lFileName);\
			else App_Log(ELogWARNING, "Cg", "Material [%s : %s] : Unable to resolve VertexProgram parameter '%s'.", lShader->Class->Name, lMaterial->Name, pParameterName);\
		}\
		else\
		{\
			if(lFileName) App_Log(ELogWARNING, "Cg", "Unable to resolve VertexProgram parameter '%s' from file '%s'", pParameterName, lFileName);\
			else App_Log(ELogWARNING, "Cg", "Unable to resolve VertexProgram parameter '%s'.", pParameterName);\
		}\
	}\
} while(0)


//================================================================
// Resolve a vertex attribute parameter from a VertexProgram
//================================================================
#define E3dSLM_GetNamedAttributeVPErrorCheck(pStageProgram, pParameterName, pParameterOut, pFileName)  E3dSLM_GetNamedParameterVPErrorCheck(pStageProgram, pParameterName, pParameterOut, pFileName)


// Vertex program
//
typedef struct
{
	E3dStageProgramCore;

	CGprogram     Program;

	CGparameter   Param_VtU_EyeLocalPosition,
	              Param_VtU_TextureMapperMatrix[E3dSLMAX_NUM_OF_TEXCOORDS];  // Planar texture mappers use matrices

	CGparameter   Param_VtA_TextureTangent[E3dSLMAX_NUM_OF_TEXCOORDS],           // Texture-space tangents for normalmaps
	              Param_VtA_Color,
	              Param_VtA_Tangent,
	              Param_VtA_Custom[E3dSLMAX_NUM_OF_ARRAY_PARAMETERS];

	CGparameter	  Param_VtU_ModelViewProjectionMatrix;

	CGparameter	  Param_VtU_LocalToWorldMatrix,
	              Param_VtU_LocalToWorldUnitVectorMatrix,
	              Param_VtU_ModelViewMatrix,
	              Param_VtU_ShadowMapProjMatrix[E3dSLMAX_NUM_OF_LIGHTS];
	CGparameter*  ResourceParameters;EIndex  NumOfResourceParameters;

	EBool         ResourceParametersStatic;
} E3dCgVertexProgram;

// Geometry program
//
typedef struct
{
	E3dStageProgramCore;

	CGprogram     Program;
} E3dCgGeometryProgram;

// Fragment program
//
typedef struct
{
	E3dStageProgramCore;

	CGprogram  Program;
} E3dCgFragmentProgram;


typedef struct
{
	CGparameter  Param_Position, Param_SpotDirection, Param_SpotCutoffAngleCos, Param_SpotAngle, Param_SpotPenumbraAngle, Param_SpotExponent, Param_Color, Param_DiffuseSpecularFactors, Param_ShadowMap;
} E3dCgLight;

#define E3dSLLight  E3dCgLight

typedef struct
{
	E3dShaderVariantCore;

// Fragment program
//
	CGparameter  Param_FgU_LocalToWorldUnitVectorMatrix,
	             Param_FgU_EyeLocalPosition, Param_FgU_EyeWorldPosition,
	             Param_FgU_Alpha,
	             Param_FgU_Fresnel0_RGB;                // Fresnel reflectance at normal direction

	CGparameter  Param_FgU_NumOfLights;
	E3dCgLight   Lights[E3dSLMAX_NUM_OF_LIGHTS];

	CGparameter  Param_FgU_Textures[E3dSLMAX_NUM_OF_2DTEXTURES],
	             Param_FgU_TextureBRDFSamplesSqrt[E3dSLMAX_NUM_OF_2DTEXTURES], Param_FgU_TextureEnvLightFactor[E3dSLMAX_NUM_OF_2DTEXTURES],
	             Param_FgU_Eta[E3dSLMAX_NUM_OF_2DTEXTURES],     // Relative indices of refraction for refraction cube-maps
	             Param_FgU_NormalMaps[E3dSLMAX_NUM_OF_2DTEXTURES],
	             Param_FgU_Custom[E3dSLMAX_NUM_OF_PARAMETERS];

	CGparameter**  TextureBlendingParameters;     // For each [Texture][FragmentUniformParam]
} E3dCgShaderVariant;


typedef struct
{
	E3dShaderRendererBindingCore;

	E3dCgShaderVariant*  CgShader;
} E3dShaderCgBinding;



typedef struct
{
	E3dPGPURendererCore;
} E3dCgRenderer;



extern CGcontext	E3dCg_ShaderContext;

extern CGprofile	E3dCg_VertexProfile;
extern CGprofile	E3dCg_FragmentProfile;

#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}	// Close scope of 'extern "C"' declaration which encloses file.
#endif

#endif	// _E3D_Cg_h
