/**
 * @author daoshengmu / http://dsmu.me/
 *
 * ------------------------------------------------------------------------------------------
 * Subsurface Scattering shader
 * Based on GDC 2011 – Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look
 * https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/
 *------------------------------------------------------------------------------------------
 */

function replaceAll( string, find, replace ) {

	return string.split( find ).join( replace );

}

var meshphong_frag_head = THREE.ShaderChunk[ "meshphong_frag" ].slice( 0, THREE.ShaderChunk[ "meshphong_frag" ].indexOf( 'void main() {' ) );
var meshphong_frag_body = THREE.ShaderChunk[ "meshphong_frag" ].slice( THREE.ShaderChunk[ "meshphong_frag" ].indexOf( 'void main() {' ) );

THREE.SubsurfaceScatteringShader = {

	uniforms: THREE.UniformsUtils.merge( [
		THREE.ShaderLib[ "phong" ].uniforms,
		{
			"thicknessMap": { value: null },
			"thicknessColor": { value: new THREE.Color( 0xffffff ) },
			"thicknessDistortion": { value: 0.1 },
			"thicknessAmbient": { value: 0.0 },
			"thicknessAttenuation": { value: 0.1 },
			"thicknessPower": { value: 2.0 },
			"thicknessScale": { value: 10.0 }
		}

	] ),

	vertexShader: [
		"#define USE_UV",
		THREE.ShaderChunk[ "meshphong_vert" ],
	].join( "\n" ),

	fragmentShader: [
		"#define USE_UV",
		"#define SUBSURFACE",

		meshphong_frag_head,

		"uniform sampler2D thicknessMap;",
		"uniform float thicknessPower;",
		"uniform float thicknessScale;",
		"uniform float thicknessDistortion;",
		"uniform float thicknessAmbient;",
		"uniform float thicknessAttenuation;",
		"uniform vec3 thicknessColor;",

		"void RE_Direct_Scattering(const in IncidentLight directLight, const in vec2 uv, const in GeometricContext geometry, inout ReflectedLight reflectedLight) {",
		"	vec3 thickness = thicknessColor * texture2D(thicknessMap, uv).r;",
		"	vec3 scatteringHalf = normalize(directLight.direction + (geometry.normal * thicknessDistortion));",
		"	float scatteringDot = pow(saturate(dot(geometry.viewDir, -scatteringHalf)), thicknessPower) * thicknessScale;",
		"	vec3 scatteringIllu = (scatteringDot + thicknessAmbient) * thickness;",
		"	reflectedLight.directDiffuse += scatteringIllu * thicknessAttenuation * directLight.color;",
		"}",

		meshphong_frag_body.replace( "#include <lights_fragment_begin>",

			replaceAll(
				THREE.ShaderChunk[ 'lights_fragment_begin' ],
				'RE_Direct( directLight, geometry, material, reflectedLight );',
				[
					"RE_Direct( directLight, geometry, material, reflectedLight );",

					"#if defined( SUBSURFACE ) && defined( USE_UV )",
					" RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight);",
					"#endif",
				].join( "\n" )
			),

		),

	].join( "\n" ),

};
