#include <string>
namespace slg { namespace ocl {
std::string KernelSource_materialdefs_funcs_generic = 
"#line 2 \"materialdefs_funcs_generic.cl\"\n"
"\n"
"/***************************************************************************\n"
" * Copyright 1998-2013 by authors (see AUTHORS.txt)                        *\n"
" *                                                                         *\n"
" *   This file is part of LuxRender.                                       *\n"
" *                                                                         *\n"
" * Licensed under the Apache License, Version 2.0 (the \"License\");         *\n"
" * you may not use this file except in compliance with the License.        *\n"
" * You may obtain a copy of the License at                                 *\n"
" *                                                                         *\n"
" *     http://www.apache.org/licenses/LICENSE-2.0                          *\n"
" *                                                                         *\n"
" * Unless required by applicable law or agreed to in writing, software     *\n"
" * distributed under the License is distributed on an \"AS IS\" BASIS,       *\n"
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*\n"
" * See the License for the specific language governing permissions and     *\n"
" * limitations under the License.                                          *\n"
" ***************************************************************************/\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Generic material related functions\n"
"//------------------------------------------------------------------------------\n"
"\n"
"float SchlickDistribution_SchlickZ(const float roughness, float cosNH) {\n"
"	const float cosNH2 = cosNH * cosNH;\n"
"	// expanded for increased numerical stability\n"
"	const float d = cosNH2 * roughness + (1.f - cosNH2);\n"
"	// use double division to avoid overflow in d*d product\n"
"	return (roughness / d) / d;\n"
"}\n"
"\n"
"float SchlickDistribution_SchlickA(const float3 H, const float anisotropy) {\n"
"	const float h = sqrt(H.x * H.x + H.y * H.y);\n"
"	if (h > 0.f) {\n"
"		const float w = (anisotropy > 0.f ? H.x : H.y) / h;\n"
"		const float p = 1.f - fabs(anisotropy);\n"
"		return sqrt(p / (p * p + w * w * (1.f - p * p)));\n"
"	}\n"
"\n"
"	return 1.f;\n"
"}\n"
"\n"
"float SchlickDistribution_D(const float roughness, const float3 wh, const float anisotropy) {\n"
"	const float cosTheta = fabs(wh.z);\n"
"	return SchlickDistribution_SchlickZ(roughness, cosTheta) * SchlickDistribution_SchlickA(wh, anisotropy) * M_1_PI_F;\n"
"}\n"
"\n"
"float SchlickDistribution_SchlickG(const float roughness, const float costheta) {\n"
"	return costheta / (costheta * (1.f - roughness) + roughness);\n"
"}\n"
"\n"
"float SchlickDistribution_G(const float roughness, const float3 fixedDir, const float3 sampledDir) {\n"
"	return SchlickDistribution_SchlickG(roughness, fabs(fixedDir.z)) *\n"
"			SchlickDistribution_SchlickG(roughness, fabs(sampledDir.z));\n"
"}\n"
"\n"
"float GetPhi(const float a, const float b) {\n"
"	return M_PI_F * .5f * sqrt(a * b / (1.f - a * (1.f - b)));\n"
"}\n"
"\n"
"void SchlickDistribution_SampleH(const float roughness, const float anisotropy,\n"
"		const float u0, const float u1, float3 *wh, float *d, float *pdf) {\n"
"	float u1x4 = u1 * 4.f;\n"
"	// Values of roughness < .0001f seems to trigger some kind of exceptions with\n"
"	// AMD OpenCL on GPUs. The result is a nearly freeze of the PC.\n"
"	const float cos2Theta = (roughness < .0001f) ? 1.f : (u0 / (roughness * (1.f - u0) + u0));\n"
"	const float cosTheta = sqrt(cos2Theta);\n"
"	const float sinTheta = sqrt(1.f - cos2Theta);\n"
"	const float p = 1.f - fabs(anisotropy);\n"
"	float phi;\n"
"	if (u1x4 < 1.f) {\n"
"		phi = GetPhi(u1x4 * u1x4, p * p);\n"
"	} else if (u1x4 < 2.f) {\n"
"		u1x4 = 2.f - u1x4;\n"
"		phi = M_PI_F - GetPhi(u1x4 * u1x4, p * p);\n"
"	} else if (u1x4 < 3.f) {\n"
"		u1x4 -= 2.f;\n"
"		phi = M_PI_F + GetPhi(u1x4 * u1x4, p * p);\n"
"	} else {\n"
"		u1x4 = 4.f - u1x4;\n"
"		phi = M_PI_F * 2.f - GetPhi(u1x4 * u1x4, p * p);\n"
"	}\n"
"\n"
"	if (anisotropy > 0.f)\n"
"		phi += M_PI_F * .5f;\n"
"\n"
"	*wh = (float3)(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);\n"
"	*d = SchlickDistribution_SchlickZ(roughness, cosTheta) * SchlickDistribution_SchlickA(*wh, anisotropy) * M_1_PI_F;\n"
"	*pdf = *d;\n"
"}\n"
"\n"
"float SchlickDistribution_Pdf(const float roughness, const float3 wh,\n"
"		const float anisotropy) {\n"
"	return SchlickDistribution_D(roughness, wh, anisotropy);\n"
"}\n"
"\n"
"float3 FresnelSchlick_Evaluate(const float3 normalIncidence, const float cosi) {\n"
"	return normalIncidence + (WHITE - normalIncidence) *\n"
"		pow(1.f - cosi, 5.f);\n"
"}\n"
"\n"
"float3 CoatingAbsorption(const float cosi, const float coso,\n"
"		const float3 alpha, const float depth) {\n"
"	if (depth > 0.f) {\n"
"		// 1/cosi+1/coso=(cosi+coso)/(cosi*coso)\n"
"		const float depthFactor = depth * (cosi + coso) / (cosi * coso);\n"
"		return Spectrum_Exp(alpha * -depthFactor);\n"
"	} else\n"
"		return WHITE;\n"
"}\n"
"\n"
"float3 FrDiel2(const float cosi, const float3 cost, const float3 eta) {\n"
"	float3 Rparl = eta * cosi;\n"
"	Rparl = (cost - Rparl) / (cost + Rparl);\n"
"	float3 Rperp = eta * cost;\n"
"	Rperp = (cosi - Rperp) / (cosi + Rperp);\n"
"\n"
"	return (Rparl * Rparl + Rperp * Rperp) * .5f;\n"
"}\n"
"\n"
"float3 FrFull(const float cosi, const float3 cost, const float3 eta, const float3 k) {\n"
"	const float3 tmp = (eta * eta + k * k) * (cosi * cosi) + (cost * cost);\n"
"	const float3 Rparl2 = (tmp - (2.f * cosi * cost) * eta) /\n"
"		(tmp + (2.f * cosi * cost) * eta);\n"
"	const float3 tmp_f = (eta * eta + k * k) * (cost * cost) + (cosi * cosi);\n"
"	const float3 Rperp2 = (tmp_f - (2.f * cosi * cost) * eta) /\n"
"		(tmp_f + (2.f * cosi * cost) * eta);\n"
"	return (Rparl2 + Rperp2) * 0.5f;\n"
"}\n"
"\n"
"float3 FresnelGeneral_Evaluate(const float3 eta, const float3 k, const float cosi) {\n"
"	float3 sint2 = fmax(0.f, 1.f - cosi * cosi);\n"
"	if (cosi > 0.f)\n"
"		sint2 /= eta * eta;\n"
"	else\n"
"		sint2 *= eta * eta;\n"
"	sint2 = Spectrum_Clamp(sint2);\n"
"\n"
"	const float3 cost2 = 1.f - sint2;\n"
"	if (cosi > 0.f) {\n"
"		const float3 a = 2.f * k * k * sint2;\n"
"		return FrFull(cosi, Spectrum_Sqrt((cost2 + Spectrum_Sqrt(cost2 * cost2 + a * a)) / 2.f), eta, k);\n"
"	} else {\n"
"		const float3 a = 2.f * k * k * sint2;\n"
"		const float3 d2 = eta * eta + k * k;\n"
"		return FrFull(-cosi, Spectrum_Sqrt((cost2 + Spectrum_Sqrt(cost2 * cost2 + a * a)) / 2.f), eta / d2, -k / d2);\n"
"	}\n"
"}\n"
"\n"
"float3 FresnelCauchy_Evaluate(const float eta, const float cosi) {\n"
"	// Compute indices of refraction for dielectric\n"
"	const bool entering = (cosi > 0.f);\n"
"\n"
"	// Compute _sint_ using Snell's law\n"
"	const float eta2 = eta * eta;\n"
"	const float sint2 = (entering ? 1.f / eta2 : eta2) *\n"
"		fmax(0.f, 1.f - cosi * cosi);\n"
"	// Handle total internal reflection\n"
"	if (sint2 >= 1.f)\n"
"		return WHITE;\n"
"	else\n"
"		return FrDiel2(fabs(cosi), sqrt(fmax(0.f, 1.f - sint2)),\n"
"			entering ? eta : 1.f / eta);\n"
"}\n"
; } }
