#include <string>
namespace slg { namespace ocl {
std::string KernelSource_texture_funcs = 
"#line 2 \"texture_funcs.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"
"#ifndef TEXTURE_STACK_SIZE\n"
"#define TEXTURE_STACK_SIZE 16\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// ImageMaps support\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined(PARAM_HAS_IMAGEMAPS)\n"
"\n"
"__global float *ImageMap_GetPixelsAddress(__global float **imageMapBuff,\n"
"		const uint page, const uint offset) {\n"
"	return &imageMapBuff[page][offset];\n"
"}\n"
"\n"
"float ImageMap_GetTexel_Float(__global float *pixels,\n"
"		const uint width, const uint height, const uint channelCount,\n"
"		const int s, const int t) {\n"
"	const uint u = Mod(s, width);\n"
"	const uint v = Mod(t, height);\n"
"\n"
"	const uint index = channelCount * (v * width + u);\n"
"\n"
"	return (channelCount == 1) ? pixels[index] : Spectrum_Y(VLOAD3F(&pixels[index]));\n"
"}\n"
"\n"
"float3 ImageMap_GetTexel_Spectrum(__global float *pixels,\n"
"		const uint width, const uint height, const uint channelCount,\n"
"		const int s, const int t) {\n"
"	const uint u = Mod(s, width);\n"
"	const uint v = Mod(t, height);\n"
"\n"
"	const uint index = channelCount * (v * width + u);\n"
"\n"
"	return (channelCount == 1) ? pixels[index] : VLOAD3F(&pixels[index]);\n"
"}\n"
"\n"
"float ImageMap_GetFloat(__global float *pixels,\n"
"		const uint width, const uint height, const uint channelCount,\n"
"		const float u, const float v) {\n"
"	const float s = u * width - 0.5f;\n"
"	const float t = v * height - 0.5f;\n"
"\n"
"	const int s0 = Floor2Int(s);\n"
"	const int t0 = Floor2Int(t);\n"
"\n"
"	const float ds = s - s0;\n"
"	const float dt = t - t0;\n"
"\n"
"	const float ids = 1.f - ds;\n"
"	const float idt = 1.f - dt;\n"
"\n"
"	const float c0 = ImageMap_GetTexel_Float(pixels, width, height, channelCount, s0, t0);\n"
"	const float c1 = ImageMap_GetTexel_Float(pixels, width, height, channelCount, s0, t0 + 1);\n"
"	const float c2 = ImageMap_GetTexel_Float(pixels, width, height, channelCount, s0 + 1, t0);\n"
"	const float c3 = ImageMap_GetTexel_Float(pixels, width, height, channelCount, s0 + 1, t0 + 1);\n"
"\n"
"	const float k0 = ids * idt;\n"
"	const float k1 = ids * dt;\n"
"	const float k2 = ds * idt;\n"
"	const float k3 = ds * dt;\n"
"\n"
"	return (k0 * c0 + k1 *c1 + k2 * c2 + k3 * c3);\n"
"}\n"
"\n"
"float3 ImageMap_GetSpectrum(__global float *pixels,\n"
"		const uint width, const uint height, const uint channelCount,\n"
"		const float u, const float v) {\n"
"	const float s = u * width - 0.5f;\n"
"	const float t = v * height - 0.5f;\n"
"\n"
"	const int s0 = Floor2Int(s);\n"
"	const int t0 = Floor2Int(t);\n"
"\n"
"	const float ds = s - s0;\n"
"	const float dt = t - t0;\n"
"\n"
"	const float ids = 1.f - ds;\n"
"	const float idt = 1.f - dt;\n"
"\n"
"	const float3 c0 = ImageMap_GetTexel_Spectrum(pixels, width, height, channelCount, s0, t0);\n"
"	const float3 c1 = ImageMap_GetTexel_Spectrum(pixels, width, height, channelCount, s0, t0 + 1);\n"
"	const float3 c2 = ImageMap_GetTexel_Spectrum(pixels, width, height, channelCount, s0 + 1, t0);\n"
"	const float3 c3 = ImageMap_GetTexel_Spectrum(pixels, width, height, channelCount, s0 + 1, t0 + 1);\n"
"\n"
"	const float k0 = ids * idt;\n"
"	const float k1 = ids * dt;\n"
"	const float k2 = ds * idt;\n"
"	const float k3 = ds * dt;\n"
"\n"
"	return (k0 * c0 + k1 *c1 + k2 * c2 + k3 * c3);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// ConstFloat texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_CONST_FLOAT)\n"
"\n"
"void ConstFloatTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = texture->constFloat.value;\n"
"}\n"
"\n"
"void ConstFloatTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = texture->constFloat.value;\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// ConstFloat3 texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_CONST_FLOAT3)\n"
"\n"
"void ConstFloat3Texture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = Spectrum_Y(VLOAD3F(texture->constFloat3.color.c));\n"
"}\n"
"\n"
"void ConstFloat3Texture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = VLOAD3F(texture->constFloat3.color.c);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// ImageMap texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_IMAGEMAP)\n"
"\n"
"void ImageMapTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize\n"
"		IMAGEMAPS_PARAM_DECL) {\n"
"	__global ImageMap *imageMap = &imageMapDescs[texture->imageMapTex.imageMapIndex];\n"
"	__global float *pixels = ImageMap_GetPixelsAddress(\n"
"			imageMapBuff, imageMap->pageIndex, imageMap->pixelsIndex);\n"
"\n"
"	const float2 uv = VLOAD2F(&hitPoint->uv.u);\n"
"	const float2 mapUV = TextureMapping2D_Map(&texture->imageMapTex.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = texture->imageMapTex.gain * ImageMap_GetFloat(\n"
"			pixels,\n"
"			imageMap->width, imageMap->height, imageMap->channelCount,\n"
"			mapUV.s0, mapUV.s1);\n"
"}\n"
"\n"
"void ImageMapTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize\n"
"		IMAGEMAPS_PARAM_DECL) {\n"
"	__global ImageMap *imageMap = &imageMapDescs[texture->imageMapTex.imageMapIndex];\n"
"	__global float *pixels = ImageMap_GetPixelsAddress(\n"
"			imageMapBuff, imageMap->pageIndex, imageMap->pixelsIndex);\n"
"\n"
"	const float2 uv = VLOAD2F(&hitPoint->uv.u);\n"
"	const float2 mapUV = TextureMapping2D_Map(&texture->imageMapTex.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = texture->imageMapTex.gain * ImageMap_GetSpectrum(\n"
"			pixels,\n"
"			imageMap->width, imageMap->height, imageMap->channelCount,\n"
"			mapUV.s0, mapUV.s1);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Scale texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_SCALE)\n"
"\n"
"void ScaleTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float value = texValues[--(*texValuesSize)] * texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = value;\n"
"}\n"
"\n"
"void ScaleTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 value = texValues[--(*texValuesSize)] * texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = value;\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// FresnelApproxN & FresnelApproxK texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_FRESNEL_APPROX_N)\n"
"\n"
"float FresnelApproxN(const float Fr) {\n"
"	const float sqrtReflectance = sqrt(clamp(Fr, 0.f, .999f));\n"
"\n"
"	return (1.f + sqrtReflectance) /\n"
"		(1.f - sqrtReflectance);\n"
"}\n"
"\n"
"float3 FresnelApproxN3(const float3 Fr) {\n"
"	const float3 sqrtReflectance = Spectrum_Sqrt(clamp(Fr, 0.f, .999f));\n"
"\n"
"	return (WHITE + sqrtReflectance) /\n"
"		(WHITE - sqrtReflectance);\n"
"}\n"
"\n"
"void FresnelApproxNTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float value = texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = FresnelApproxN(value);\n"
"}\n"
"\n"
"void FresnelApproxNTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 value = texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = FresnelApproxN3(value);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"#if defined (PARAM_ENABLE_FRESNEL_APPROX_K)\n"
"\n"
"float FresnelApproxK(const float Fr) {\n"
"	const float reflectance = clamp(Fr, 0.f, .999f);\n"
"\n"
"	return 2.f * sqrt(reflectance /\n"
"		(1.f - reflectance));\n"
"}\n"
"\n"
"float3 FresnelApproxK3(const float3 Fr) {\n"
"	const float3 reflectance = clamp(Fr, 0.f, .999f);\n"
"\n"
"	return 2.f * Spectrum_Sqrt(reflectance /\n"
"		(WHITE - reflectance));\n"
"}\n"
"\n"
"void FresnelApproxKTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float value = texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = FresnelApproxK(value);\n"
"}\n"
"\n"
"void FresnelApproxKTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 value = texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = FresnelApproxK3(value);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// CheckerBoard 2D & 3D texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_CHECKERBOARD2D)\n"
"\n"
"void CheckerBoard2DTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float value1 = texValues[--(*texValuesSize)];\n"
"	const float value2 = texValues[--(*texValuesSize)];\n"
"\n"
"	const float2 uv = VLOAD2F(&hitPoint->uv.u);\n"
"	const float2 mapUV = TextureMapping2D_Map(&texture->checkerBoard2D.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = ((Floor2Int(mapUV.s0) + Floor2Int(mapUV.s1)) % 2 == 0) ? value1 : value2;\n"
"}\n"
"\n"
"void CheckerBoard2DTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 value1 = texValues[--(*texValuesSize)];\n"
"	const float3 value2 = texValues[--(*texValuesSize)];\n"
"\n"
"	const float2 uv = VLOAD2F(&hitPoint->uv.u);\n"
"	const float2 mapUV = TextureMapping2D_Map(&texture->checkerBoard2D.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = ((Floor2Int(mapUV.s0) + Floor2Int(mapUV.s1)) % 2 == 0) ? value1 : value2;\n"
"}\n"
"\n"
"#endif\n"
"\n"
"#if defined (PARAM_ENABLE_CHECKERBOARD3D)\n"
"\n"
"void CheckerBoard3DTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float value1 = texValues[--(*texValuesSize)];\n"
"	const float value2 = texValues[--(*texValuesSize)];\n"
"\n"
"	const float3 mapP = TextureMapping3D_Map(&texture->checkerBoard3D.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = ((Floor2Int(mapP.x) + Floor2Int(mapP.y) + Floor2Int(mapP.z)) % 2 == 0) ? value1 : value2;\n"
"}\n"
"\n"
"void CheckerBoard3DTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 value1 = texValues[--(*texValuesSize)];\n"
"	const float3 value2 = texValues[--(*texValuesSize)];\n"
"\n"
"	const float3 mapP = TextureMapping3D_Map(&texture->checkerBoard3D.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = ((Floor2Int(mapP.x) + Floor2Int(mapP.y) + Floor2Int(mapP.z)) % 2 == 0) ? value1 : value2;\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Mix texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_MIX)\n"
"\n"
"void MixTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float amt = clamp(texValues[--(*texValuesSize)], 0.f, 1.f);;\n"
"	const float value1 = texValues[--(*texValuesSize)];\n"
"	const float value2 = texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = Lerp(amt, value1, value2);\n"
"}\n"
"\n"
"void MixTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 amt = clamp(texValues[--(*texValuesSize)], 0.f, 1.f);\n"
"	const float3 value1 = texValues[--(*texValuesSize)];\n"
"	const float3 value2 = texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = mix(value1, value2, amt);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// FBM texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_FBM_TEX)\n"
"\n"
"void FBMTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 mapP = TextureMapping3D_Map(&texture->fbm.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = FBm(mapP, texture->fbm.omega, texture->fbm.octaves);\n"
"}\n"
"\n"
"void FBMTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 mapP = TextureMapping3D_Map(&texture->fbm.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = FBm(mapP, texture->fbm.omega, texture->fbm.octaves);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Marble texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_MARBLE)\n"
"\n"
"// Evaluate marble spline at _t_\n"
"__constant float MarbleTexture_c[9][3] = {\n"
"	{ .58f, .58f, .6f},\n"
"	{ .58f, .58f, .6f},\n"
"	{ .58f, .58f, .6f},\n"
"	{ .5f, .5f, .5f},\n"
"	{ .6f, .59f, .58f},\n"
"	{ .58f, .58f, .6f},\n"
"	{ .58f, .58f, .6f},\n"
"	{.2f, .2f, .33f},\n"
"	{ .58f, .58f, .6f}\n"
"};\n"
"\n"
"float3 MarbleTexture_Evaluate(__global Texture *texture, __global HitPoint *hitPoint) {\n"
"	const float3 P = texture->marble.scale * TextureMapping3D_Map(&texture->marble.mapping, hitPoint);\n"
"\n"
"	float marble = P.y + texture->marble.variation * FBm(P, texture->marble.omega, texture->marble.octaves);\n"
"	float t = .5f + .5f * sin(marble);\n"
"#define NC  sizeof(MarbleTexture_c) / sizeof(MarbleTexture_c[0])\n"
"#define NSEG (NC-3)\n"
"	const int first = Floor2Int(t * NSEG);\n"
"	t = (t * NSEG - first);\n"
"#undef NC\n"
"#undef NSEG\n"
"#define ASSIGN_CF3(a) (float3)(a[0], a[1], a[2])\n"
"	const float3 c0 = ASSIGN_CF3(MarbleTexture_c[first]);\n"
"	const float3 c1 = ASSIGN_CF3(MarbleTexture_c[first + 1]);\n"
"	const float3 c2 = ASSIGN_CF3(MarbleTexture_c[first + 2]);\n"
"	const float3 c3 = ASSIGN_CF3(MarbleTexture_c[first + 3]);\n"
"#undef ASSIGN_CF3\n"
"	// Bezier spline evaluated with de Castilejau's algorithm	\n"
"	float3 s0 = mix(c0, c1, t);\n"
"	float3 s1 = mix(c1, c2, t);\n"
"	float3 s2 = mix(c2, c3, t);\n"
"	s0 = mix(s0, s1, t);\n"
"	s1 = mix(s1, s2, t);\n"
"	// Extra scale of 1.5 to increase variation among colors\n"
"	return 1.5f * mix(s0, s1, t);\n"
"}\n"
"\n"
"void MarbleTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = Spectrum_Y(MarbleTexture_Evaluate(texture, hitPoint));\n"
"}\n"
"\n"
"void MarbleTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = MarbleTexture_Evaluate(texture, hitPoint);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Dots texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_DOTS)\n"
"\n"
"void DotsTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float value1 = texValues[--(*texValuesSize)];\n"
"	const float value2 = texValues[--(*texValuesSize)];\n"
"\n"
"	const float2 uv = TextureMapping2D_Map(&texture->dots.mapping, hitPoint);\n"
"\n"
"	const int sCell = Floor2Int(uv.s0 + .5f);\n"
"	const int tCell = Floor2Int(uv.s1 + .5f);\n"
"	// Return _insideDot_ result if point is inside dot\n"
"	if (Noise(sCell + .5f, tCell + .5f, .5f) > 0.f) {\n"
"		const float radius = .35f;\n"
"		const float maxShift = 0.5f - radius;\n"
"		const float sCenter = sCell + maxShift *\n"
"			Noise(sCell + 1.5f, tCell + 2.8f, .5f);\n"
"		const float tCenter = tCell + maxShift *\n"
"			Noise(sCell + 4.5f, tCell + 9.8f, .5f);\n"
"		const float ds = uv.s0 - sCenter, dt = uv.s1 - tCenter;\n"
"		if (ds * ds + dt * dt < radius * radius) {\n"
"			texValues[(*texValuesSize)++] = value1;\n"
"			return;\n"
"		}\n"
"	}\n"
"\n"
"	texValues[(*texValuesSize)++] = value2;\n"
"}\n"
"\n"
"void DotsTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 value1 = texValues[--(*texValuesSize)];\n"
"	const float3 value2 = texValues[--(*texValuesSize)];\n"
"\n"
"	const float2 uv = TextureMapping2D_Map(&texture->dots.mapping, hitPoint);\n"
"\n"
"	const int sCell = Floor2Int(uv.s0 + .5f);\n"
"	const int tCell = Floor2Int(uv.s1 + .5f);\n"
"	// Return _insideDot_ result if point is inside dot\n"
"	if (Noise(sCell + .5f, tCell + .5f, .5f) > 0.f) {\n"
"		const float radius = .35f;\n"
"		const float maxShift = 0.5f - radius;\n"
"		const float sCenter = sCell + maxShift *\n"
"			Noise(sCell + 1.5f, tCell + 2.8f, .5f);\n"
"		const float tCenter = tCell + maxShift *\n"
"			Noise(sCell + 4.5f, tCell + 9.8f, .5f);\n"
"		const float ds = uv.s0 - sCenter, dt = uv.s1 - tCenter;\n"
"		if (ds * ds + dt * dt < radius * radius) {\n"
"			texValues[(*texValuesSize)++] = value1;\n"
"			return;\n"
"		}\n"
"	}\n"
"\n"
"	texValues[(*texValuesSize)++] = value2;\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Brick texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_BRICK)\n"
"\n"
"bool BrickTexture_RunningAlternate(__global Texture *texture, const float3 p, float3 *i, float3 *b,\n"
"		int nWhole) {\n"
"	const float run = texture->brick.run;\n"
"	const float mortarwidth = texture->brick.mortarwidth;\n"
"	const float mortarheight = texture->brick.mortarheight;\n"
"	const float mortardepth = texture->brick.mortardepth;\n"
"\n"
"	const float sub = nWhole + 0.5f;\n"
"	const float rsub = ceil(sub);\n"
"	(*i).z = floor(p.z);\n"
"	(*b).x = (p.x + (*i).z * run) / sub;\n"
"	(*b).y = (p.y + (*i).z * run) / sub;\n"
"	(*i).x = floor((*b).x);\n"
"	(*i).y = floor((*b).y);\n"
"	(*b).x = ((*b).x - (*i).x) * sub;\n"
"	(*b).y = ((*b).y - (*i).y) * sub;\n"
"	(*b).z = (p.z - (*i).z) * sub;\n"
"	(*i).x += floor((*b).x) / rsub;\n"
"	(*i).y += floor((*b).y) / rsub;\n"
"	(*b).x -= floor((*b).x);\n"
"	(*b).y -= floor((*b).y);\n"
"	return (*b).z > mortarheight && (*b).y > mortardepth &&\n"
"		(*b).x > mortarwidth;\n"
"}\n"
"\n"
"bool BrickTexture_Basket(__global Texture *texture, const float3 p, float3 *i) {\n"
"	const float mortarwidth = texture->brick.mortarwidth;\n"
"	const float mortardepth = texture->brick.mortardepth;\n"
"	const float proportion = texture->brick.proportion;\n"
"	const float invproportion = texture->brick.invproportion;\n"
"\n"
"	(*i).x = floor(p.x);\n"
"	(*i).y = floor(p.y);\n"
"	float bx = p.x - (*i).x;\n"
"	float by = p.y - (*i).y;\n"
"	(*i).x += (*i).y - 2.f * floor(0.5f * (*i).y);\n"
"	const bool split = ((*i).x - 2.f * floor(0.5f * (*i).x)) < 1.f;\n"
"	if (split) {\n"
"		bx = fmod(bx, invproportion);\n"
"		(*i).x = floor(proportion * p.x) * invproportion;\n"
"	} else {\n"
"		by = fmod(by, invproportion);\n"
"		(*i).y = floor(proportion * p.y) * invproportion;\n"
"	}\n"
"	return by > mortardepth && bx > mortarwidth;\n"
"}\n"
"\n"
"bool BrickTexture_Herringbone(__global Texture *texture, const float3 p, float3 *i) {\n"
"	const float mortarwidth = texture->brick.mortarwidth;\n"
"	const float mortarheight = texture->brick.mortarheight;\n"
"	const float proportion = texture->brick.proportion;\n"
"	const float invproportion = texture->brick.invproportion;\n"
"\n"
"	(*i).y = floor(proportion * p.y);\n"
"	const float px = p.x + (*i).y * invproportion;\n"
"	(*i).x = floor(px);\n"
"	float bx = 0.5f * px - floor(px * 0.5f);\n"
"	bx *= 2.f;\n"
"	float by = proportion * p.y - floor(proportion * p.y);\n"
"	by *= invproportion;\n"
"	if (bx > 1.f + invproportion) {\n"
"		bx = proportion * (bx - 1.f);\n"
"		(*i).y -= floor(bx - 1.f);\n"
"		bx -= floor(bx);\n"
"		bx *= invproportion;\n"
"		by = 1.f;\n"
"	} else if (bx > 1.f) {\n"
"		bx = proportion * (bx - 1.f);\n"
"		(*i).y -= floor(bx - 1.f);\n"
"		bx -= floor(bx);\n"
"		bx *= invproportion;\n"
"	}\n"
"	return by > mortarheight && bx > mortarwidth;\n"
"}\n"
"\n"
"bool BrickTexture_Running(__global Texture *texture, const float3 p, float3 *i, float3 *b) {\n"
"	const float run = texture->brick.run;\n"
"	const float mortarwidth = texture->brick.mortarwidth;\n"
"	const float mortarheight = texture->brick.mortarheight;\n"
"	const float mortardepth = texture->brick.mortardepth;\n"
"\n"
"	(*i).z = floor(p.z);\n"
"	(*b).x = p.x + (*i).z * run;\n"
"	(*b).y = p.y - (*i).z * run;\n"
"	(*i).x = floor((*b).x);\n"
"	(*i).y = floor((*b).y);\n"
"	(*b).z = p.z - (*i).z;\n"
"	(*b).x -= (*i).x;\n"
"	(*b).y -= (*i).y;\n"
"	return (*b).z > mortarheight && (*b).y > mortardepth &&\n"
"		(*b).x > mortarwidth;\n"
"}\n"
"\n"
"bool BrickTexture_English(__global Texture *texture, const float3 p, float3 *i, float3 *b) {\n"
"	const float run = texture->brick.run;\n"
"	const float mortarwidth = texture->brick.mortarwidth;\n"
"	const float mortarheight = texture->brick.mortarheight;\n"
"	const float mortardepth = texture->brick.mortardepth;\n"
"\n"
"	(*i).z = floor(p.z);\n"
"	(*b).x = p.x + (*i).z * run;\n"
"	(*b).y = p.y - (*i).z * run;\n"
"	(*i).x = floor((*b).x);\n"
"	(*i).y = floor((*b).y);\n"
"	(*b).z = p.z - (*i).z;\n"
"	const float divider = floor(fmod(fabs((*i).z), 2.f)) + 1.f;\n"
"	(*b).x = (divider * (*b).x - floor(divider * (*b).x)) / divider;\n"
"	(*b).y = (divider * (*b).y - floor(divider * (*b).y)) / divider;\n"
"	return (*b).z > mortarheight && (*b).y > mortardepth &&\n"
"		(*b).x > mortarwidth;\n"
"}\n"
"\n"
"bool BrickTexture_Evaluate(__global Texture *texture, __global HitPoint *hitPoint) {\n"
"#define BRICK_EPSILON 1e-3f\n"
"	const float3 P = TextureMapping3D_Map(&texture->brick.mapping, hitPoint);\n"
"\n"
"	const float offs = BRICK_EPSILON + texture->brick.mortarsize;\n"
"	float3 bP = P + (float3)(offs, offs, offs);\n"
"\n"
"	// Normalize coordinates according brick dimensions\n"
"	bP.x /= texture->brick.brickwidth;\n"
"	bP.y /= texture->brick.brickdepth;\n"
"	bP.z /= texture->brick.brickheight;\n"
"\n"
"	bP += VLOAD3F(&texture->brick.offsetx);\n"
"\n"
"	float3 brickIndex;\n"
"	float3 bevel;\n"
"	bool b;\n"
"	switch (texture->brick.bond) {\n"
"		case FLEMISH:\n"
"			b = BrickTexture_RunningAlternate(texture, bP, &brickIndex, &bevel, 1);\n"
"			break;\n"
"		case RUNNING:\n"
"			b = BrickTexture_Running(texture, bP, &brickIndex, &bevel);\n"
"			break;\n"
"		case ENGLISH:\n"
"			b = BrickTexture_English(texture, bP, &brickIndex, &bevel);\n"
"			break;\n"
"		case HERRINGBONE:\n"
"			b = BrickTexture_Herringbone(texture, bP, &brickIndex);\n"
"			break;\n"
"		case BASKET:\n"
"			b = BrickTexture_Basket(texture, bP, &brickIndex);\n"
"			break;\n"
"		case KETTING:\n"
"			b = BrickTexture_RunningAlternate(texture, bP, &brickIndex, &bevel, 2);\n"
"			break; \n"
"		default:\n"
"			b = true;\n"
"			break;\n"
"	}\n"
"\n"
"	return b;\n"
"#undef BRICK_EPSILON\n"
"}\n"
"\n"
"void BrickTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float value1 = texValues[--(*texValuesSize)];\n"
"	const float value2 = texValues[--(*texValuesSize)];\n"
"	const float value3 = texValues[--(*texValuesSize)];\n"
"\n"
"	if (BrickTexture_Evaluate(texture, hitPoint))\n"
"		texValues[(*texValuesSize)++] = value1 * value3;\n"
"	else\n"
"		texValues[(*texValuesSize)++] = value2;\n"
"}\n"
"\n"
"void BrickTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 value1 = texValues[--(*texValuesSize)];\n"
"	const float3 value2 = texValues[--(*texValuesSize)];\n"
"	const float3 value3 = texValues[--(*texValuesSize)];\n"
"\n"
"	if (BrickTexture_Evaluate(texture, hitPoint))\n"
"		texValues[(*texValuesSize)++] = value1 * value3;\n"
"	else\n"
"		texValues[(*texValuesSize)++] = value2;\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Add texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_ADD)\n"
"\n"
"void AddTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float value = texValues[--(*texValuesSize)] + texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = value;\n"
"}\n"
"\n"
"void AddTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 value = texValues[--(*texValuesSize)] + texValues[--(*texValuesSize)];\n"
"\n"
"	texValues[(*texValuesSize)++] = value;\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Windy texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_WINDY)\n"
"\n"
"void WindyTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 mapP = TextureMapping3D_Map(&texture->windy.mapping, hitPoint);\n"
"\n"
"	const float windStrength = FBm(.1f * mapP, .5f, 3);\n"
"	const float waveHeight = FBm(mapP, .5f, 6);\n"
"\n"
"	texValues[(*texValuesSize)++] = fabs(windStrength) * waveHeight;\n"
"}\n"
"\n"
"void WindyTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 mapP = TextureMapping3D_Map(&texture->windy.mapping, hitPoint);\n"
"\n"
"	const float windStrength = FBm(.1f * mapP, .5f, 3);\n"
"	const float waveHeight = FBm(mapP, .5f, 6);\n"
"\n"
"	texValues[(*texValuesSize)++] = fabs(windStrength) * waveHeight;\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Wrinkled texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_WRINKLED)\n"
"\n"
"void WrinkledTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 mapP = TextureMapping3D_Map(&texture->wrinkled.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = Turbulence(mapP, texture->wrinkled.omega, texture->wrinkled.octaves);\n"
"}\n"
"\n"
"void WrinkledTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float3 mapP = TextureMapping3D_Map(&texture->wrinkled.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = Turbulence(mapP, texture->wrinkled.omega, texture->wrinkled.octaves);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// UV texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_UV)\n"
"\n"
"void UVTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float2 uv = TextureMapping2D_Map(&texture->uvTex.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = Spectrum_Y((float3)(uv.s0 - Floor2Int(uv.s0), uv.s1 - Floor2Int(uv.s1), 0.f));\n"
"}\n"
"\n"
"void UVTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float2 uv = TextureMapping2D_Map(&texture->uvTex.mapping, hitPoint);\n"
"\n"
"	texValues[(*texValuesSize)++] = (float3)(uv.s0 - Floor2Int(uv.s0), uv.s1 - Floor2Int(uv.s1), 0.f);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Band texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_BAND)\n"
"\n"
"void BandTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float a = clamp(texValues[--(*texValuesSize)], 0.f, 1.f);\n"
"\n"
"	const uint last = texture->band.size - 1;\n"
"	if (a < texture->band.offsets[0])\n"
"		texValues[(*texValuesSize)++] = Spectrum_Y(VLOAD3F(texture->band.values[0].c));\n"
"	else if (a >= texture->band.offsets[last])\n"
"		texValues[(*texValuesSize)++] = Spectrum_Y(VLOAD3F(texture->band.values[last].c));\n"
"	else {\n"
"		uint p = 0;\n"
"		for (; p <= last; ++p) {\n"
"			if (a < texture->band.offsets[p])\n"
"				break;\n"
"		}\n"
"\n"
"		const float p1 = Spectrum_Y(VLOAD3F(texture->band.values[p - 1].c));\n"
"		const float p0 = Spectrum_Y(VLOAD3F(texture->band.values[p].c));\n"
"		const float o1 = texture->band.offsets[p - 1];\n"
"		const float o0 = texture->band.offsets[p];\n"
"		texValues[(*texValuesSize)++] = Lerp((a - o1) / (o0 - o1), p1, p0);\n"
"	}\n"
"}\n"
"\n"
"void BandTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float a = clamp(Spectrum_Y(texValues[--(*texValuesSize)]), 0.f, 1.f);\n"
"\n"
"	const uint last = texture->band.size - 1;\n"
"	if (a < texture->band.offsets[0])\n"
"		texValues[(*texValuesSize)++] = VLOAD3F(texture->band.values[0].c);\n"
"	else if (a >= texture->band.offsets[last])\n"
"		texValues[(*texValuesSize)++] = VLOAD3F(texture->band.values[last].c);\n"
"	else {\n"
"		uint p = 0;\n"
"		for (; p <= last; ++p) {\n"
"			if (a < texture->band.offsets[p])\n"
"				break;\n"
"		}\n"
"\n"
"		const float3 p1 = VLOAD3F(texture->band.values[p - 1].c);\n"
"		const float3 p0 = VLOAD3F(texture->band.values[p].c);\n"
"		const float o1 = texture->band.offsets[p - 1];\n"
"		const float o0 = texture->band.offsets[p];\n"
"		texValues[(*texValuesSize)++] = Lerp3((a - o1) / (o0 - o1), p1, p0);\n"
"	}\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// HitPointColor texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_HITPOINTCOLOR)\n"
"\n"
"void HitPointColorTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = Spectrum_Y(VLOAD3F(hitPoint->color.c));\n"
"}\n"
"\n"
"void HitPointColorTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = VLOAD3F(hitPoint->color.c);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// HitPointAlpha texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_HITPOINTALPHA)\n"
"\n"
"void HitPointAlphaTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = hitPoint->alpha;\n"
"}\n"
"\n"
"void HitPointAlphaTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const float alpha = hitPoint->alpha;\n"
"	texValues[(*texValuesSize)++] = (float3)(alpha, alpha, alpha);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// HitPointGrey texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_HITPOINTGREY)\n"
"\n"
"void HitPointGreyTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const uint channel = texture->hitPointGrey.channel;\n"
"	switch (channel) {\n"
"		case 0:\n"
"			texValues[*texValuesSize] = hitPoint->color.c[0];\n"
"			break;\n"
"		case 1:\n"
"			texValues[*texValuesSize] = hitPoint->color.c[1];\n"
"			break;\n"
"		case 2:\n"
"			texValues[*texValuesSize] = hitPoint->color.c[2];\n"
"			break;\n"
"		default:\n"
"			texValues[*texValuesSize] = Spectrum_Y(VLOAD3F(hitPoint->color.c));\n"
"			break;\n"
"	}\n"
"\n"
"	++(*texValuesSize);\n"
"}\n"
"\n"
"void HitPointGreyTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	const uint channel = texture->hitPointGrey.channel;\n"
"	float v;\n"
"	switch (channel) {\n"
"		case 0:\n"
"			v = hitPoint->color.c[0];\n"
"			break;\n"
"		case 1:\n"
"			v = hitPoint->color.c[1];\n"
"			break;\n"
"		case 2:\n"
"			v = hitPoint->color.c[2];\n"
"			break;\n"
"		default:\n"
"			v = Spectrum_Y(VLOAD3F(hitPoint->color.c));\n"
"			break;\n"
"	}\n"
"\n"
"	texValues[(*texValuesSize)++] = (float3)(v, v, v);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// NormalMap texture\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_NORMALMAP)\n"
"\n"
"void NormalMapTexture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"    texValues[*texValuesSize] = 0.f;\n"
"	++(*texValuesSize);\n"
"}\n"
"\n"
"void NormalMapTexture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize) {\n"
"	texValues[(*texValuesSize)++] = (float3)(0.f, 0.f, 0.f);\n"
"}\n"
"\n"
"#endif\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Generic texture functions with support for recursive textures\n"
"//------------------------------------------------------------------------------\n"
"\n"
"uint Texture_AddSubTexture(__global Texture *texture,\n"
"		__global Texture *todoTex[TEXTURE_STACK_SIZE], uint *todoTexSize\n"
"		TEXTURES_PARAM_DECL) {\n"
"	switch (texture->type) {\n"
"#if defined(PARAM_ENABLE_TEX_SCALE)\n"
"		case SCALE_TEX:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->scaleTex.tex1Index];\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->scaleTex.tex2Index];\n"
"			return 2;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_FRESNEL_APPROX_N)\n"
"		case FRESNEL_APPROX_N:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->fresnelApproxN.texIndex];\n"
"			return 1;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_FRESNEL_APPROX_K)\n"
"		case FRESNEL_APPROX_K:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->fresnelApproxK.texIndex];\n"
"			return 1;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_CHECKERBOARD2D)\n"
"		case CHECKERBOARD2D:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->checkerBoard2D.tex1Index];\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->checkerBoard2D.tex2Index];\n"
"			return 2;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_CHECKERBOARD3D)\n"
"		case CHECKERBOARD3D:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->checkerBoard3D.tex1Index];\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->checkerBoard3D.tex2Index];\n"
"			return 2;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_TEX_MIX)\n"
"		case MIX_TEX:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->mixTex.amountTexIndex];\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->mixTex.tex1Index];\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->mixTex.tex2Index];\n"
"			return 3;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_DOTS)\n"
"		case DOTS:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->dots.insideIndex];\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->dots.outsideIndex];\n"
"			return 2;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_BRICK)\n"
"		case BRICK:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->brick.tex1Index];\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->brick.tex2Index];\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->brick.tex3Index];\n"
"			return 3;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_ADD)\n"
"		case ADD_TEX:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->addTex.tex1Index];\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->addTex.tex2Index];\n"
"			return 2;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_TEX_BAND)\n"
"		case BAND_TEX:\n"
"			todoTex[(*todoTexSize)++] = &texs[texture->band.amountTexIndex];\n"
"			return 1;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_TEX_NORMALMAP)\n"
"		case NORMALMAP_TEX:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_TEX_HITPOINTGREY)\n"
"		case HITPOINTGREY:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_TEX_HITPOINTALPHA)\n"
"		case HITPOINTALPHA:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_TEX_HITPOINTCOLOR)\n"
"		case HITPOINTCOLOR:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_TEX_UV)\n"
"		case UV_TEX:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_WRINKLED)\n"
"		case WRINKLED:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_BLENDER_WOOD)\n"
"		case BLENDER_WOOD:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_BLENDER_CLOUDS)\n"
"		case BLENDER_CLOUDS:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_WINDY)\n"
"		case WINDY:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_MARBLE)\n"
"		case MARBLE:\n"
"#endif\n"
"#if defined (PARAM_ENABLE_FBM_TEX)\n"
"		case FBM_TEX:\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_CONST_FLOAT)\n"
"		case CONST_FLOAT:\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_CONST_FLOAT3)\n"
"		case CONST_FLOAT3:\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_IMAGEMAP)\n"
"		case IMAGEMAP:\n"
"#endif\n"
"		default:\n"
"			return 0;\n"
"	}\n"
"}\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Float texture channel\n"
"//------------------------------------------------------------------------------\n"
"\n"
"void Texture_EvaluateFloat(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float texValues[TEXTURE_STACK_SIZE], uint *texValuesSize\n"
"		IMAGEMAPS_PARAM_DECL) {\n"
"	switch (texture->type) {\n"
"#if defined(PARAM_ENABLE_TEX_CONST_FLOAT)\n"
"		case CONST_FLOAT:\n"
"			ConstFloatTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_CONST_FLOAT3)\n"
"		case CONST_FLOAT3:\n"
"			ConstFloat3Texture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_IMAGEMAP)\n"
"		case IMAGEMAP:\n"
"			ImageMapTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize\n"
"					IMAGEMAPS_PARAM);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_SCALE)\n"
"		case SCALE_TEX:\n"
"			ScaleTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_FRESNEL_APPROX_N)\n"
"		case FRESNEL_APPROX_N:\n"
"			FresnelApproxNTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_FRESNEL_APPROX_K)\n"
"		case FRESNEL_APPROX_K:\n"
"			FresnelApproxKTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_CHECKERBOARD2D)\n"
"		case CHECKERBOARD2D:\n"
"			CheckerBoard2DTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_CHECKERBOARD3D)\n"
"		case CHECKERBOARD3D:\n"
"			CheckerBoard3DTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_TEX_MIX)\n"
"		case MIX_TEX:\n"
"			MixTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_FBM_TEX)\n"
"		case FBM_TEX:\n"
"			FBMTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_MARBLE)\n"
"		case MARBLE:\n"
"			MarbleTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_DOTS)\n"
"		case DOTS:\n"
"			DotsTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_BRICK)\n"
"		case BRICK:\n"
"			BrickTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_ADD)\n"
"		case ADD_TEX:\n"
"			AddTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_WINDY)\n"
"		case WINDY:\n"
"			WindyTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_BLENDER_CLOUDS)\n"
"		case BLENDER_CLOUDS:\n"
"			BlenderCloudsTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_BLENDER_WOOD)\n"
"		case BLENDER_WOOD:\n"
"			BlenderWoodTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_WRINKLED)\n"
"		case WRINKLED:\n"
"			WrinkledTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_UV)\n"
"		case UV_TEX:\n"
"			UVTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_BAND)\n"
"		case BAND_TEX:\n"
"			BandTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_HITPOINTCOLOR)\n"
"		case HITPOINTCOLOR:\n"
"			HitPointColorTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_HITPOINTALPHA)\n"
"		case HITPOINTALPHA:\n"
"			HitPointAlphaTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_HITPOINTGREY)\n"
"		case HITPOINTGREY:\n"
"			HitPointGreyTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_NORMALMAP)\n"
"		case NORMALMAP_TEX:\n"
"			NormalMapTexture_EvaluateFloat(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"		default:\n"
"			// Do nothing\n"
"			break;\n"
"	}\n"
"}\n"
"\n"
"float Texture_GetFloatValue(__global Texture *texture, __global HitPoint *hitPoint\n"
"		TEXTURES_PARAM_DECL) {\n"
"	__global Texture *todoTex[TEXTURE_STACK_SIZE];\n"
"	uint todoTexSize = 0;\n"
"\n"
"	__global Texture *pendingTex[TEXTURE_STACK_SIZE];\n"
"	uint targetTexCount[TEXTURE_STACK_SIZE];\n"
"	uint pendingTexSize = 0;\n"
"\n"
"	float texValues[TEXTURE_STACK_SIZE];\n"
"	uint texValuesSize = 0;\n"
"\n"
"	const uint subTexCount = Texture_AddSubTexture(texture, todoTex, &todoTexSize\n"
"			TEXTURES_PARAM);\n"
"	if (subTexCount == 0) {\n"
"		// A fast path for evaluating non recursive textures\n"
"		Texture_EvaluateFloat(texture, hitPoint, texValues, &texValuesSize\n"
"			IMAGEMAPS_PARAM);\n"
"	} else {\n"
"		// Normal complex path for evaluating non recursive textures\n"
"		pendingTex[pendingTexSize] = texture;\n"
"		targetTexCount[pendingTexSize++] = subTexCount;\n"
"		do {\n"
"			if ((pendingTexSize > 0) && (texValuesSize == targetTexCount[pendingTexSize - 1])) {\n"
"				// Pop the a texture to do\n"
"				__global Texture *tex = pendingTex[--pendingTexSize];\n"
"\n"
"				Texture_EvaluateFloat(tex, hitPoint, texValues, &texValuesSize\n"
"						IMAGEMAPS_PARAM);\n"
"				continue;\n"
"			}\n"
"\n"
"			if (todoTexSize > 0) {\n"
"				// Pop the a texture to do\n"
"				__global Texture *tex = todoTex[--todoTexSize];\n"
"\n"
"				// Add this texture to the list of pending one\n"
"				const uint subTexCount = Texture_AddSubTexture(tex, todoTex, &todoTexSize\n"
"						TEXTURES_PARAM);\n"
"				pendingTex[pendingTexSize] = tex;\n"
"				targetTexCount[pendingTexSize++] = subTexCount + texValuesSize;\n"
"			}\n"
"		} while ((todoTexSize > 0) || (pendingTexSize > 0));\n"
"	}\n"
"\n"
"	return texValues[0];\n"
"}\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Color texture channel\n"
"//------------------------------------------------------------------------------\n"
"\n"
"void Texture_EvaluateSpectrum(__global Texture *texture, __global HitPoint *hitPoint,\n"
"		float3 texValues[TEXTURE_STACK_SIZE], uint *texValuesSize\n"
"		IMAGEMAPS_PARAM_DECL) {\n"
"	switch (texture->type) {\n"
"#if defined(PARAM_ENABLE_TEX_CONST_FLOAT)\n"
"		case CONST_FLOAT:\n"
"			ConstFloatTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_CONST_FLOAT3)\n"
"		case CONST_FLOAT3:\n"
"			ConstFloat3Texture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_IMAGEMAP)\n"
"		case IMAGEMAP:\n"
"			ImageMapTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize\n"
"					IMAGEMAPS_PARAM);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_SCALE)\n"
"		case SCALE_TEX:\n"
"			ScaleTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_FRESNEL_APPROX_N)\n"
"		case FRESNEL_APPROX_N:\n"
"			FresnelApproxNTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_FRESNEL_APPROX_K)\n"
"		case FRESNEL_APPROX_K:\n"
"			FresnelApproxKTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_CHECKERBOARD2D)\n"
"		case CHECKERBOARD2D:\n"
"			CheckerBoard2DTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_CHECKERBOARD3D)\n"
"		case CHECKERBOARD3D:\n"
"			CheckerBoard3DTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_TEX_MIX)\n"
"		case MIX_TEX:\n"
"			MixTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_FBM_TEX)\n"
"		case FBM_TEX:\n"
"			FBMTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_MARBLE)\n"
"		case MARBLE:\n"
"			MarbleTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_DOTS)\n"
"		case DOTS:\n"
"			DotsTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_BRICK)\n"
"		case BRICK:\n"
"			BrickTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_ADD)\n"
"		case ADD_TEX:\n"
"			AddTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_WINDY)\n"
"		case WINDY:\n"
"			WindyTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_BLENDER_CLOUDS)\n"
"		case BLENDER_CLOUDS:\n"
"			BlenderCloudsTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined (PARAM_ENABLE_BLENDER_WOOD)\n"
"		case BLENDER_WOOD:\n"
"			BlenderWoodTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_WRINKLED)\n"
"		case WRINKLED:\n"
"			WrinkledTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_UV)\n"
"		case UV_TEX:\n"
"			UVTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_BAND)\n"
"		case BAND_TEX:\n"
"			BandTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_HITPOINTCOLOR)\n"
"		case HITPOINTCOLOR:\n"
"			HitPointColorTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_HITPOINTALPHA)\n"
"		case HITPOINTALPHA:\n"
"			HitPointAlphaTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_HITPOINTGREY)\n"
"		case HITPOINTGREY:\n"
"			HitPointGreyTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_NORMALMAP)\n"
"		case NORMALMAP_TEX:\n"
"			NormalMapTexture_EvaluateSpectrum(texture, hitPoint, texValues, texValuesSize);\n"
"			break;\n"
"#endif\n"
"		default:\n"
"			// Do nothing\n"
"			break;\n"
"	}\n"
"}\n"
"\n"
"float3 Texture_GetSpectrumValue(__global Texture *texture, __global HitPoint *hitPoint\n"
"		TEXTURES_PARAM_DECL) {\n"
"	__global Texture *todoTex[TEXTURE_STACK_SIZE];\n"
"	uint todoTexSize = 0;\n"
"\n"
"	__global Texture *pendingTex[TEXTURE_STACK_SIZE];\n"
"	uint targetTexCount[TEXTURE_STACK_SIZE];\n"
"	uint pendingTexSize = 0;\n"
"\n"
"	float3 texValues[TEXTURE_STACK_SIZE];\n"
"	uint texValuesSize = 0;\n"
"\n"
"	const uint subTexCount = Texture_AddSubTexture(texture, todoTex, &todoTexSize\n"
"			TEXTURES_PARAM);\n"
"	if (subTexCount == 0) {\n"
"		// A fast path for evaluating non recursive textures\n"
"		Texture_EvaluateSpectrum(texture, hitPoint, texValues, &texValuesSize\n"
"			IMAGEMAPS_PARAM);\n"
"	} else {\n"
"		// Normal complex path for evaluating non recursive textures\n"
"		pendingTex[pendingTexSize] = texture;\n"
"		targetTexCount[pendingTexSize++] = subTexCount;\n"
"		do {\n"
"			if ((pendingTexSize > 0) && (texValuesSize == targetTexCount[pendingTexSize - 1])) {\n"
"				// Pop the a texture to do\n"
"				__global Texture *tex = pendingTex[--pendingTexSize];\n"
"\n"
"				Texture_EvaluateSpectrum(tex, hitPoint, texValues, &texValuesSize\n"
"						IMAGEMAPS_PARAM);\n"
"				continue;\n"
"			}\n"
"\n"
"			if (todoTexSize > 0) {\n"
"				// Pop the a texture to do\n"
"				__global Texture *tex = todoTex[--todoTexSize];\n"
"\n"
"				// Add this texture to the list of pending one\n"
"				const uint subTexCount = Texture_AddSubTexture(tex, todoTex, &todoTexSize\n"
"						TEXTURES_PARAM);\n"
"				pendingTex[pendingTexSize] = tex;\n"
"				targetTexCount[pendingTexSize++] = subTexCount + texValuesSize;\n"
"			}\n"
"		} while ((todoTexSize > 0) || (pendingTexSize > 0));\n"
"	}\n"
"\n"
"	return texValues[0];\n"
"}\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Duv texture information\n"
"//------------------------------------------------------------------------------\n"
"\n"
"#if defined(PARAM_HAS_BUMPMAPS)\n"
"float2 Texture_GetDuv(\n"
"        __global Texture *texture,\n"
"        __global HitPoint *hitPoint,\n"
"        const float3 dpdu, const float3 dpdv,\n"
"        const float3 dndu, const float3 dndv,\n"
"        const float sampleDistance\n"
"        TEXTURES_PARAM_DECL) {\n"
"    // Calculate bump map value at intersection point\n"
"    const float base = Texture_GetFloatValue(texture, hitPoint\n"
"			TEXTURES_PARAM);\n"
"\n"
"    // Compute offset positions and evaluate displacement texture\n"
"    const float3 origP = VLOAD3F(&hitPoint->p.x);\n"
"    const float3 origShadeN = VLOAD3F(&hitPoint->shadeN.x);\n"
"    const float2 origUV = VLOAD2F(&hitPoint->uv.u);\n"
"\n"
"    float2 duv;\n"
"\n"
"    // Shift hitPointTmp.du in the u direction and calculate value\n"
"    const float uu = sampleDistance / length(dpdu);\n"
"    VSTORE3F(origP + uu * dpdu, &hitPoint->p.x);\n"
"    hitPoint->uv.u += uu;\n"
"    VSTORE3F(normalize(origShadeN + uu * dndu), &hitPoint->shadeN.x);\n"
"    const float duValue = Texture_GetFloatValue(texture, hitPoint\n"
"			TEXTURES_PARAM);\n"
"    duv.s0 = (duValue - base) / uu;\n"
"\n"
"    // Shift hitPointTmp.dv in the v direction and calculate value\n"
"    const float vv = sampleDistance / length(dpdv);\n"
"    VSTORE3F(origP + vv * dpdv, &hitPoint->p.x);\n"
"    hitPoint->uv.u = origUV.s0;\n"
"    hitPoint->uv.v += vv;\n"
"    VSTORE3F(normalize(origShadeN + vv * dndv), &hitPoint->shadeN.x);\n"
"    const float dvValue = Texture_GetFloatValue(texture, hitPoint\n"
"			TEXTURES_PARAM);\n"
"    duv.s1 = (dvValue - base) / vv;\n"
"\n"
"    // Restore HitPoint\n"
"    VSTORE3F(origP, &hitPoint->p.x);\n"
"    VSTORE2F(origUV, &hitPoint->uv.u);\n"
"    VSTORE3F(origShadeN, &hitPoint->shadeN.x);\n"
"\n"
"    return duv;\n"
"}\n"
"\n"
"#if defined (PARAM_ENABLE_TEX_NORMALMAP)\n"
"float2 NormalMapTexture_GetDuv(\n"
"        __global Texture *texture,\n"
"        __global HitPoint *hitPoint,\n"
"        const float3 dpdu, const float3 dpdv,\n"
"        const float3 dndu, const float3 dndv,\n"
"        const float sampleDistance\n"
"        TEXTURES_PARAM_DECL) {\n"
"    float3 rgb = Texture_GetSpectrumValue(&texs[texture->normalMap.texIndex], hitPoint\n"
"			TEXTURES_PARAM);\n"
"    rgb = clamp(rgb, -1.f, 1.f);\n"
"\n"
"	// Normal from normal map\n"
"	float3 n = 2.f * rgb - (float3)(1.f, 1.f, 1.f);\n"
"\n"
"	const float3 k = VLOAD3F(&hitPoint->shadeN.x);\n"
"\n"
"	// Transform n from tangent to object space\n"
"    const float btsign = (dot(dpdv, k) > 0.f) ? 1.f : -1.f;\n"
"\n"
"	// Magnitude of btsign is the magnitude of the interpolated normal\n"
"	const float3 kk = k * fabs(btsign);\n"
"\n"
"	// tangent -> object\n"
"	n = normalize(n.x * dpdu + n.y * btsign * dpdv + n.z * kk);	\n"
"\n"
"	// Since n is stored normalized in the normal map\n"
"	// we need to recover the original length (lambda).\n"
"	// We do this by solving \n"
"	//   lambda*n = dp/du x dp/dv\n"
"	// where \n"
"	//   p(u,v) = base(u,v) + h(u,v) * k\n"
"	// and\n"
"	//   k = dbase/du x dbase/dv\n"
"	//\n"
"	// We recover lambda by dotting the above with k\n"
"	//   k . lambda*n = k . (dp/du x dp/dv)\n"
"	//   lambda = (k . k) / (k . n)\n"
"	// \n"
"	// We then recover dh/du by dotting the first eq by dp/du\n"
"	//   dp/du . lambda*n = dp/du . (dp/du x dp/dv)\n"
"	//   dp/du . lambda*n = dh/du * [dbase/du . (k x dbase/dv)]\n"
"	//\n"
"	// The term \"dbase/du . (k x dbase/dv)\" reduces to \"-(k . k)\", so we get\n"
"	//   dp/du . lambda*n = dh/du * -(k . k)\n"
"	//   dp/du . [(k . k) / (k . n)*n] = dh/du * -(k . k)\n"
"	//   dp/du . [-n / (k . n)] = dh/du\n"
"	// and similar for dh/dv\n"
"	// \n"
"	// Since the recovered dh/du will be in units of ||k||, we must divide\n"
"	// by ||k|| to get normalized results. Using dg.nn as k in the last eq \n"
"	// yields the same result.\n"
"	const float3 nn = (-1.f / dot(k, n)) * n;\n"
"\n"
"	return (float2)(dot(dpdu, nn), dot(dpdv, nn));\n"
"}\n"
"#endif\n"
"\n"
"#endif\n"
; } }
