#include <string>
namespace slg { namespace ocl {
std::string KernelSource_volume_funcs = 
"#line 2 \"volume_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"
"#if defined(PARAM_HAS_VOLUMES)\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// PathVolumeInfo\n"
"//------------------------------------------------------------------------------\n"
"\n"
"void PathVolumeInfo_Init(__global PathVolumeInfo *pvi) {\n"
"	pvi->currentVolumeIndex = NULL_INDEX;\n"
"	pvi->volumeIndexListSize = 0;\n"
"\n"
"	pvi->scatteredStart = false;\n"
"}\n"
"\n"
"void PathVolumeInfo_AddVolume(__global PathVolumeInfo *pvi, const uint volIndex\n"
"		MATERIALS_PARAM_DECL) {\n"
"	if ((volIndex == NULL_INDEX) || (pvi->volumeIndexListSize == OPENCL_PATHVOLUMEINFO_SIZE)) {\n"
"		// NULL volume or out of space, I just ignore the volume\n"
"		return;\n"
"	}\n"
"\n"
"	// Update the current volume. \">=\" because I want to catch the last added volume.\n"
"	if ((pvi->currentVolumeIndex == NULL_INDEX) ||\n"
"			(mats[volIndex].volume.priority >= mats[pvi->currentVolumeIndex].volume.priority))\n"
"		pvi->currentVolumeIndex = volIndex;\n"
"\n"
"	// Add the volume to the list\n"
"	pvi->volumeIndexList[(pvi->volumeIndexListSize)++] = volIndex;\n"
"}\n"
"\n"
"void PathVolumeInfo_RemoveVolume(__global PathVolumeInfo *pvi, const uint volIndex\n"
"		MATERIALS_PARAM_DECL) {\n"
"	if ((volIndex == NULL_INDEX) || (pvi->volumeIndexListSize == 0)) {\n"
"		// NULL volume or empty volume list\n"
"		return;\n"
"	}\n"
"\n"
"	// Update the current volume and the list\n"
"	bool found = false;\n"
"	uint currentVolume = NULL_INDEX;\n"
"	for (uint i = 0; i < pvi->volumeIndexListSize; ++i) {\n"
"		if (found) {\n"
"			// Re-compact the list\n"
"			pvi->volumeIndexList[i - 1] = pvi->volumeIndexList[i];\n"
"		} else if (pvi->volumeIndexList[i] == volIndex) {\n"
"			// Found the volume to remove\n"
"			found = true;\n"
"			continue;\n"
"		}\n"
"\n"
"		// Update currentVolume. \">=\" because I want to catch the last added volume.\n"
"		if ((currentVolume == NULL_INDEX) ||\n"
"				(mats[pvi->volumeIndexList[i]].volume.priority >= mats[currentVolume].volume.priority))\n"
"			currentVolume = pvi->volumeIndexList[i];\n"
"	}\n"
"	pvi->currentVolumeIndex = currentVolume;\n"
"\n"
"	// Update the list size\n"
"	--(pvi->volumeIndexListSize);\n"
"}\n"
"\n"
"void PathVolumeInfo_Update(__global PathVolumeInfo *pvi, const BSDFEvent eventType,\n"
"		__global BSDF *bsdf\n"
"		MATERIALS_PARAM_DECL) {\n"
"	// Update only if it isn't a volume scattering and the material can TRANSMIT\n"
"	if (bsdf->isVolume)\n"
"		pvi->scatteredStart = true;\n"
"	else {\n"
"		pvi->scatteredStart = false;\n"
"\n"
"		if(eventType  & TRANSMIT) {\n"
"			const uint volIndex = BSDF_GetMaterialInteriorVolume(bsdf\n"
"					MATERIALS_PARAM);\n"
"\n"
"			if (bsdf->hitPoint.intoObject)\n"
"				PathVolumeInfo_AddVolume(pvi, volIndex\n"
"						MATERIALS_PARAM);\n"
"			else\n"
"				PathVolumeInfo_RemoveVolume(pvi, volIndex\n"
"						MATERIALS_PARAM);\n"
"		}\n"
"	}\n"
"}\n"
"\n"
"bool PathVolumeInfo_CompareVolumePriorities(const uint vol1Index, const uint vol2Index\n"
"	MATERIALS_PARAM_DECL) {\n"
"	// A volume wins over another if and only if it is the same volume or has a\n"
"	// higher priority\n"
"\n"
"	if (vol1Index != NULL_INDEX) {\n"
"		if (vol2Index != NULL_INDEX) {\n"
"			if (vol1Index == vol2Index)\n"
"				return true;\n"
"			else\n"
"				return (mats[vol1Index].volume.priority > mats[vol2Index].volume.priority);\n"
"		} else\n"
"			return false;\n"
"	} else\n"
"		return false;\n"
"}\n"
"\n"
"bool PathVolumeInfo_ContinueToTrace(__global PathVolumeInfo *pvi, __global BSDF *bsdf\n"
"		MATERIALS_PARAM_DECL) {\n"
"	// Check if the volume priority system has to be applied\n"
"	if (BSDF_GetEventTypes(bsdf\n"
"			MATERIALS_PARAM) & TRANSMIT) {\n"
"		// Ok, the surface can transmit so check if volume priority\n"
"		// system is telling me to continue to trace the ray\n"
"\n"
"		// I have to continue to trace the ray if:\n"
"		//\n"
"		// 1) I'm entering an object and the interior volume has a\n"
"		// higher priority than the current one.\n"
"		//\n"
"		// 2) I'm exiting an object and I'm leaving the current volume\n"
"\n"
"		const uint volIndex = BSDF_GetMaterialInteriorVolume(bsdf\n"
"			MATERIALS_PARAM);\n"
"		if (\n"
"			// Condition #1\n"
"			(bsdf->hitPoint.intoObject && PathVolumeInfo_CompareVolumePriorities(pvi->currentVolumeIndex, volIndex\n"
"				MATERIALS_PARAM)) ||\n"
"			// Condition #2\n"
"			(!bsdf->hitPoint.intoObject && (pvi->currentVolumeIndex != volIndex))) {\n"
"			// Ok, green light for continuing to trace the ray\n"
"			return true;\n"
"		}\n"
"	}\n"
"\n"
"	return false;\n"
"}\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// ClearVolume scatter\n"
"//------------------------------------------------------------------------------\n"
"\n"
"float3 ClearVolume_SigmaA(__global Volume *vol, __global HitPoint *hitPoint\n"
"	TEXTURES_PARAM_DECL) {\n"
"	const float3 sigmaA = Texture_GetSpectrumValue(&texs[vol->volume.clear.sigmaATexIndex], hitPoint\n"
"		TEXTURES_PARAM);\n"
"			\n"
"	return clamp(sigmaA, 0.f, INFINITY);\n"
"}\n"
"\n"
"float3 ClearVolume_SigmaS(__global Volume *vol, __global HitPoint *hitPoint\n"
"	TEXTURES_PARAM_DECL) {\n"
"	return BLACK;\n"
"}\n"
"\n"
"float3 ClearVolume_SigmaT(__global Volume *vol, __global HitPoint *hitPoint\n"
"	TEXTURES_PARAM_DECL) {\n"
"	return\n"
"			ClearVolume_SigmaA(vol, hitPoint\n"
"				TEXTURES_PARAM) +\n"
"			ClearVolume_SigmaS(vol, hitPoint\n"
"				TEXTURES_PARAM);\n"
"}\n"
"\n"
"float ClearVolume_Scatter(__global Volume *vol,\n"
"		__global Ray *ray, const float hitT,\n"
"#if defined(PARAM_HAS_PASSTHROUGH)\n"
"		const float passThroughEvent,\n"
"#endif\n"
"		const bool scatteredStart, float3 *connectionThroughput,\n"
"		float3 *connectionEmission, __global HitPoint *tmpHitPoint\n"
"		TEXTURES_PARAM_DECL) {\n"
"	// Initialize tmpHitPoint\n"
"	const float3 rayOrig = VLOAD3F(&ray->o.x);\n"
"	const float3 rayDir = VLOAD3F(&ray->d.x);\n"
"	VSTORE3F(rayDir, &tmpHitPoint->fixedDir.x);\n"
"	VSTORE3F(rayOrig, &tmpHitPoint->p.x);\n"
"	VSTORE2F((float2)(0.f, 0.f), &tmpHitPoint->uv.u);\n"
"	VSTORE3F(-rayDir, &tmpHitPoint->geometryN.x);\n"
"	VSTORE3F(-rayDir, &tmpHitPoint->shadeN.x);\n"
"#if defined(PARAM_ENABLE_TEX_HITPOINTCOLOR) || defined(PARAM_ENABLE_TEX_HITPOINTGREY)\n"
"	VSTORE2F(WHITE, &tmpHitPoint->color.c);\n"
"#endif\n"
"#if defined(PARAM_ENABLE_TEX_HITPOINTALPHA)\n"
"	VSTORE2F(1.f, &tmpHitPoint->alpha);\n"
"#endif\n"
"#if defined(PARAM_HAS_PASSTHROUGH)\n"
"	tmpHitPoint->passThroughEvent = passThroughEvent;\n"
"#endif\n"
"#if defined(PARAM_HAS_VOLUMES)\n"
"	tmpHitPoint->interiorVolumeIndex = NULL_INDEX;\n"
"	tmpHitPoint->exteriorVolumeIndex = NULL_INDEX;\n"
"	tmpHitPoint->intoObject = true;\n"
"#endif\n"
"\n"
"	const float distance = hitT - ray->mint;	\n"
"	float3 transmittance = WHITE;\n"
"\n"
"	const float3 sigma = ClearVolume_SigmaT(vol, tmpHitPoint\n"
"			TEXTURES_PARAM);\n"
"	if (!Spectrum_IsBlack(sigma)) {\n"
"		const float3 tau = clamp(distance * sigma, 0.f, INFINITY);\n"
"		transmittance = Spectrum_Exp(-tau);\n"
"	}\n"
"\n"
"	// Apply volume transmittance\n"
"	*connectionThroughput *= transmittance;\n"
"\n"
"	// Apply volume emission\n"
"	const uint emiTexIndex = vol->volume.volumeEmissionTexIndex;\n"
"	if (emiTexIndex != NULL_INDEX) {\n"
"		const float3 emiTex = Texture_GetSpectrumValue(&texs[emiTexIndex], tmpHitPoint\n"
"			TEXTURES_PARAM);\n"
"		*connectionEmission += *connectionThroughput * distance * clamp(emiTex, 0.f, INFINITY);\n"
"	}\n"
"\n"
"	return -1.f;\n"
"}\n"
"\n"
"//------------------------------------------------------------------------------\n"
"// Volume scatter\n"
"//------------------------------------------------------------------------------\n"
"\n"
"float Volume_Scatter(__global Volume *vol,\n"
"		__global Ray *ray, const float hitT, const float passThrough,\n"
"		const bool scatteredStart, float3 *connectionThroughput,\n"
"		float3 *connectionEmission, __global HitPoint *tmpHitPoint\n"
"		TEXTURES_PARAM_DECL) {\n"
"	switch (vol->type) {\n"
"		case CLEAR_VOL:\n"
"			ClearVolume_Scatter(vol, ray, hitT, passThrough, scatteredStart,\n"
"					connectionThroughput, connectionEmission, tmpHitPoint\n"
"					TEXTURES_PARAM);\n"
"		default:\n"
"			return -1.f;\n"
"	}\n"
"}\n"
"\n"
"#endif\n"
; } }
