//================================================================
// E3D
//
// Materials and Shaders
//
// AUTHOR:  Gabor Nagy
// DATE:    2026-Jul-31 22:45:37
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#ifndef _E3D_Material_h
#define _E3D_Material_h

#include <stdint.h>  // For uint32_t etc. for E_Random

#ifndef _E3D_Texture_h
#include <E3D/Texture.h>
#endif


#define E3dM_SpectralLoop(pSpectralIndex, pNSpectralSamples)  int  LSC = 0, LSI = pSpectralIndex;for(;LSC < pNSpectralSamples;LSC++, LSI++)

#define E3dBRDF_MIS_MAX_SIZE_SQRT          16  // Square root of maximum BRDF sample for multiple importance-sampling shaders
#define E3dBRDF_CDF_MAX_SIZE_SQRT           8  // Square root of maximum size of CDF used for importance-sampling shaders
#define E3dBRDF_SUPERSAMPLE_MAX_SIZE_SQRT  32  // Square root of maximum BRDF supersampling multiplier
#define E3dBRDF_SHADER_SAMPLED_LOBES_MAX    2  // Max # of shader lobes that can be sampled for indirect light


#ifdef E3dCHECK_VALUES
#define M_MAX	1000000.0
#define _E3dCheckRGB_s(p) do\
{\
	assert(p.R < M_MAX);\
	assert(p.G < M_MAX);\
	assert(p.B < M_MAX);\
\
	assert(p.R >= 0.0);\
	assert(p.G >= 0.0);\
	assert(p.B >= 0.0);\
\
	assert(EFinite(p.R));\
	assert(EFinite(p.G));\
	assert(EFinite(p.B));\
} while(0)

#define _E3dCheckSpectral(p, pNSpectralSamples) do\
{\
	int  lSI = 0;for(;lSI < pNSpectralSamples;lSI++)\
	{\
		float  lF = p[lSI];\
		assert(lF >= 0.0);\
		assert(lF < M_MAX);\
		assert(EFinite(lF));\
	}\
} while(0)

#define _E3dCheckST_s(p) do\
{\
	if(!E3d_Finite(p.S)) assert(0);\
	if(!E3d_Finite(p.T)) assert(0);\
} while(0)

#define _E3dCheckST_p(p) do\
{\
	if(!E3d_Finite(p->S)) assert(0);\
	if(!E3d_Finite(p->T)) assert(0);\
} while(0)

#else
#define _E3dCheckRGB_s(p)
#define _E3dCheckSpectral(p, pNSpectralSamples)
#define _E3dCheckST_s(p)
#define _E3dCheckST_p(p)
#endif


#define E3dMaterial_NewAssignToMember(pShaderClass, pResult,pMember) do\
{\
	E3dMaterial*  lMaterial;ENew(lMaterial);if(lMaterial)\
	{\
		EM_ObjectInit(EObject, lMaterial, E3dMaterial_class);if(pShaderClass)\
		{\
			E3dMaterial_SetShader(lMaterial, E3dShader_New(pShaderClass));\
		}\
	}\
\
	E_AssignToMember(lMaterial, pResult,pMember);\
} while(0)


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


// Blending functions
//
enum
{
	E3dBLENDF_NONE = 0,
	E3dBLENDF_ONE_ZERO,
	E3dBLENDF_ONE_ONE,
	E3dBLENDF_ONE_ONE_MINUS_SRC_ALPHA
};


#define E3dBLENDF_NOT_SET	0xFFFFFFFF

#ifndef _E3dLight
#define _E3dLight
typedef struct E3dLight_S	E3dLight;
#endif


#ifndef _E3dShader
#define _E3dShader
typedef struct E3dShader_S  E3dShader;               // Forward-define E3dShader
#endif

#ifndef _E3dShaderClass
#define _E3dShaderClass
typedef struct E3dShaderClass_S   E3dShaderClass;    // Forward-define E3dShaderClass
typedef struct E3dShaderClass_S*  E3dShaderClassPtr;
EList_t(E3dShaderClassPtr);
#endif

#ifndef _E3dMaterial
#define _E3dMaterial
typedef struct E3dMaterial_S     E3dMaterial;     // Forward-define E3dMaterial
typedef struct E3dMaterial_S*    E3dMaterialPtr;
EList_t(E3dMaterialPtr);      // E3dMaterialPtrList
EListA_t(E3dMaterialPtr);     // E3dMaterialPtrListA
#endif

#ifndef _E3dScene
#define _E3dScene
typedef struct E3dScene_S        E3dScene;        // Forward-define E3dScene
#endif

#ifndef _E3dRenderer
#define _E3dRenderer
typedef struct E3dRenderer_S         E3dRenderer;         // Forward-define E3dRenderer
typedef struct E3dRenderer_thread_S  E3dRenderer_thread;  // Forward-define E3dRenderer_thread
#endif

// Generic ShaderProc for Init, Edit and Destroy
//
typedef int  (*E3dShaderUpdateFunc)(E3dMaterial* PMaterial, E3dShader* PShader, const E3dRenderer* PRenderer, E3dModel* PModel, E3dObject* PObject, EObject* PShadeable, const EChangeFlags PChangedFlags);

#define E3dBxDFLobeALL  0x07
// A light / light sample, passed to a shader
//
typedef struct
{
	union { E3dCoord4	PointToLightNew;E3dCoord3  PointToLightXYZ; };  // Point to light unit vector and light source distance
	float          Power[EcMAX_NUM_OF_SPECTRAL_SAMPLES];              // If these were already multiplied by the NdotL cosine term, Mult will be 1.0. Otherwise Mult is NdotL
	E3dCoordinate  NdotL, Mult;
	float          Weight;           // For importance sampling
	float          SolidAngle;
	float          CDFPosition;      // For importance-sampling, using a Cumulative Distribution Function
	uint16_t       Shadowed : 1,
	               ImportanceSampled : 1;
} E3dShaderLight, *E3dShaderLightPtr;
EList_t(E3dShaderLightPtr);


// Ray-tracing related definitions
//

#ifndef _E3dStackRay
#define _E3dStackRay
typedef struct E3dStackRay_S  E3dStackRay;		// Forward-define E3dStackRay
#endif

#ifndef _E3dRayTracer
#define _E3dRayTracer
typedef struct E3dRayTracer_S         E3dRayTracer;
typedef struct E3dRayTracer_thread_S  E3dRayTracer_thread;
#endif


// Struct filled out by shaders
//
typedef struct
{
// Inputs for the shader
//
	int                   SpectralIndex, NumOfSpectralSamples;  // Starting index, number of spectral samples (e.g. a hyper-spectral Renderer might trace rays band-by-band, so SpectralIndex

	ERandomState*         RandomState;

	const E3dRayTracer*   Renderer;
	E3dRayTracer_thread*  Thread;
	void*                 Face;               // Face that was hit (to avoid hitting it again with shadow rays etc.)
	uint32_t              FrontFace : 1,      // Surface front or back
	                      DoubleSided : 1,    // Surface is double-sided (blades of grass etc.)
												ApplyNdotL : 1;     // E.g. with photon mapping, the photon density implicitly includes the cosine term (Normal . Light direction)

// Outputs from the shader
//
	float                 Color[EcMAX_NUM_OF_SPECTRAL_SAMPLES];        // Color spectral samples
	float                 Opacity[EcMAX_NUM_OF_SPECTRAL_SAMPLES];      // Accumulated opacity color (i.e. color "alpha")

	float                 Reflective[EcMAX_NUM_OF_SPECTRAL_SAMPLES];   // This shader's mirror-reflectivity (not accumulated!)
	float                 Transparent[EcMAX_NUM_OF_SPECTRAL_SAMPLES];  // This shader's transparency (not accumulated!)

	float                 Emission[EcMAX_NUM_OF_SPECTRAL_SAMPLES];
	float                 LightVisibility;                             // Light visibility ratio (0.0 : all lights are blocked, 1.0 : not in shadow)
	E3dCoordinate         Depth;
} E3dShaderResult;


typedef int            (*E3dShaderVolumeFunc)(E3dScene* PScene, const E3dStackRay* PRay, E3dShaderResult* PResult);
typedef E3dCoordinate  (*E3dPhaseFunction)(const E3dShader* PShader, const E3dCoordinate PCosTheta);
typedef void           (*E3dPhaseFunctionSample)(const E3dShader* PShader, const E3dCoord3* PIn, const E3dCoordinate PU, const E3dCoordinate PV, E3dCoord3* POut);


typedef int  E3dSampleCount;


// Point used for shading surfaces and for TextureMappers
//
typedef struct
{
	E3dSurfacePointCore;

	E3dCoord3         Tangent;                                      // Tangent vector
	union { E3dCoord4	PointToViewer;E3dCoord3	PointToViewerXYZ; };  // Normalized X,Y,Z and length (distance)
	E3dCoord3         ViewerPosition;

	E3dCoord2         StratifiedUV;

	float             AmbientLightColor[EcMAX_NUM_OF_SPECTRAL_SAMPLES];
	const E3dShader*  SurfaceShader;

// Custom stuff
//
	EcRGBAf32Color    Color;                                        // Interpolated vertex color
	uint16_t          FaceSelected : 1;
} E3dSurfacePoint;

static inline void E3dSurfacePoint_Init(E3dSurfacePoint* PSurfacePoint)
{
	EClr_p(PSurfacePoint);
	PSurfacePoint->Normal = E3dCoord3_s(0.0, 1.0, 0.0);
	PSurfacePoint->Tangent = E3dCoord3_s(1.0, 0.0, 0.0);
	PSurfacePoint->Color = EcRGBAf32Color_s(1.0, 1.0, 1.0, 1.0);
}



// Position, Normal, Lights, NumOfLights, ColorReturn
//
typedef void  (*E3dShaderSurfaceFunc)(E3dRayTracer_thread* PRayTracer_thread,  E3dSurfacePoint* PSPoint,  const E3dMaterial* PSurfaceMaterial, const E3dShader* PTextureModulatedSurfaceShader, const E3dShader* PVolumeShader, const E3dShader* PShaderBeyondSurface,  const E3dShaderLight* PLightSamples, const int PNLightSamples,   E3dShaderResult* PResult);
typedef int   (*E3dShaderSampleDirectionFunc)(E3dSurfacePoint* PSPoint,  const E3dMaterial* PSurfaceMaterial, const E3dShader* PTextureModulatedSurfaceShader, const E3dShader* PVolumeShader,  const float PThreshold, ERandomState* PRandomState,  const int PSpectralIndex, const int PNSpectralSamples,   E3dShaderLight* PSamples);
typedef int   (*E3dShaderSampleDirectionsFunc)(E3dSurfacePoint* PSPoint,  const E3dMaterial* PSurfaceMaterial, const E3dShader* PTextureModulatedSurfaceShader, const E3dShader* PVolumeShader,  const E3dSampleCount PNumOfSamplesSqrt, const float PThreshold, ERandomState* PRandomState,  const int PSpectralIndex, const int PNSpectralSamples,  E3dShaderLight* PSamples);


#define E3dHIGHEST_SAMPLESET                 64  // Highest of BRDFUniform***xSampleSets

#ifndef _E3dGeometry
#define _E3dGeometry
typedef struct E3dGeometry_S  E3dGeometry;    // Forward-define E3dGeometry
#endif



#define E3dShdfCONSTANT  0x0001
#define E3dShdfLAMBERT   0x0002
#define E3dShdfPHONG     0x0004


// Convert a Shader to a basic, built-in class (Lambert, Phong, etc.), e.g. for the sake of file formats that don't support custom/complex shaders.
//
typedef E3dShader* (*E3dShaderCovertToBasicFunc)(const E3dShader* PShader, const uint16_t PClassFlags);


typedef struct E3dGPUContext_S  E3dGPUContext;

// Scene, Model, Geometry to draw, LSubGeoIndex, DisplayFlags
//
typedef int  (*E3dShaderGLDrawFunc)(E3dRenderer* PRenderer, const E3dDrawContext* PDrawContext, E3dGPUContext* PGPUContext,  E3dScene* PScene, E3dModel* PModel, E3dGeometry* PGeometry, EObject* PShadeable);



// Shader instance per Renderer instance data
#define E3dShaderRendererBindingCore\
	EObjectClass*  RendererClass

typedef struct
{
	E3dShaderRendererBindingCore;
	void*  Data;
} E3dShaderRendererBinding;



typedef void  (*E3dShaderRendererFunc)(E3dShader* PShader, E3dShaderRendererBinding* PBinding);
typedef void  (*E3dShaderRendererUpdateFunc)(E3dShader* PShader, const E3dRenderer* PRenderer, E3dShaderRendererBinding* PBinding);


#define E3dStageProgramCore\
	int    RefCnt;\
	char*  Source;EBool  SourceStatic;\
	char*  Signature

//
// Vertex program/fragment program etc. variant
//
typedef struct
{
	E3dStageProgramCore;
} E3dStageProgram, *E3dStageProgramPtr;
EListA_t(E3dStageProgramPtr);


#define E3dMAX_NUM_OF_LIGHTS  4

//----------------------------------------------------------------
// Code generation parameters for a specific ShaderVariant
//----------------------------------------------------------------
typedef struct
{
// Vertex attributes
	uint32_t  UsesPosition : 1;uint32_t  UsesNormal : 1;uint32_t  UsesTangent : 1;
	uint32_t  UsesColor0 : 1;uint32_t  UsesColor1 : 1;

	uint32_t  NeedPointToEye : 1;
	uint32_t  HasEYEPosition : 1;uint32_t  NeedEyePosition : 1;
	uint32_t  UseWorldSpace : 1;

	uint32_t  NeedLightColor : 1;uint32_t  NeedLightDiffuseSpecularFactors : 1;

	uint32_t  HasCubeMap : 1;uint32_t  HasReflectionMap : 1;uint32_t  HasRefractionMap : 1;
	uint32_t  HasFresnel : 1;
	uint32_t  HasIBLCubemap : 1;
	uint32_t  HasIBLPrefilteredCubemap : 1;

	uint32_t  AddComments : 1;

	uint32_t  NormalMapIndexFlags;  // There may be multiple normal-maps. These flags show which textures are normal-maps. E.g. bit-0 set to 1 means Texture-0 is a normal-map.
	uint8_t   NLights;uint8_t  LightTypes[E3dMAX_NUM_OF_LIGHTS];
} E3dSLCodeGenParams;


typedef uint16_t  E3dShaderPassesMask;

#define E3dShaderPassBASE        0x0001
#define E3dShaderPassLIGHTADD    0x0002
#define E3dShaderPassALL_LIGHTS  0x0004


#define E3dShaderVariantCore\
	char*                Signature;\
	int                  CreationResult;\
	int                  NumOfTextures;\
\
	E3dStageProgram*     VertexProgram;\
	E3dStageProgram*     GeometryProgram;\
	E3dStageProgram*     FragmentProgram;\
\
	E3dSLCodeGenParams   CodeGenParams;\
	int                  TextureEnginesUsed;\
	EIndex               NumOfBlendersPerTexture;\
	E3dTextureBlender**  TextureBlenderLists

typedef struct E3dShaderVariant_S   E3dShaderVariant;
typedef struct E3dShaderVariant_S*  E3dShaderVariantPtr;
EListA_t(E3dShaderVariantPtr);

struct E3dShaderVariant_S
{
	E3dShaderVariantCore;
	E3dShaderPassesMask  PassesMask;
};

// An instance of this struct appears on each ShaderClass for each custom RendererClass
//
#define E3dShaderClassRendererBindingCore\
	EObjectClass*                RendererClass;\
	EResourceList                VertexProgramResources;      /* Resources for the VertexProgram        */\
	EResourceList                Resources;                   /* Resources for the fragment program     */\
	char*                        SourceCore;                  /* Shader source core for auto-generating shader code  */\
	unsigned int                 ShaderBindingStructSize;\
	E3dShaderRendererFunc        Init,                        /* Called when Shader instance is created      */\
	                             Free;                        /* Called when Shader instance is destroyed    */\
	E3dShaderRendererUpdateFunc  Update;                      /* Called when Shader instance is updated      */\
	E3dShaderGLDrawFunc          GLDraw;\
	EListA_s(, E3dShaderVariantPtr, ShaderVariants);\
	uint32_t                     StagesUsed : 12,             /* E3dShaderStageVERTEX / _AUTO, E3dShaderStageGEOMETRY / _AUTO, E3dShaderStageFRAGMENT / _AUTO. More bits reserved for tesselation and compute shaders  */\
	                             Initialized : 1

typedef struct
{
	E3dShaderClassRendererBindingCore;
} E3dShaderClassRendererBinding;


struct E3dShaderClass_S
{
	EBaseClassCore(E3dShader);

// Default procedures
//
	E3dShaderUpdateFunc                 Update;               // Called when parameters change to allow pre-processing (e.g. recompiling a Cg/GLSL shader)

	E3dShaderSurfaceFunc                ShadeSurface;         // Active surface shader
	E3dShaderSurfaceFunc                UnshadeSurface;       // Active surface shader
	E3dShaderSampleDirectionFunc        SampleDirection;      // Importance sample BRDF 1-sample
	E3dShaderSampleDirectionsFunc       SampleDirections;     // Importance sample BRDF

	E3dShaderVolumeFunc              ShadeVolume;          // Active volumetric shader
	E3dPhaseFunction                 PhaseFunction;
	E3dPhaseFunctionSample           PhaseFunctionSample;

	E3dShaderCovertToBasicFunc       ConvertToBasic;       // Convert a Shader to a basic, built-in class (Lambert, Phong, etc.)

	E3dShaderGLDrawFunc              GLDraw;               // Active GLDrawProc

	E3dShaderGLDrawFunc              DefaultGLDraw;        // Default (fallback) GLDrawProc

	E3dShaderClassRendererBinding**  RendererClasses;EIndex  RendererClasses_Count;  // Renderer bindings
};


typedef struct
{
	EcColor        Absorption;    // Absorption coefficient
	EcColor        Scattering;    // Scattering albedo

	float          g;				      // Phase function g parameter
	E3dCoordinate  PhaseFunctionNormalizer;  // 1.0 / max. value of phase function

// Subsurface scattering
	int            SSSSamplesSqrt,    // Samples. The number of samples will be the square of this.
	               SSSDepth;          // Max number of scatter events before a ray is considered absorbed
} E3dVolumeShader;


#define E3dShaderCore\
	EObjectCore(E3dShader);\
\
	E3dShaderRendererBinding**  RendererBindings;  /* Renderer bindings. The number and order matches that of the ShaderClass.   */\
\
	EcColor     Emission;\
\
	EcColor     Reflective;float  Reflectivity;    /* Mirror-reflectivity color and multiplier                                   */\
	EBool       UsesLights, ReflectedCaustics, UseVertexColors;\
	EcColor     ReflectiveBack;                    /* Mirror-reflectivity for the back side of surfaces (internal reflection)    */\
	EcColor     Transparent;float  Transparency;   /* The Shader "lets this color through" at the surface. Color and multiplier.  */\
\
	int         BxDFSupersamplingSqrt;             /* Supersample indirect light. E.g. for objects receiving caustics. */\
\
/* Internal data used by renderers            */\
/* Updated in E3dMaterial_UpdateForDisplay()  */\
/* Spectrally sampled colors                  */\
\
	E3dVolumeShader  Volume;\
	float            RefractiveIndexInv_RGB[3];\
	float            Fresnel0_RGB[3];    /* Fresnel reflectance factor at normal-direction            */\
	float            Alpha;\
\
	EcColor          RefractiveIndex;             /* Spectral refractive index, specified by the user, if any  */\
\
	EBool            NormalizeBRDF;               /* Normalize, so the integral of the BRDF will add up to 1.0. Allows for getting shininess, etc. from a texture easily  */\
/* CDF-based importance sampling for shaders with no closed-form / invertable probability distribution function */\
	int              ImportanceSamplingBinsSqrt;\
\
	uint16_t         MISBxDFSamplesSqrt;          /* When not 0, use multiple importance sampling and use this many samples for the BxDF */\
\
	float            RefractiveIndexMono;         /* For backward compatibility                                */\
	uint32_t         IsReflective : 1, IsTransparent : 1,\
	                 IsEmissive : 1, HasVolumeAbsorption : 1, HasVolumeScattering : 1,\
	                 HasMIPMapping : 1, HasAnisotropicFiltering : 1;\
	EIndex           NumOfEmissionTextures

// E3dShaderSampleDirectionsFunc  SampleDirections

struct E3dShader_S
{
	E3dShaderCore;
};




typedef struct
{
	E3dShaderCore;

	EcColor  Diffuse;
	EBool    FresnelReflection, FresnelTransparency;
} E3dUnlitShader;


typedef struct
{
	E3dShaderCore;

	EcColor  Ambient, Diffuse;
	EBool    FresnelReflection;
} E3dLambertShader;


typedef struct
{
	E3dShaderCore;

	EcColor  Ambient, Diffuse, Specular;
	float    Shininess;  // Specular exponent
	EBool    FresnelReflection;

	float    ShininessHalf;
} E3dPhongShader;


// Material used with fixed-function OpenGL
//
#ifdef USEOpenGL
typedef struct
{
	float  Ambient[4];
	float  Diffuse[4];
	float  Specular[4];
	float  Emission[4];
	float  Shininess;
	float  FlatColor[4];
	int    BlendingFunction;
	int    UseTextureIndex;  // Index to Texture to use in Material->Textures, or -1 if none of them apply (e.g. all BlendingFactors are 0.0)
	EBool  SeparateSpecularColor;
} E3dGLMaterial;
#endif // USEOpenGL

enum
{
	E3dIS_BY_TRIANGLE_APPARENT_SOLID_ANGLE = 1
};

// Area light
//
typedef struct
{
// User-settable parameters
//
	float    ShadowBrightness, CutoffAngle;  // 0.0 .. 90 degrees
	int64_t  NumOfSamples;
	uint8_t  ImportanceSampling;             // 0 or E3dIS_BY_TRIANGLE_APPARENT_SOLID_ANGLE

// Internals
//
	float    CutoffAngleCos;
	EIndex   ChangeCount;            // Change-counter. Will usually trigger a full copy of the Material for rendering.
	EIndex   SamplingChangeCount;    // Change-counter for NumOfSamples and ImportanceSampling
	EIndex   NPhotons;               // 0: don't shoot photons from this light. -1: auto
} E3dMatLight;


struct E3dMaterial_S
{
	EObjectCore(EObject);

	char*           FileName;

	EObjectID       ID;                   // Unique ID of this Material. This ensures that we can identify Materials clearly, even if it we free Materials and a freed pointer gets reused for a new allocation.
	EObjectID       OriginalID;           // The ID of the Material this one was cloned from. 0 if this is an "original" (not a clone).

	E3dShader*      Shader;

	E3dMatLight     Light;                // Light source information for area lights

	EListA_s(, E3d2DTexturePtr, Textures);

	E3dDrawState    DrawState;            // Depth write / depth test, blending function etc.

#ifdef USEOpenGL
	E3dGLMaterial   GLMaterial;
	E3dGLMaterial   GLTextureMaterial;
#endif // USEOpenGL


// Internal data used by EQUINOX-3D
//
	int32_t         CurrentTextureIndex;  // For editing, in the Material dialog box, and for selecting textures for fixed-pipeline OpenGL renderers
	E3dCoord3       SchemTranslation;     // Parent-relative position on schematic view
	E3dCoord3       SchemPosition;        // World-relative position on schematic view
	void*           Sample;               // Material sample (little icon with name etc. in the lister)

	EChanges        Changes;
};


static inline void E3dShaderResult_SetCore(const E3dShader* PShader, E3dShaderResult* PResult)
{
	const int   LSpectralIndex = PResult->SpectralIndex, LNSpectralSamples = PResult->NumOfSpectralSamples;const int  LSpectralBytes = sizeof(float) * LNSpectralSamples;
	memcpy(PResult->Transparent + LSpectralIndex, PShader->Transparent.Samples + LSpectralIndex, LSpectralBytes);
	memcpy(PResult->Emission + LSpectralIndex, PShader->Emission.Samples + LSpectralIndex, LSpectralBytes);
}


//================================================================
// Initialize an E3dShaderResult
// The E3dShaderResult structure is filled out by shaders.
//================================================================
static inline void E3dShaderResult_Init(E3dShaderResult* PShaderResult, const E3dMaterial* PMaterial,  const int PSpectralIndex, const int PNSpectralSamples,  const E3dRayTracer* PRenderer, E3dRayTracer_thread* PThread,  ERandomState* PRandomState,  void* PFace, const EBool PFrontFace, const EBool PDoubleSided)
{
	const E3dShader*	LShader = PMaterial->Shader;
	PShaderResult->SpectralIndex = PSpectralIndex;PShaderResult->NumOfSpectralSamples = PNSpectralSamples;
	memcpy(PShaderResult->Reflective + PSpectralIndex, LShader->Reflective.Samples  + PSpectralIndex, sizeof(float) * PNSpectralSamples);
	memcpy(PShaderResult->Transparent + PSpectralIndex, LShader->Transparent.Samples + PSpectralIndex, sizeof(float) * PNSpectralSamples);
	memset(PShaderResult->Color + PSpectralIndex, 0, sizeof(float) * PNSpectralSamples);
	memset(PShaderResult->Opacity + PSpectralIndex, 0, sizeof(float) * PNSpectralSamples);
	PShaderResult->Depth = 0.0;
	PShaderResult->RandomState = PRandomState;
	PShaderResult->ApplyNdotL = TRUE;
	PShaderResult->Renderer = PRenderer;
	PShaderResult->Thread = PThread;
	PShaderResult->Face = PFace;
	PShaderResult->FrontFace = PFrontFace;
	PShaderResult->DoubleSided = PDoubleSided;
}



//----------------------------------------------------------------
// Global variables & structures
//----------------------------------------------------------------
extern EBool  E3d_DefaultBRDFSampling_Force, E3d_DefaultBRDFSampling_IS;

extern const float  E3d_Ones[];

extern EResourceList     E3dMaterial_resources;
extern EObjectClass      E3dMaterial_class[];
extern E3dShaderClass    E3dShader_class[];

extern E3dShaderClass*   E3dUnlitShader_class;
extern E3dShaderClass*   E3dLambertShader_class;
extern E3dShaderClass*   E3dPhongShader_class;

extern const char  E3dShaderSemantic_Prefix[];

EList_s(extern, E3dShaderClassPtr, E3dShader_Classes);
extern EIndex            E3d_NumOfBuiltInShaderClasses;
extern int               E3d_KillTextureFilteringOverAALevel;  // Turn off MIP-mapping and anisotropic filtering at and above this level of anti-aliasing


extern E3dMaterial*   E3d_DefaultMaterial;
extern E3d2DTexture   E3d_Default2DTexture;
extern E3d2DTexture*  E3d_Default2DTextureArray[1];

extern E3dMaterial*   E3d_PlasterMaterial;

extern const float    E3d_TransparencyMin;

extern char           E3dNMayComeFromTexture[];  // Used in the .UI element of a Shader Resource. It indicates that the Resource may come from a Texture, and a TextureBlender will be created for it.

extern EArg  E3d_BRDFSS_UI[];
extern char  E3d_BRDFSS_ToolTip[];

//----------------------------------------------------------------
// Function prototypes
//----------------------------------------------------------------
extern void    (*E3d_ShaderClassFreeGUI)(E3dShaderClass* PShaderClass);

extern E3dMaterial*  E3dMaterial_New(E3dShaderClass* PShaderClass);

extern void    E3dMaterial_Print(E3dMaterial* PMaterial, const int PIndent);

extern void    E3dMaterial_SetShader(E3dMaterial* PMaterial, E3dShader* PShader);
extern void    E3dMaterial_ConvertShader(E3dMaterial* PMaterial, E3dShader* PShader);

extern E3d2DTexture*  E3dMaterial_AddTexture(E3dMaterial* PMaterial);
extern void    E3dMaterial_AppendTexture(E3dMaterial* PMaterial, E3d2DTexture* PTexture);
extern void    E3dMaterial_InsertTexture(E3dMaterial* PMaterial, E3d2DTexture* PTexture, const EIndex PWhere);
extern void    E3dMaterial_RemoveTexture(E3dMaterial* PMaterial, E3d2DTexture* PTexture);
extern EChangeFlags   E3dMaterial_UpdateClone(const E3dMaterial* PSrcMaterial, E3dRenderer* PRenderer,  E3dMaterial* PDstMaterial);

extern EBool   E3dMaterial_IsAreaLight(E3dMaterial* PMaterial, EIndex* PNumOfEmissionTextures);

extern E3dCoordinate	E3d_HGPhase(const E3dShader* PShader, const E3dCoordinate PCosTheta);
extern void    E3d_HGPhaseSample(const E3dShader* PShader, const E3dCoord3* PAxis,  const E3dCoordinate PEta1, const E3dCoordinate PEta2,  E3dCoord3* PResult);

extern void    E3dMaterial_UpdateForDisplay(E3dMaterial* PMaterial, const E3dRenderer* PRenderer, const EChangeFlags PChanged, const EChangeFlags PTextureUpdateFlags);
extern void    E3dMaterial_UpdateAreaLightCutoffAngle(E3dMaterial* PMaterial);

extern void    E3dTexture_UpdateBlenders(E3dMaterial* PMaterial, E3d2DTexture* PTexture, const EBool PInitialize);
extern void    E3d2DTexture_UpdateForDisplay(const E3dMaterial* PMaterial, E3d2DTexture* PTexture, const int PNSubPixels, const int PNAnisoSamples, const int PColorModel, const EUpdateFlags PFlags);



extern E3dShader*  E3dShader_New(E3dShaderClass* PClass);
extern E3dShader*  E3dShader_Copy(const E3dShader* PShader);
extern float       E3dShader_GetTransparency(const E3dShader* PShader);

extern E3dShader*  E3dShader_ModulateWithTextures(const E3dMaterial* PMaterial,  const E3dShader* PSrcShader, E3dShader* PDstShader,  const EcRGBAf32Color* PTextureColors,  const int PSpectralIndex, const int PNSpectralSamples);


extern E3dShaderClass*	E3dShader_ClassByName(const char* PName);
extern E3dShaderClass*	E3dShader_ClassRegister(const E3dShaderClass* PTemplate);
extern E3dShaderClass*	E3dShader_ClassRegisterInactive(const char* PName);
extern void		  E3dShader_ClassDeactivate(E3dShaderClass* PShader);
extern void		  E3dShader_ClassesFree(void);

extern void     E3d_AddBuiltInShaders(void);

extern void          E3dGL_ContextBindShader(E3dGPUContext* PGPUContext, E3dShaderVariant* PGLShader);
extern unsigned int  E3dGL_MaterialBind(E3dScene* PScene, E3dGPUContext* PGPUContext,  E3dMaterial* PMaterial,  const E3dTextureMapperPtrList* PTextureMappers, const E3dTextureMapperPtrList* PTextureMapperRefs, const int PTextureIndex,  const EBool PUseTextures, const EBool PTransparencyOn);


// Internal functions
//
extern void  _E3dMaterial_CopyFields(const E3dMaterial* PSrcMaterial, E3dMaterial* PDstMaterial);


// Legacy interface
//
extern EBool  E3dMaterial_GetDiffuseColorRGB(const E3dMaterial* PMaterial, EcRGBf32Color* PResult);


#ifdef USEOpenGL
extern void   E3dMaterial_GLConvert(E3dMaterial* PMaterial);
#endif // USEOpenGL


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

#endif	// _E3D_Material_h
