/*
====================================================================================================

    Copyright (C) 2025 Pyvtron VX Shaders - Pyvton

    All Rights Reserved unless otherwise explicitly stated.

    Before You Do Something With Pyvtron VX Shaders, You MUST Read This:

    You Must Read The License: https://pyvton.pages.dev/minecraft-shaders/pyvtron-shaders-license
    And Read The Agreement: https://pyvton.pages.dev/minecraft-shaders/pyvtron-shaders-agreement

====================================================================================================
*/


const float _PI_ = 3.14159265358979323846;
const float _EPS_ = 1e-6;

float FSchlick(const float f0,const float LoH){float t=clamp(1.-LoH,.0,1.);float p=pow(t,5.);return f0+(1.-f0)*p;}float FSchlickGaussian(const float f0,const float LoH){float L=clamp(LoH,.0,1.);float x2=L*L;float x4=x2*x2;float x8=x4*x4;float e=exp2(-9.60232*x8-8.58092*L);return f0+(1.-f0)*e;}vec3 FExactF0(const vec3 f0,const float LoH){vec3 f=sqrt(max(f0,vec3(.0)));vec3 p=f+vec3(1.);vec3 m=f-vec3(1.);float t=clamp(1.-LoH*LoH,.0,1.);vec3 a=(m*m)*(t/(p*p+vec3(_EPS_)));vec3 xa=p*a;vec3 ma=m*a;vec3 x=(p*LoH+ma)/(p*LoH-ma+vec3(_EPS_));vec3 y=(m*LoH+xa)/(m*LoH-xa+vec3(_EPS_));vec3 r=.5*(y*y+x*x);return clamp(r,vec3(.0),vec3(1.));}vec3 FExact(const vec3 n,const vec3 k,const float c){float c2=c*c;vec3 k2=k*k;vec3 n2=n*n;vec3 n2k2=n2+k2;vec3 nc2=2.*n*c;vec3 rs=(n2k2-nc2+vec3(c2))/(n2k2+nc2+vec3(c2)+vec3(_EPS_));vec3 rp=(n2k2*vec3(c2)-nc2+vec3(1.))/(n2k2*vec3(c2)+nc2+vec3(1.)+vec3(_EPS_));return clamp(.5*(rs+rp),vec3(.0),vec3(1.));}vec3 FMaster(const float f0,const float LoH,const mat2x3 metalIOR,const vec3 diffuseColor){float f0c=clamp(f0,.0,1.);if(f0c<.16){return vec3(FSchlickGaussian(f0c,LoH));}else if(f0c<1.){return FExact(metalIOR[0],metalIOR[1],LoH);}return FExact(F0ToIor(diffuseColor),vec3(.0),LoH);}float DGGX(float a2,float NoH){float d=(NoH*a2-NoH)*NoH+1.;float denom=_PI_*d*d+_EPS_;return a2/denom;}float G1Smith(float alpha2,float NoS){float tmp=sqrt(alpha2+(1.-alpha2)*NoS*NoS);return(2.*NoS)/(tmp+NoS+_EPS_);}float G2Smith(float alpha2,float NoL,float NoV){float x=2.*NoL*NoV;float y=(1.-alpha2);float t1=sqrt(alpha2+y*(NoL*NoL));float t2=sqrt(alpha2+y*(NoV*NoV));return x/(NoV*t1+NoL*t2+_EPS_);}float VisJoint(float alpha,float NoL,float NoV){float invA=1.-alpha;float v=NoL*(NoV*invA+alpha)+NoV*(NoL*invA+alpha);return .5/(v+_EPS_);}float GetNoHSquared(float radiusTan,float NoL,float NoV,float VoL){float rc=inversesqrt(radiusTan*radiusTan+1.);float RoL=2.*NoL*NoV-VoL;if(RoL>=rc)return 1.;float invRoot=inversesqrt(max(1.-RoL*RoL,_EPS_));float rOverLengthT=rc*radiusTan*invRoot;float NoTr=rOverLengthT*(NoV-RoL*NoL);float VoTr=rOverLengthT*(2.*NoV*NoV-1.-RoL*VoL);float triple=sqrt(clamp(1.-NoL*NoL-NoV*NoV-VoL*VoL+2.*NoL*NoV*VoL,.0,1.));float NoBr=rOverLengthT*triple;float VoBr=rOverLengthT*(2.*triple*NoV);float NoLVTr=NoL*rc+NoV+NoTr;float VoLVTr=VoL*rc+1.+VoTr;float p=NoBr*VoLVTr;float q=NoLVTr*VoLVTr;float s=VoBr*NoLVTr;float xNum=q*(-.5*p+.25*VoBr*NoLVTr);float xDen=p*p+s*(s-2.*p)+NoLVTr*((NoL*rc+NoV)*VoLVTr*VoLVTr+q*(-.5*(VoLVTr+VoL*rc)-.5));float twoX1=2.*xNum/(xDen*xDen+xNum*xNum+_EPS_);float sinTheta=twoX1*xDen;float cosTheta=1.-twoX1*xNum;NoTr=cosTheta*NoTr+sinTheta*NoBr;VoTr=cosTheta*VoTr+sinTheta*VoBr;float newNol=NoL*rc+NoTr;float newVol=VoL*rc+VoTr;float NoH=NoV+newNol;float HoH=2.*newVol+2.;return max(NoH*NoH/max(HoH,_EPS_),.0);}void EvaluateNdotH(float radius,float NdotL,float NdotV,float LdotV,inout float NdotH){float rt=max(.001,tan(radius));NdotH=sqrt(max(GetNoHSquared(rt,NdotL,NdotV,LdotV),.0));}float EvaluateNormalizationFactor(float alpha,float LdotH,float radius){float a2=alpha*alpha*(LdotH+.001);return a2/(a2+.25*radius*(2.*alpha+radius)+_EPS_);}vec3 CalculateSpecularHighlight(vec3 diffuseColor,vec3 normal,vec3 viewVector,float roughness,float f0,mat2x3 metalIOR){vec3 L=worldLightVector;float NoL=dot(normal,L);if(NoL<=.0)return vec3(.0);float a=roughness;float a2=a*a;vec3 H=normalize(viewVector+L);float NoV=clamp(dot(normal,viewVector),1e-6,1.);float LoV=clamp(dot(L,viewVector),-1.,1.);float LoH=clamp(dot(L,H),-1.,1.);float NoH=.0;float lightAngularRadius=.015;EvaluateNdotH(lightAngularRadius,NoL,NoV,LoV,NoH);float pdf=EvaluateNormalizationFactor(a,LoH,lightAngularRadius);vec3 F=FMaster(f0,LoH,metalIOR,diffuseColor);float D=DGGX(a2,NoH);float G2=G2Smith(a2,NoL,NoV);vec3 spec=(F*D*G2)/(4.*NoL*NoV+_EPS_);spec*=clamp(NoL,.0,1.);if(f0>(230./255.)&& f0<1.)spec*=diffuseColor;return spec*pdf;}vec3 CalculateSpecularHighlightTorch(vec3 diffuseColor,vec3 normal,vec3 viewVector,vec3 lightVector,float roughness,float f0,mat2x3 metalIOR){vec3 L=lightVector;float NoL=dot(normal,L);if(NoL<=.0)return vec3(.0);float a=roughness;float a2=a*a;vec3 H=normalize(viewVector+L);float NoV=clamp(dot(normal,viewVector),1e-6,1.);float LoV=clamp(dot(L,viewVector),-1.,1.);float LoH=clamp(dot(L,H),-1.,1.);float NoH=.0;float lightAngularRadius=1e-6;EvaluateNdotH(lightAngularRadius,NoL,NoV,LoV,NoH);float pdf=EvaluateNormalizationFactor(a,LoH,lightAngularRadius);vec3 F=FMaster(f0,LoH,metalIOR,diffuseColor);float D=DGGX(a2,NoH);float G2=G2Smith(a2,NoL,NoV);vec3 spec=(F*D*G2)/(4.*NoL*NoV+_EPS_);spec*=clamp(NoL,.0,1.);if(f0>(230./255.)&& f0<1.)spec*=diffuseColor;return spec*pdf;}