#include <string>
namespace luxrays { namespace ocl {
std::string KernelSource_mbvh = 
"#line 2 \"mbvh_kernel.cl\"\n"
"\n"
"/***************************************************************************\n"
" *   Copyright (C) 1998-2013 by authors (see AUTHORS.txt)                  *\n"
" *                                                                         *\n"
" *   This file is part of LuxRays.                                         *\n"
" *                                                                         *\n"
" *   LuxRays is free software; you can redistribute it and/or modify       *\n"
" *   it under the terms of the GNU General Public License as published by  *\n"
" *   the Free Software Foundation; either version 3 of the License, or     *\n"
" *   (at your option) any later version.                                   *\n"
" *                                                                         *\n"
" *   LuxRays is distributed in the hope that it will be useful,            *\n"
" *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\n"
" *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\n"
" *   GNU General Public License for more details.                          *\n"
" *                                                                         *\n"
" *   You should have received a copy of the GNU General Public License     *\n"
" *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *\n"
" *                                                                         *\n"
" *   LuxRays website: http://www.luxrender.net                             *\n"
" ***************************************************************************/\n"
"\n"
"typedef struct {\n"
"	union {\n"
"		struct {\n"
"			// I can not use BBox here because objects with a constructor are not\n"
"			// allowed inside an union.\n"
"			float bboxMin[3];\n"
"			float bboxMax[3];\n"
"		} bvhNode;\n"
"		struct {\n"
"			uint v[3];\n"
"			uint triangleIndex;\n"
"		} triangleLeaf;\n"
"		struct {\n"
"			uint leafIndex;\n"
"			uint transformIndex;\n"
"			uint meshOffsetIndex;\n"
"		} bvhLeaf; // Used by MBVH\n"
"	};\n"
"	// Most significant bit is used to mark leafs\n"
"	uint nodeData;\n"
"	int pad0; // To align to float4\n"
"} BVHAccelArrayNode;\n"
"\n"
"#define BVHNodeData_IsLeaf(nodeData) ((nodeData) & 0x80000000u)\n"
"#define BVHNodeData_GetSkipIndex(nodeData) ((nodeData) & 0x7fffffffu)\n"
"#if (MBVH_NODES_PAGE_COUNT > 1)\n"
"#define BVHNodeData_GetPageIndex(nodeData) (((nodeData) & 0x70000000u) >> 28)\n"
"#define BVHNodeData_GetNodeIndex(nodeData) ((nodeData) & 0x0fffffffu)\n"
"#endif\n"
"\n"
"#if (MBVH_NODES_PAGE_COUNT > 1)\n"
"void NextNode(uint *pageIndex, uint *nodeIndex) {\n"
"	++(*nodeIndex);\n"
"	if (*nodeIndex >= MBVH_NODES_PAGE_SIZE) {\n"
"		*nodeIndex = 0;\n"
"		++(*pageIndex);\n"
"	}\n"
"}\n"
"#endif\n"
"\n"
"__kernel __attribute__((work_group_size_hint(64, 1, 1))) void Intersect(\n"
"		__global Ray *rays,\n"
"		__global RayHit *rayHits,\n"
"		const uint rayCount\n"
"#if defined(MBVH_HAS_TRANSFORMATIONS)\n"
"		, __global Matrix4x4 *leafTransformations\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE0)\n"
"		, __global Point *vertPage0\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE1)\n"
"		, __global Point *vertPage1\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE2)\n"
"		, __global Point *vertPage2\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE3)\n"
"		, __global Point *vertPage3\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE4)\n"
"		, __global Point *vertPage4\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE5)\n"
"		, __global Point *vertPage5\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE6)\n"
"		, __global Point *vertPage6\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE7)\n"
"		, __global Point *vertPage7\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE0)\n"
"		, __global BVHAccelArrayNode *nodePage0\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE1)\n"
"		, __global BVHAccelArrayNode *nodePage1\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE2)\n"
"		, __global BVHAccelArrayNode *nodePage2\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE3)\n"
"		, __global BVHAccelArrayNode *nodePage3\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE4)\n"
"		, __global BVHAccelArrayNode *nodePage4\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE5)\n"
"		, __global BVHAccelArrayNode *nodePage5\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE6)\n"
"		, __global BVHAccelArrayNode *nodePage6\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE7)\n"
"		, __global BVHAccelArrayNode *nodePage7\n"
"#endif\n"
"		) {\n"
"	// Select the ray to check\n"
"	const int gid = get_global_id(0);\n"
"	if (gid >= rayCount)\n"
"		return;\n"
"\n"
"	// Initialize vertex page references\n"
"#if (MBVH_VERTS_PAGE_COUNT > 1)\n"
"	__global Point *vertPages[MBVH_VERTS_PAGE_COUNT];\n"
"#if defined(MBVH_VERTS_PAGE0)\n"
"	vertPages[0] = vertPage0;\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE1)\n"
"	vertPages[1] = vertPage1;\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE2)\n"
"	vertPages[2] = vertPage2;\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE3)\n"
"	vertPages[3] = vertPage3;\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE4)\n"
"	vertPages[4] = vertPage4;\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE5)\n"
"	vertPages[5] = vertPage5;\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE6)\n"
"	vertPages[6] = vertPage6;\n"
"#endif\n"
"#if defined(MBVH_VERTS_PAGE7)\n"
"	vertPages[7] = vertPage7;\n"
"#endif\n"
"#endif\n"
"\n"
"	// Initialize node page references\n"
"#if (MBVH_NODES_PAGE_COUNT > 1)\n"
"	__global BVHAccelArrayNode *nodePages[MBVH_NODES_PAGE_COUNT];\n"
"#if defined(MBVH_NODES_PAGE0)\n"
"	nodePages[0] = nodePage0;\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE1)\n"
"	nodePages[1] = nodePage1;\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE2)\n"
"	nodePages[2] = nodePage2;\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE3)\n"
"	nodePages[3] = nodePage3;\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE4)\n"
"	nodePages[4] = nodePage4;\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE5)\n"
"	nodePages[5] = nodePage5;\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE6)\n"
"	nodePages[6] = nodePage6;\n"
"#endif\n"
"#if defined(MBVH_NODES_PAGE7)\n"
"	nodePages[7] = nodePage7;\n"
"#endif\n"
"#endif\n"
"\n"
"	bool insideLeafTree = false;\n"
"#if (MBVH_NODES_PAGE_COUNT == 1)\n"
"	uint currentRootNode = 0;\n"
"	uint rootStopNode = BVHNodeData_GetSkipIndex(nodePage0[0].nodeData); // Non-existent\n"
"	uint currentStopNode = rootStopNode; // Non-existent\n"
"	uint currentNode = currentRootNode;\n"
"#else\n"
"	uint currentRootPage = 0;\n"
"	uint currentRootNode = 0;\n"
"\n"
"	const uint rootStopIndex = nodePage0[0].nodeData;\n"
"	const uint rootStopPage = BVHNodeData_GetPageIndex(rootStopIndex);\n"
"	const uint rootStopNode = BVHNodeData_GetNodeIndex(rootStopIndex); // Non-existent\n"
"\n"
"	uint currentStopPage = rootStopPage; // Non-existent\n"
"	uint currentStopNode = rootStopNode; // Non-existent\n"
"\n"
"	uint currentPage = 0; // Root Node Page\n"
"	uint currentNode = currentRootNode;\n"
"#endif\n"
"	\n"
"	uint currentMeshOffset = 0;\n"
"\n"
"	__global Ray *ray = &rays[gid];\n"
"	//const float3 rootRayOrig = VLOAD3F(&ray->o.x);\n"
"	//const float3 rootRayDir = VLOAD3F(&ray->d.x);\n"
"	//const float mint = ray->mint;\n"
"	//float maxt = ray->maxt;\n"
"	float3 rootRayOrig, rootRayDir;\n"
"	float mint, maxt;\n"
"	Ray_ReadAligned4(ray, &rootRayOrig, &rootRayDir, &mint, &maxt);\n"
"\n"
"	float3 currentRayOrig = rootRayOrig;\n"
"	float3 currentRayDir = rootRayDir;\n"
"\n"
"	uint hitMeshIndex = NULL_INDEX;\n"
"	uint hitTriangleIndex = NULL_INDEX;\n"
"\n"
"	float b1, b2;\n"
"	for (;;) {\n"
"#if (MBVH_NODES_PAGE_COUNT == 1)\n"
"		if (currentNode >= currentStopNode) {\n"
"#else\n"
"		if (!((currentPage < currentStopPage) || (currentNode < currentStopNode))) {\n"
"#endif\n"
"			if (insideLeafTree) {\n"
"				// Go back to the root tree\n"
"#if (MBVH_NODES_PAGE_COUNT == 1)\n"
"				currentNode = currentRootNode;\n"
"				currentStopNode = rootStopNode;\n"
"#else\n"
"				currentPage = currentRootPage;\n"
"				currentNode = currentRootNode;\n"
"				currentStopPage = rootStopPage;\n"
"				currentStopNode = rootStopNode;\n"
"#endif\n"
"				currentRayOrig = rootRayOrig;\n"
"				currentRayDir = rootRayDir;\n"
"				insideLeafTree = false;\n"
"\n"
"				// Check if the leaf was the very last root node\n"
"#if (MBVH_NODES_PAGE_COUNT == 1)\n"
"				if (currentNode >= currentStopNode)\n"
"#else\n"
"				if (!((currentPage < currentStopPage) || (currentNode < currentStopNode)))\n"
"#endif\n"
"					break;\n"
"			} else {\n"
"				// Done\n"
"				break;\n"
"			}\n"
"		}\n"
"\n"
"#if (MBVH_NODES_PAGE_COUNT == 1)\n"
"		__global BVHAccelArrayNode *node = &nodePage0[currentNode];\n"
"#else\n"
"		__global BVHAccelArrayNode *nodePage = nodePages[currentPage];\n"
"		__global BVHAccelArrayNode *node = &nodePage[currentNode];\n"
"#endif\n"
"// Read the node\n"
"		__global float4 *data = (__global float4 *)node;\n"
"		const float4 data0 = *data++;\n"
"		const float4 data1 = *data;\n"
"\n"
"		//const uint nodeData = node->nodeData;\n"
"		const uint nodeData = as_uint(data1.s2);\n"
"		if (BVHNodeData_IsLeaf(nodeData)) {\n"
"			if (insideLeafTree) {\n"
"				// I'm inside a leaf tree, I have to check the triangle\n"
"				\n"
"				//const uint i0 = node->triangleLeaf.v[0];\n"
"				//const uint i1 = node->triangleLeaf.v[1];\n"
"				//const uint i2 = node->triangleLeaf.v[2];\n"
"				const uint v0 = as_uint(data0.s0);\n"
"				const uint v1 = as_uint(data0.s1);\n"
"				const uint v2 = as_uint(data0.s2);\n"
"\n"
"#if (MBVH_VERTS_PAGE_COUNT == 1)\n"
"				// Fast path for when there is only one memory page\n"
"				const float3 p0 = VLOAD3F(&vertPage0[v0].x);\n"
"				const float3 p1 = VLOAD3F(&vertPage0[v1].x);\n"
"				const float3 p2 = VLOAD3F(&vertPage0[v2].x);\n"
"#else\n"
"				const uint pv0 = (v0 & 0xe0000000u) >> 29;\n"
"				const uint iv0 = (v0 & 0x1fffffffu);\n"
"				__global Point *vp0 = vertPages[pv0];\n"
"				const float3 p0 = VLOAD3F(&vp0[iv0].x);\n"
"\n"
"				const uint pv1 = (v1 & 0xe0000000u) >> 29;\n"
"				const uint iv1 = (v1 & 0x1fffffffu);\n"
"				__global Point *vp1 = vertPages[pv1];\n"
"				const float3 p1 = VLOAD3F(&vp1[iv1].x);\n"
"\n"
"				const uint pv2 = (v2 & 0xe0000000u) >> 29;\n"
"				const uint iv2 = (v2 & 0x1fffffffu);\n"
"				__global Point *vp2 = vertPages[pv2];\n"
"				const float3 p2 = VLOAD3F(&vp2[iv2].x);\n"
"#endif\n"
"\n"
"				//const uint meshIndex = node->triangleLeaf.meshIndex + currentMeshOffset;\n"
"				//const uint triangleIndex = node->triangleLeaf.triangleIndex;\n"
"				const uint meshIndex = as_uint(data0.s3) + currentMeshOffset;\n"
"				const uint triangleIndex = as_uint(data1.s0);\n"
"				Triangle_Intersect(currentRayOrig, currentRayDir, mint, &maxt, &hitMeshIndex, &hitTriangleIndex, &b1, &b2,\n"
"					meshIndex, triangleIndex, p0, p1, p2);\n"
"#if (MBVH_NODES_PAGE_COUNT == 1)\n"
"				++currentNode;\n"
"#else\n"
"				NextNode(&currentPage, &currentNode);\n"
"#endif\n"
"			} else {\n"
"				// I have to check a leaf tree\n"
"#if defined(MBVH_HAS_TRANSFORMATIONS)\n"
"				// Transform the ray in the local coordinate system\n"
"				//const uint transformIndex = node->bvhLeaf.transformIndex;\n"
"				const uint transformIndex = as_int(data0.s1);\n"
"				if (transformIndex != NULL_INDEX) {\n"
"					// Transform ray origin\n"
"					__global Matrix4x4 *m = &leafTransformations[transformIndex];\n"
"					currentRayOrig = Matrix4x4_ApplyPoint(m, rootRayOrig);\n"
"					currentRayDir = Matrix4x4_ApplyVector(m, rootRayDir);\n"
"				}\n"
"#endif \n"
"				//currentMeshOffset = node->bvhLeaf.meshOffsetIndex;\n"
"				currentMeshOffset = as_int(data0.s2);\n"
"\n"
"				//const uint leafIndex = node->bvhLeaf.leafIndex;\n"
"				const uint leafIndex = as_int(data0.s0);\n"
"#if (MBVH_NODES_PAGE_COUNT == 1)\n"
"				currentRootNode = currentNode + 1;\n"
"				currentNode = leafIndex;\n"
"				currentStopNode = BVHNodeData_GetSkipIndex(nodePage0[currentNode].nodeData);\n"
"#else\n"
"				currentRootPage = currentPage;\n"
"				currentRootNode = currentNode;\n"
"				NextNode(&currentRootPage, &currentRootNode);\n"
"\n"
"				currentPage = BVHNodeData_GetPageIndex(leafIndex);\n"
"				currentNode = BVHNodeData_GetNodeIndex(leafIndex);\n"
"\n"
"				__global BVHAccelArrayNode *stopNodePage = nodePages[currentPage];\n"
"				__global BVHAccelArrayNode *stopNode = &stopNodePage[currentNode];\n"
"				const uint stopIndex = stopNode->nodeData;\n"
"				currentStopPage = BVHNodeData_GetPageIndex(stopIndex);\n"
"				currentStopNode = BVHNodeData_GetNodeIndex(stopIndex);\n"
"#endif\n"
"\n"
"				// Now, I'm inside a leaf tree\n"
"				insideLeafTree = true;\n"
"			}\n"
"		} else {\n"
"			// It is a node, check the bounding box\n"
"			//const float3 pMin = VLOAD3F(&node->bvhNode.bboxMin[0]);\n"
"			//const float3 pMax = VLOAD3F(&node->bvhNode.bboxMax[0]);\n"
"			const float3 pMin = (float3)(data0.s0, data0.s1, data0.s2);\n"
"			const float3 pMax = (float3)(data0.s3, data1.s0, data1.s1);\n"
"\n"
"			if (BBox_IntersectP(pMin, pMax, currentRayOrig, 1.f / currentRayDir, mint, maxt)) {\n"
"#if (MBVH_NODES_PAGE_COUNT == 1)\n"
"				++currentNode;\n"
"#else\n"
"				NextNode(&currentPage, &currentNode);\n"
"#endif\n"
"			} else {\n"
"#if (MBVH_NODES_PAGE_COUNT == 1)\n"
"				// I don't need to use BVHNodeData_GetSkipIndex() here because\n"
"				// I already know the flag (i.e. the last bit) is 0\n"
"				currentNode = nodeData;\n"
"#else\n"
"				currentPage = BVHNodeData_GetPageIndex(nodeData);\n"
"				currentNode = BVHNodeData_GetNodeIndex(nodeData);\n"
"#endif\n"
"			}\n"
"		}\n"
"	}\n"
"\n"
"	// Write result\n"
"	__global RayHit *rayHit = &rayHits[gid];\n"
"	rayHit->t = maxt;\n"
"	rayHit->b1 = b1;\n"
"	rayHit->b2 = b2;\n"
"	rayHit->meshIndex = hitMeshIndex;\n"
"	rayHit->triangleIndex = hitTriangleIndex;\n"
"}\n"
; } }
