Fix typo

Fix typo

#line 2 "texture_types.cl"

/***************************************************************************
 * Copyright 1998-2013 by authors (see AUTHORS.txt)                        *
 *                                                                         *
 *   This file is part of LuxRender.                                       *
 *                                                                         *
 * Licensed under the Apache License, Version 2.0 (the "License");         *
 * you may not use this file except in compliance with the License.        *
 * You may obtain a copy of the License at                                 *
 *                                                                         *
 *     http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                         *
 * Unless required by applicable law or agreed to in writing, software     *
 * distributed under the License is distributed on an "AS IS" BASIS,       *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 * See the License for the specific language governing permissions and     *
 * limitations under the License.                                          *
 ***************************************************************************/

#define DUDV_VALUE 0.001f

typedef enum {
	CONST_FLOAT, CONST_FLOAT3, IMAGEMAP, SCALE_TEX, FRESNEL_APPROX_N,
	FRESNEL_APPROX_K, MIX_TEX, ADD_TEX, HITPOINTCOLOR, HITPOINTALPHA,
	HITPOINTGREY, NORMALMAP_TEX,
	// Procedural textures
	BLENDER_BLEND, BLENDER_CLOUDS, BLENDER_DISTORTED_NOISE, BLENDER_MAGIC,
	BLENDER_MARBLE, BLENDER_MUSGRAVE, BLENDER_STUCCI, BLENDER_WOOD, BLENDER_VORONOI,
	CHECKERBOARD2D, CHECKERBOARD3D, FBM_TEX, MARBLE, DOTS, BRICK, WINDY, WRINKLED, UV_TEX, BAND_TEX
} TextureType;

typedef struct {
	float value;
} ConstFloatParam;

typedef struct {
	Spectrum color;
} ConstFloat3Param;

typedef struct {
	unsigned int channelCount, width, height;
	unsigned int pageIndex, pixelsIndex;
} ImageMap;

typedef struct {
	TextureMapping2D mapping;
	float gain;

	unsigned int imageMapIndex;
} ImageMapTexParam;

typedef struct {
	unsigned int tex1Index, tex2Index;
} ScaleTexParam;

typedef struct {
	unsigned int texIndex;
} FresnelApproxNTexParam;

typedef struct {
	unsigned int texIndex;
} FresnelApproxKTexParam;

typedef struct {
	unsigned int amountTexIndex, tex1Index, tex2Index;
} MixTexParam;

typedef struct {
	TextureMapping2D mapping;
	unsigned int tex1Index, tex2Index;
} CheckerBoard2DTexParam;

typedef struct {
	TextureMapping3D mapping;
	unsigned int tex1Index, tex2Index;
} CheckerBoard3DTexParam;

typedef struct {
	TextureMapping3D mapping;
	int octaves;
	float omega;
} FBMTexParam;

typedef struct {
	TextureMapping3D mapping;
	int octaves;
	float omega, scale, variation;
} MarbleTexParam;

typedef struct {
	TextureMapping2D mapping;
	unsigned int insideIndex, outsideIndex;
} DotsTexParam;

typedef enum {
	FLEMISH, RUNNING, ENGLISH, HERRINGBONE, BASKET, KETTING
} MasonryBond;

typedef struct {
	TextureMapping3D mapping;
	unsigned int tex1Index, tex2Index, tex3Index;
	MasonryBond bond;
	float offsetx, offsety, offsetz;
	float brickwidth, brickheight, brickdepth, mortarsize;
	float proportion, invproportion, run;
	float mortarwidth, mortarheight, mortardepth;
	float bevelwidth, bevelheight, beveldepth;
	int usebevel;
} BrickTexParam;

typedef struct {
	unsigned int tex1Index, tex2Index;
} AddTexParam;

typedef struct {
	TextureMapping3D mapping;
	int octaves;
	float omega;
} WindyTexParam;

typedef enum {
	ACTUAL_DISTANCE, DISTANCE_SQUARED, MANHATTAN, CHEBYCHEV, MINKOWSKI_HALF,
	MINKOWSKI_FOUR, MINKOWSKI
} DistanceMetric;

typedef enum {
	TEX_LIN, TEX_QUAD, TEX_EASE, TEX_DIAG, TEX_SPHERE, TEX_HALO, TEX_RAD
} ProgressionType;

typedef enum {
    BLENDER_ORIGINAL, ORIGINAL_PERLIN, IMPROVED_PERLIN,
    VORONOI_F1, VORONOI_F2, VORONOI_F3, VORONOI_F4, VORONOI_F2_F1,
    VORONOI_CRACKLE, CELL_NOISE
} BlenderNoiseBasis;

typedef enum {
	TEX_SIN, TEX_SAW, TEX_TRI
} BlenderNoiseBase;

typedef struct {
	TextureMapping3D mapping;
	ProgressionType type;
	bool direction;
	float bright, contrast;
} BlenderBlendTexParam;

typedef struct {
	TextureMapping3D mapping;
	BlenderNoiseBasis noisebasis;
	float noisesize;
	int noisedepth;
	float bright, contrast;
	bool hard;
} BlenderCloudsTexParam;

typedef struct {
	TextureMapping3D mapping;
	BlenderNoiseBasis noisedistortion;
	BlenderNoiseBasis noisebasis;
	float distortion;
	float noisesize;
	float bright, contrast;
} BlenderDistortedNoiseTexParam;

typedef struct {
	TextureMapping3D mapping;
	int noisedepth;
	float turbulence;
	float bright, contrast;
} BlenderMagicTexParam;

typedef enum {
	TEX_SOFT, TEX_SHARP, TEX_SHARPER
} BlenderMarbleType;

typedef struct {
	TextureMapping3D mapping;
	BlenderMarbleType type;
	BlenderNoiseBasis noisebasis;
	BlenderNoiseBase noisebasis2;
	float noisesize, turbulence;
	int noisedepth;
	float bright, contrast;
	bool hard;
} BlenderMarbleTexParam;

typedef enum {
	TEX_MULTIFRACTAL, TEX_RIDGED_MULTIFRACTAL, TEX_HYBRID_MULTIFRACTAL, TEX_FBM, TEX_HETERO_TERRAIN
} BlenderMusgraveType;

typedef struct {
	TextureMapping3D mapping;
	BlenderMusgraveType type;
	BlenderNoiseBasis noisebasis;
	float dimension;
	float intensity;
	float lacunarity;
	float offset;
	float gain;
	float octaves;
	float noisesize;
	float bright, contrast;
	bool hard;
} BlenderMusgraveTexParam;

typedef struct {
	int noisedepth;
	float bright, contrast;
} BlenderNoiseTexParam;

typedef enum {
	TEX_PLASTIC, TEX_WALL_IN, TEX_WALL_OUT
} BlenderStucciType;

typedef struct {
	TextureMapping3D mapping;
	BlenderStucciType type;
	BlenderNoiseBasis noisebasis;
	float noisesize;
	float turbulence;
	float bright, contrast;
	bool hard;
} BlenderStucciTexParam;

typedef enum {
	BANDS, RINGS, BANDNOISE, RINGNOISE
} BlenderWoodType;

typedef struct {
	TextureMapping3D mapping;
	BlenderWoodType type;
	BlenderNoiseBase noisebasis2;
	BlenderNoiseBasis noisebasis;
	float noisesize, turbulence;
	float bright, contrast;
	bool hard;
} BlenderWoodTexParam;

typedef struct {
 	TextureMapping3D mapping;
	DistanceMetric distancemetric;
	float feature_weight1;
	float feature_weight2;
	float feature_weight3;
	float feature_weight4;
	float noisesize;
	float intensity;
	float exponent;
 	float bright, contrast;
} BlenderVoronoiTexParam;

typedef struct {
	TextureMapping3D mapping;
	int octaves;
	float omega;
} WrinkledTexParam;

typedef struct {
	TextureMapping2D mapping;
} UVTexParam;

#define BAND_TEX_MAX_SIZE 16

typedef struct {
	unsigned int amountTexIndex;
	unsigned int size;
	float offsets[BAND_TEX_MAX_SIZE];
	Spectrum values[BAND_TEX_MAX_SIZE];
} BandTexParam;

typedef struct {
	unsigned int channel;
} HitPointGreyTexParam;

typedef struct {
	unsigned int texIndex;
} NormalMapTexParam;

typedef struct {
	TextureType type;
	union {
		BlenderBlendTexParam blenderBlend;
 		BlenderCloudsTexParam blenderClouds;
		BlenderDistortedNoiseTexParam blenderDistortedNoise;
		BlenderMagicTexParam blenderMagic;
		BlenderMarbleTexParam blenderMarble;
		BlenderMusgraveTexParam blenderMusgrave;
		BlenderNoiseTexParam blenderNoise;
		BlenderStucciTexParam blenderStucci;
 		BlenderWoodTexParam blenderWood;
		BlenderVoronoiTexParam blenderVoronoi;
		ConstFloatParam constFloat;
		ConstFloat3Param constFloat3;
		ImageMapTexParam imageMapTex;
		ScaleTexParam scaleTex;
		FresnelApproxNTexParam fresnelApproxN;
		FresnelApproxKTexParam fresnelApproxK;
		MixTexParam mixTex;
		CheckerBoard2DTexParam checkerBoard2D;
		CheckerBoard3DTexParam checkerBoard3D;
		FBMTexParam fbm;
		MarbleTexParam marble;
		DotsTexParam dots;
		BrickTexParam brick;
		AddTexParam addTex;
		WindyTexParam windy;
		WrinkledTexParam wrinkled;
		UVTexParam uvTex;
		BandTexParam band;
		HitPointGreyTexParam hitPointGrey;
        NormalMapTexParam normalMap;
	};
} Texture;

//------------------------------------------------------------------------------
// Some macro trick in order to have more readable code
//------------------------------------------------------------------------------

#if defined(SLG_OPENCL_KERNEL)

#if defined(PARAM_HAS_IMAGEMAPS)

#define IMAGEMAPS_PARAM_DECL , __global ImageMap *imageMapDescs, __global float **imageMapBuff
#define IMAGEMAPS_PARAM , imageMapDescs, imageMapBuff

#else

#define IMAGEMAPS_PARAM_DECL
#define IMAGEMAPS_PARAM

#endif

#define TEXTURES_PARAM_DECL , __global Texture *texs IMAGEMAPS_PARAM_DECL
#define TEXTURES_PARAM , texs IMAGEMAPS_PARAM

#endif

#line 2 "texture_types.cl"

/***************************************************************************
 * Copyright 1998-2013 by authors (see AUTHORS.txt)                        *
 *                                                                         *
 *   This file is part of LuxRender.                                       *
 *                                                                         *
 * Licensed under the Apache License, Version 2.0 (the "License");         *
 * you may not use this file except in compliance with the License.        *
 * You may obtain a copy of the License at                                 *
 *                                                                         *
 *     http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                         *
 * Unless required by applicable law or agreed to in writing, software     *
 * distributed under the License is distributed on an "AS IS" BASIS,       *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 * See the License for the specific language governing permissions and     *
 * limitations under the License.                                          *
 ***************************************************************************/

#define DUDV_VALUE 0.001f

typedef enum {
	CONST_FLOAT, CONST_FLOAT3, IMAGEMAP, SCALE_TEX, FRESNEL_APPROX_N,
	FRESNEL_APPROX_K, MIX_TEX, ADD_TEX, HITPOINTCOLOR, HITPOINTALPHA,
	HITPOINTGREY, NORMALMAP_TEX,
	// Procedural textures
	BLENDER_BLEND, BLENDER_CLOUDS, BLENDER_DISTORTED_NOISE, BLENDER_MAGIC,
	BLENDER_MARBLE, BLENDER_MUSGRAVE, BLENDER_STUCCI, BLENDER_WOOD, BLENDER_VORONOI,
	CHECKERBOARD2D, CHECKERBOARD3D, FBM_TEX, MARBLE, DOTS, BRICK, WINDY, WRINKLED, UV_TEX, BAND_TEX
} TextureType;

typedef struct {
	float value;
} ConstFloatParam;

typedef struct {
	Spectrum color;
} ConstFloat3Param;

typedef struct {
	unsigned int channelCount, width, height;
	unsigned int pageIndex, pixelsIndex;
} ImageMap;

typedef struct {
	TextureMapping2D mapping;
	float gain;

	unsigned int imageMapIndex;
} ImageMapTexParam;

typedef struct {
	unsigned int tex1Index, tex2Index;
} ScaleTexParam;

typedef struct {
	unsigned int texIndex;
} FresnelApproxNTexParam;

typedef struct {
	unsigned int texIndex;
} FresnelApproxKTexParam;

typedef struct {
	unsigned int amountTexIndex, tex1Index, tex2Index;
} MixTexParam;

typedef struct {
	TextureMapping2D mapping;
	unsigned int tex1Index, tex2Index;
} CheckerBoard2DTexParam;

typedef struct {
	TextureMapping3D mapping;
	unsigned int tex1Index, tex2Index;
} CheckerBoard3DTexParam;

typedef struct {
	TextureMapping3D mapping;
	int octaves;
	float omega;
} FBMTexParam;

typedef struct {
	TextureMapping3D mapping;
	int octaves;
	float omega, scale, variation;
} MarbleTexParam;

typedef struct {
	TextureMapping2D mapping;
	unsigned int insideIndex, outsideIndex;
} DotsTexParam;

typedef enum {
	FLEMISH, RUNNING, ENGLISH, HERRINGBONE, BASKET, KETTING
} MasonryBond;

typedef struct {
	TextureMapping3D mapping;
	unsigned int tex1Index, tex2Index, tex3Index;
	MasonryBond bond;
	float offsetx, offsety, offsetz;
	float brickwidth, brickheight, brickdepth, mortarsize;
	float proportion, invproportion, run;
	float mortarwidth, mortarheight, mortardepth;
	float bevelwidth, bevelheight, beveldepth;
	int usebevel;
} BrickTexParam;

typedef struct {
	unsigned int tex1Index, tex2Index;
} AddTexParam;

typedef struct {
	TextureMapping3D mapping;
	int octaves;
	float omega;
} WindyTexParam;

typedef enum {
	ACTUAL_DISTANCE, DISTANCE_SQUARED, MANHATTAN, CHEBYCHEV, MINKOWSKI_HALF,
	MINKOWSKI_FOUR, MINKOWSKI
} DistanceMetric;

typedef enum {
	TEX_LIN, TEX_QUAD, TEX_EASE, TEX_DIAG, TEX_SPHERE, TEX_HALO, TEX_RAD
} ProgressionType;

typedef enum {
    BLENDER_ORIGINAL, ORIGINAL_PERLIN, IMPROVED_PERLIN,
    VORONOI_F1, VORONOI_F2, VORONOI_F3, VORONOI_F4, VORONOI_F2_F1,
    VORONOI_CRACKLE, CELL_NOISE
} BlenderNoiseBasis;

typedef enum {
	TEX_SIN, TEX_SAW, TEX_TRI
} BlenderNoiseBase;

typedef struct {
	TextureMapping3D mapping;
	ProgressionType type;
	bool direction;
	float bright, contrast;
} BlenderBlendTexParam;

typedef struct {
	TextureMapping3D mapping;
	BlenderNoiseBasis noisebasis;
	float noisesize;
	int noisedepth;
	float bright, contrast;
	bool hard;
} BlenderCloudsTexParam;

typedef struct {
	TextureMapping3D mapping;
	BlenderNoiseBasis noisedistortion;
	BlenderNoiseBasis noisebasis;
	float distortion;
	float noisesize;
	float bright, contrast;
} BlenderDistortedNoiseTexParam;

typedef struct {
	TextureMapping3D mapping;
	int noisedepth;
	float turbulence;
	float bright, contrast;
} BlenderMagicTexParam;

typedef enum {
	TEX_SOFT, TEX_SHARP, TEX_SHARPER
} BlenderMarbleType;

typedef struct {
	TextureMapping3D mapping;
	BlenderMarbleType type;
	BlenderNoiseBasis noisebasis;
	BlenderNoiseBase noisebasis2;
	float noisesize, turbulence;
	int noisedepth;
	float bright, contrast;
	bool hard;
} BlenderMarbleTexParam;

typedef enum {
	TEX_MULTIFRACTAL, TEX_RIDGED_MULTIFRACTAL, TEX_HYBRID_MULTIFRACTAL, TEX_FBM, TEX_HETERO_TERRAIN
} BlenderMusgraveType;

typedef struct {
	TextureMapping3D mapping;
	BlenderMusgraveType type;
	BlenderNoiseBasis noisebasis;
	float dimension;
	float intensity;
	float lacunarity;
	float offset;
	float gain;
	float octaves;
	float noisesize;
	float bright, contrast;
	bool hard;
} BlenderMusgraveTexParam;

typedef struct {
	int noisedepth;
	float bright, contrast;
} BlenderNoiseTexParam;

typedef enum {
	TEX_PLASTIC, TEX_WALL_IN, TEX_WALL_OUT
} BlenderStucciType;

typedef struct {
	TextureMapping3D mapping;
	BlenderStucciType type;
	BlenderNoiseBasis noisebasis;
	float noisesize;
	float turbulence;
	float bright, contrast;
	bool hard;
} BlenderStucciTexParam;

typedef enum {
	BANDS, RINGS, BANDNOISE, RINGNOISE
BlenderWoodType;

typedef struct {
	TextureMapping3D mapping;
	BlenderWoodType type;
	BlenderNoiseBase noisebasis2;
	BlenderNoiseBasis noisebasis;
	float noisesize, turbulence;
	float bright, contrast;
	bool hard;
} BlenderWoodTexParam;

typedef struct {
 	TextureMapping3D mapping;
	DistanceMetric distancemetric;
	float feature_weight1;
	float feature_weight2;
	float feature_weight3;
	float feature_weight4;
	float noisesize;
	float intensity;
	float exponent;
 	float bright, contrast;
} BlenderVoronoiTexParam;

typedef struct {
	TextureMapping3D mapping;
	int octaves;
	float omega;
} WrinkledTexParam;

typedef struct {
	TextureMapping2D mapping;
} UVTexParam;

#define BAND_TEX_MAX_SIZE 16

typedef struct {
	unsigned int amountTexIndex;
	unsigned int size;
	float offsets[BAND_TEX_MAX_SIZE];
	Spectrum values[BAND_TEX_MAX_SIZE];
} BandTexParam;

typedef struct {
	unsigned int channel;
} HitPointGreyTexParam;

typedef struct {
	unsigned int texIndex;
} NormalMapTexParam;

typedef struct {
	TextureType type;
	union {
		BlenderBlendTexParam blenderBlend;
 		BlenderCloudsTexParam blenderClouds;
		BlenderDistortedNoiseTexParam blenderDistortedNoise;
		BlenderMagicTexParam blenderMagic;
		BlenderMarbleTexParam blenderMarble;
		BlenderMusgraveTexParam blenderMusgrave;
		BlenderNoiseTexParam blenderNoise;
		BlenderStucciTexParam blenderStucci;
 		BlenderWoodTexParam blenderWood;
		BlenderVoronoiTexParam blenderVoronoi;
		ConstFloatParam constFloat;
		ConstFloat3Param constFloat3;
		ImageMapTexParam imageMapTex;
		ScaleTexParam scaleTex;
		FresnelApproxNTexParam fresnelApproxN;
		FresnelApproxKTexParam fresnelApproxK;
		MixTexParam mixTex;
		CheckerBoard2DTexParam checkerBoard2D;
		CheckerBoard3DTexParam checkerBoard3D;
		FBMTexParam fbm;
		MarbleTexParam marble;
		DotsTexParam dots;
		BrickTexParam brick;
		AddTexParam addTex;
		WindyTexParam windy;
		WrinkledTexParam wrinkled;
		UVTexParam uvTex;
		BandTexParam band;
		HitPointGreyTexParam hitPointGrey;
        NormalMapTexParam normalMap;
	};
} Texture;

//------------------------------------------------------------------------------
// Some macro trick in order to have more readable code
//------------------------------------------------------------------------------

#if defined(SLG_OPENCL_KERNEL)

#if defined(PARAM_HAS_IMAGEMAPS)

#define IMAGEMAPS_PARAM_DECL , __global ImageMap *imageMapDescs, __global float **imageMapBuff
#define IMAGEMAPS_PARAM , imageMapDescs, imageMapBuff

#else

#define IMAGEMAPS_PARAM_DECL
#define IMAGEMAPS_PARAM

#endif

#define TEXTURES_PARAM_DECL , __global Texture *texs IMAGEMAPS_PARAM_DECL
#define TEXTURES_PARAM , texs IMAGEMAPS_PARAM

#endif


fixed float bug in kernel

fixed float bug in kernel

/*
  adapted from the Nvidia sdk sample
  http://developer.download.nvidia.com/compute/cuda/4_2/rel/sdk/website/OpenCL/html/samples.html

  mweigert@mpi-cbg.de
 */

#define maxSteps 200
#define tstep 0.01f

inline
float random(uint x, uint y)
{
    uint a = 4421 +(1+x)*(1+y) +x +y;

    for(int i=0; i < 10; i++)
    {
        a = (1664525 * a + 1013904223) % 79197919;
    }

    float rnd = (a*1.0f)/(79197919);

    // return .5f*(rnd-.5f);
	return -rnd;

}

// intersect ray with a box
// http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm

int intersectBox(float4 r_o, float4 r_d, float4 boxmin, float4 boxmax, float *tnear, float *tfar)
{
    // compute intersection of ray with all six bbox planes
    float4 invR = (float4)(1.0f,1.0f,1.0f,1.0f) / r_d;
    float4 tbot = invR * (boxmin - r_o);
    float4 ttop = invR * (boxmax - r_o);

    // re-order intersections to find smallest and largest on each axis
    float4 tmin = min(ttop, tbot);
    float4 tmax = max(ttop, tbot);

    // find the largest tmin and the smallest tmax
    float largest_tmin = max(max(tmin.x, tmin.y), max(tmin.x, tmin.z));
    float smallest_tmax = min(min(tmax.x, tmax.y), min(tmax.x, tmax.z));

	*tnear = largest_tmin;
	*tfar = smallest_tmax;

	return smallest_tmax > largest_tmin;
}

// void printf4(const float4 v)
// {
//   printf("kernel: %.2f  %.2f  %.2f  %.2f\n",v.x,v.y,v.z,v.w);
// }

float4 mult(__constant float* M, float4 v){
  float4 res;
  res.x = dot(v, (float4)(M[0],M[1],M[2],M[3]));
  res.y = dot(v, (float4)(M[4],M[5],M[6],M[7]));
  res.z = dot(v, (float4)(M[8],M[9],M[10],M[11]));
  res.w = dot(v, (float4)(M[12],M[13],M[14],M[15]));
  return res;
}

__kernel void
max_project_old(__global float *d_output,
			uint Nx, uint Ny,
			float boxMin_x,
			float boxMax_x,
			float boxMin_y,
			float boxMax_y,
			float boxMin_z,
			float boxMax_z,
			float maxVal,
			float gamma,
			__constant float* invP,
			__constant float* invM,
			__read_only image3d_t volume,
			int isShortType)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;

  float t = tnear;

  float4 pos;
  uint i;
  for(i=0; i<maxSteps; i++) {
  	pos = orig + t*direc;
	pos = pos*0.5f+0.5f;    // map position to [0, 1] coordinates

  	// read from 3D texture
	float newVal;
	if (isShortType)
	  newVal = 1.f*read_imageui(volume, volumeSampler, pos).x;
	else
	  newVal = read_imagef(volume, volumeSampler, pos).x;

	// newVal *= (1+2*exp(-10.f*i/maxSteps));
	// newVal *= exp(-2.f*i/maxSteps);

  	colVal = max(colVal, newVal);

  	t += tstep;
  	if (t > tfar) break;
  }

  colVal = (maxVal == 0)?colVal:colVal/maxVal;
  colVal = pow(colVal,gamma);

  if ((x < Nx) && (y < Ny))
	d_output[x+Nx*y] = colVal;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf4((float4)(tnear,tfar,0,0));

}

__kernel void
max_project(__global float *d_output, __global float *d_alpha_output,
			uint Nx, uint Ny,
			float boxMin_x,
			float boxMax_x,
			float boxMin_y,
			float boxMax_y,
			float boxMin_z,
			float boxMax_z,
			float minVal,

			float maxVal,
			float gamma,
			float alpha_pow,
			__constant float* invP,
			__constant float* invM,
			__read_only image3d_t volume,
			int isShortType)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;

  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;
  float alphaVal = 0;

  float t = tnear;

  float4 pos;
  uint i;

  float dt = (tfar-tnear)/maxSteps;

  float tmax = tnear;

  //dither the original

  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  // dt = tstep;

  for(i=0; i<=maxSteps; i++) {
  	pos = orig + t*direc;
	pos = pos*0.5f+0.5f;    // map position to [0, 1] coordinates

  	// read from 3D texture
	float newVal;
	if (isShortType)
	  newVal = 1.f*read_imageui(volume, volumeSampler, pos).x;
	else
	  newVal = read_imagef(volume, volumeSampler, pos).x;

	// // this is still slow as hell...

	// newVal = (maxVal == 0)?newVal:newVal/maxVal;
	// colVal = max(colVal, newVal*(1-alphaVal));

  	// alphaVal += (1.f-alphaVal)*pow(newVal,alpha_pow);

	// // this ist still slow as hell...
	// alphaVal += maxSteps*dt*(1.f-alphaVal)*pow(newVal,alpha_pow);

	if (alpha_pow>.02)
	  newVal *= 1./(1+alpha_pow*i);

	colVal = max(colVal, newVal);

	t += dt;

  	// if ((t > tfar) || (alphaVal >=1.f))
	//   break;

	// if (t > tfar)
	//   break;

  }

  colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  // alphaVal = .3f*(tfar-tnear);

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("start:  %.2f %.2f %.2f %.2f\n",tnear,tfar,tmax,alphaVal);

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("%.5f %.5f\n",tnear,tfar);

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = colVal;

  	// d_alpha_output[x+Nx*y] = alphaVal*alphaVal+(1-alphaVal)*colVal;
	// d_alpha_output[x+Nx*y] = colVal+(1.-colVal)*exp(-alpha_pow);
	d_alpha_output[x+Nx*y] = alphaVal;
  }

}

#define read_image(volume,sampler, pos,isShortType) (isShortType?1.f*read_imageui(volume, sampler, pos).x:read_imagef(volume, sampler, pos).x)

__kernel void iso_surface(
						  __global float *d_output,
						  __global float *d_alpha_output,
						  uint Nx, uint Ny,
						  float boxMin_x,
						  float boxMax_x,
						  float boxMin_y,
						  float boxMax_y,
						  float boxMin_z,
						  float boxMax_z,
						  float isoVal,
						  float gamma,
						  __constant float* invP,
						  __constant float* invM,
						  __read_only image3d_t volume,
						  int isShortType)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;
  float alphaVal = 0;

  float4 light = (float4)(2,-1,-2,0);

  float c_ambient = .3;
  float c_diffuse = .4;
  float c_specular = .3;

  // c_ambient = 0.;
  // c_diffuse = 1.;
  // c_specular = .0;

  light = mult(invM,light);
  light = normalize(light);

  float t = tnear;

  float4 pos = orig + tnear*direc;;
  uint i;

  float dt = (tfar-tnear)/maxSteps;

  float newVal = read_image(volume, volumeSampler, pos*0.5f+0.5f, isShortType);
  bool isGreater = newVal>isoVal;
  bool hitIso = false;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("start:  %.2f %.2f %d\n",newVal,isoVal,isGreater);

  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  // orig += dt*random(entropy+x,entropy+y)*direc;

  for(i=1; i<maxSteps; i++) {
  	pos = orig + (t+dt*i)*direc;
	pos = pos*0.5f+0.5f;    // map position to [0, 1] coordinates

	// newVal = read_imagef(volume, volumeSampler, pos).x;
	newVal = read_image(volume, volumeSampler, pos, isShortType);

	// if ((x == Nx/2) && (y == Ny/2))
	//   printf("%.3f %d %d %d \n",newVal,i,newVal>isoVal,hitIso);

	if ((newVal>isoVal) != isGreater){
	  hitIso = true;
	  break;
	}
  }

  // find real intersection point
  // still broken
  // float oldVal = read_image(volume, volumeSampler, .5f*(orig + (t+dt*(i-1))*direc)+.5f, isShortType);
  // float lam = (newVal - isoVal)/(newVal-oldVal);
  // pos = .5f*(orig + (t+dt*((i-1)*(1-lam)+i*lam) )*direc)+.5f;

  // now phong shading

  // the normal

  float4 normal;
  float4 reflect;
  float h = dt;

  h*= pow(gamma,2);

  // normal.x = read_image(volume,volumeSampler,pos+(float4)(h,0,0,0), isShortType)-
  // 	read_image(volume,volumeSampler,pos+(float4)(-h,0,0,0), isShortType);
  // normal.y = read_image(volume,volumeSampler,pos+(float4)(0,h,0,0), isShortType)-
  // 	read_image(volume,volumeSampler,pos+(float4)(0,-h,0,0), isShortType);
  // normal.z = read_image(volume,volumeSampler,pos+(float4)(0,0,h,0), isShortType)-
  // 	read_image(volume,volumeSampler,pos+(float4)(0,0,-h,0), isShortType);

  // robust 2nd order
  normal.x = 2.f*read_image(volume,volumeSampler,pos+(float4)(h,0,0,0), isShortType)-
  	2.f*read_image(volume,volumeSampler,pos+(float4)(-h,0,0,0), isShortType)+
	read_image(volume,volumeSampler,pos+(float4)(2.f*h,0,0,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(-2.f*h,0,0,0), isShortType);

  normal.y = 2.f*read_image(volume,volumeSampler,pos+(float4)(0,h,0,0), isShortType)-
  	2.f*read_image(volume,volumeSampler,pos+(float4)(0,-h,0,0), isShortType)+
	read_image(volume,volumeSampler,pos+(float4)(0,2.f*h,0,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,-2.f*h,0,0), isShortType);

  normal.z = read_image(volume,volumeSampler,pos+(float4)(0,0,h,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,0,-h,0), isShortType)+
	read_image(volume,volumeSampler,pos+(float4)(0,0,2.f*h,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,0,-2.f*h,0), isShortType);

  normal.w = 0;

  //flip normal if we are comming from values greater than isoVal...
  normal = (1.f-2*isGreater)*normalize(normal);

  reflect = 2*dot(light,normal)*normal-light;

  float diffuse = fmax(0.f,dot(light,normal));
  float specular = pow(fmax(0.f,dot(normalize(reflect),normalize(direc))),10);

  // phong shading
  if (hitIso){
	colVal = c_ambient
	  + c_diffuse*diffuse
	  + (diffuse>0)*c_specular*specular;

  }

  // for depth test...
  alphaVal = tnear;

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = colVal;
	d_alpha_output[x+Nx*y] = alphaVal;

  }

}

__kernel void
max_project_float(__global float *d_output, __global float *d_alpha_output,
			uint Nx, uint Ny,
			float boxMin_x,
			float boxMax_x,
			float boxMin_y,
			float boxMax_y,
			float boxMin_z,
			float boxMax_z,
			float minVal,
			float maxVal,
			float gamma,
			float alpha_pow,
			__constant float* invP,
			__constant float* invM,
			__read_only image3d_t volume)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);

  // if (x==300 && y == 300)
  // 	printf("%.2f  %.2f %.2f  %.2f \n",invP[0],invP[1],invP[2],invP[3]);

  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;
  float alphaVal = 0;

  float t = tnear;
  float dt = (tfar-tnear)/maxSteps;

  //dither the original
  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  float4 dpos = .5f*dt*direc;
  float4 pos = 0.5f *(1.f + orig + tnear*direc);

  uint i;

  for(i=0; i<=maxSteps; i++) {
	colVal = max(colVal, read_imagef(volume, volumeSampler, pos+i*dpos).x);
  }

  colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = colVal;
	d_alpha_output[x+Nx*y] = alphaVal;
  }
}

__kernel void
max_project_short(__global float *d_output, __global float *d_alpha_output,
			uint Nx, uint Ny,
			float boxMin_x,
			float boxMax_x,
			float boxMin_y,
			float boxMax_y,
			float boxMin_z,
			float boxMax_z,
			float minVal,
			float maxVal,
			float gamma,
			float alpha_pow,
			__constant float* invP,
			__constant float* invM,
			__read_only image3d_t volume)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;
  float alphaVal = 0;

  float t = tnear;
  float dt = (tfar-tnear)/maxSteps;

  //dither the original
  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  float4 dpos = .5f*dt*direc;
  float4 pos = 0.5f *(1.f + orig + tnear*direc);

  uint i;

  for(i=0; i<=maxSteps; i++) {
	colVal = max(colVal, 1.f*read_imageui(volume, volumeSampler, pos+i*dpos).x);
  }

  colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = colVal;
	d_alpha_output[x+Nx*y] = alphaVal;
  }
}

__kernel void
max_project_part_float(__global float *d_output, __global float *d_alpha_output,
				 uint Nx, uint Ny,
				 float boxMin_x,
				 float boxMax_x,
				 float boxMin_y,
				 float boxMax_y,
				 float boxMin_z,
				 float boxMax_z,
				 float minVal,
				 float maxVal,
				 float gamma,
				 float alpha_pow,
				 int numParts,
				 int currentPart,
				 __constant float* invP,
				 __constant float* invM,
				 __read_only image3d_t volume
				 )
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);

  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;

  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  // dt = tstep;

  float colVal = 0;
  float alphaVal = 0;

  float dt = (tfar-tnear)/maxSteps*numParts;
  float t0 = tnear + dt*currentPart/numParts;

  //  dither the original
  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  float4 delta_pos = .5f*dt*direc;
  float4 pos = 0.5f *(1.f + orig + t0*direc);

  uint i;

  float cumsum = 1;
  float newVal;

  for(i=0; i<=maxSteps/numParts; i++) {
	// colVal = max(colVal, read_imagef(volume, volumeSampler, pos+i*delta_pos).x);
	newVal = read_imagef(volume, volumeSampler, pos+i*delta_pos).x;
	newVal = (maxVal == 0)?newVal:(newVal-minVal)/(maxVal-minVal);
	colVal = max(colVal,cumsum*newVal);
	cumsum *= (1.f-.1f*alpha_pow*newVal);

  }

  // colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("%.5f %.5f\n",tnear,tfar);

  if ((x < Nx) && (y < Ny)){
	if (currentPart==0){
	  d_output[x+Nx*y] = colVal;
	  d_alpha_output[x+Nx*y] = alphaVal;
	}
	else{
	  d_output[x+Nx*y] = max(colVal,d_output[x+Nx*y]);
	  d_alpha_output[x+Nx*y] = max(alphaVal,d_alpha_output[x+Nx*y]);
	}

  }

}
__kernel void
max_project_part_short(__global float *d_output, __global float *d_alpha_output,
				 uint Nx, uint Ny,
				 float boxMin_x,
				 float boxMax_x,
				 float boxMin_y,
				 float boxMax_y,
				 float boxMin_z,
				 float boxMax_z,
				 float minVal,
				 float maxVal,
				 float gamma,
				 float alpha_pow,
				 int numParts,
				 int currentPart,
				 __constant float* invP,
				 __constant float* invM,
				 __read_only image3d_t volume
				 )
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;

  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  // dt = tstep;

  float colVal = 0;
  float alphaVal = 0;

  float dt = (tfar-tnear)/maxSteps*numParts;
  float t0 = tnear + dt*currentPart/numParts;

  //  dither the original
  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  float4 dpos = .5f*dt*direc;
  float4 pos = 0.5f *(1.f + orig + t0*direc);

  uint i;

  float newVal;
  float cumsum = 1.f;

  for(i=0; i<=maxSteps/numParts; i++) {
	// colVal = max(colVal, 1.f*read_imageui(volume, volumeSampler, pos+i*dpos).x);
	newVal = 1.f*read_imageui(volume, volumeSampler, pos+i*dpos).x;
	newVal = (maxVal == 0)?newVal:(newVal-minVal)/(maxVal-minVal);
	colVal = max(colVal,cumsum*newVal);
	cumsum *= (1.f-.1f*alpha_pow*newVal);

  }

  // colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  // alphaVal = .3f*(tfar-tnear);

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("start:  %.2f %.2f %.2f %.2f\n",tnear,tfar,tmax,alphaVal);

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("%.5f %.5f\n",tnear,tfar);

  if ((x < Nx) && (y < Ny)){
	if (currentPart==0){
	  d_output[x+Nx*y] = colVal;
	  d_alpha_output[x+Nx*y] = alphaVal;
	}
	else{
	  d_output[x+Nx*y] = max(colVal,d_output[x+Nx*y]);
	  d_alpha_output[x+Nx*y] = max(alphaVal,d_alpha_output[x+Nx*y]);
	}

  }

}

__kernel void iso_surface_new(
						  __global float *d_normals,
						  __global float *d_alpha,
						  uint Nx, uint Ny,
						  float boxMin_x,
						  float boxMax_x,
						  float boxMin_y,
						  float boxMax_y,
						  float boxMin_z,
						  float boxMax_z,
						  float isoVal,
						  float gamma,
						  __constant float* invP,
						  __constant float* invM,
						  __read_only image3d_t volume,
						  int isShortType)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_normals[0+3*x+3*Nx*y] = 0.f;
	  d_normals[1+3*x+3*Nx*y] = 0.f;
	  d_normals[2+3*x+3*Nx*y] = 0.f;
	  d_alpha[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float t = tnear;

  float4 pos = orig + tnear*direc;;

  uint i;

  float dt = (tfar-tnear)/maxSteps;

  float newVal = read_image(volume, volumeSampler, pos*0.5f+0.5f, isShortType);
  bool isGreater = newVal>isoVal;
  bool hitIso = false;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("start:  %.2f %.2f %d\n",newVal,isoVal,isGreater);

  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  // orig += dt*random(entropy+x,entropy+y)*direc;

  for(t=tnear; t<tfar; t+=dt) {
  	pos = orig + t*direc;
	pos = pos*0.5f+0.5f;    // map position to [0, 1] coordinates

	newVal = read_image(volume, volumeSampler, pos, isShortType);

	if ((newVal>isoVal) != isGreater){
	  hitIso = true;
	  break;
	}
  }

  if (!hitIso) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_normals[0+3*x+3*Nx*y] = 0.f;
	  d_normals[1+3*x+3*Nx*y] = 0.f;
	  d_normals[2+3*x+3*Nx*y] = 0.f;
	  d_alpha[x+Nx*y] = 0.f;
  	}
  	return;
  }

  // the normal

  // if (x==300 &&y ==300)
  // 	printf("diffuse: %.4f \n",tnear);

  float4 normal;
  float h = dt;

  h*= pow(gamma,2);

  normal.x = read_image(volume,volumeSampler,pos+(float4)(h,0,0,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(-h,0,0,0), isShortType);
  normal.y = read_image(volume,volumeSampler,pos+(float4)(0,h,0,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,-h,0,0), isShortType);
  normal.z = read_image(volume,volumeSampler,pos+(float4)(0,0,h,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,0,-h,0), isShortType);

  normal.w = 0;

  //flip normal if we are comming from values greater than isoVal...
  normal = (1.f-2*isGreater)*normalize(normal);

  if ((x < Nx) && (y < Ny)){
	  d_normals[0+3*x+3*Nx*y] = normal.x;
	  d_normals[1+3*x+3*Nx*y] = normal.y;
	  d_normals[2+3*x+3*Nx*y] = normal.z;
	  d_alpha[x+Nx*y] = t;
  }

}

__kernel void blur_normals_x(__global float *d_input,
							 __global float *d_output,
							 int N)

{

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  uint Nx = get_global_size(0);
  uint Ny = get_global_size(1);

  float4 res = (float4)(0.f,0.f,0.f,0.f);
  float hsum = 0.f;

  float fac = -.1f/N/N;

  for (int i = -N; i <= N; ++i){
	float h = exp(fac*i*i);
	hsum += h;

	res.x += h*d_input[0+3*(x+i)+3*Nx*y];
	res.y += h*d_input[1+3*(x+i)+3*Nx*y];
	res.z += h*d_input[2+3*(x+i)+3*Nx*y];

  }

  // if (x==300 &&y ==300)
  // 	  printf("%.2f \n",hsum);

  res *= 1.f/hsum;

  //res = normalize(res);

  d_output[0+3*x+3*Nx*y] = res.x;
  d_output[1+3*x+3*Nx*y] = res.y;
  d_output[2+3*x+3*Nx*y] = res.z;

}

__kernel void blur_normals_y(__global float *d_input,
							 __global float *d_output,
							 int N)

{

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  uint Nx = get_global_size(0);
  uint Ny = get_global_size(1);

  float4 res = (float4)(0.f,0.f,0.f,0.f);
  float hsum = 0.f;

  float fac = -.1f/N/N;

  for (int i = -N; i <= N; ++i){
	float h = exp(fac*i*i);
	hsum += h;

	res.x += h*d_input[0+3*x+3*Nx*(y+i)];
	res.y += h*d_input[1+3*x+3*Nx*(y+i)];
	res.z += h*d_input[2+3*x+3*Nx*(y+i)];

  }

  // if (x==300 &&y ==300)
  // 	  printf("%.2f \n",hsum);

  res *= 1.f/hsum;

  //res = normalize(res);

  d_output[0+3*x+3*Nx*y] = res.x;
  d_output[1+3*x+3*Nx*y] = res.y;
  d_output[2+3*x+3*Nx*y] = res.z;

}

__kernel void iso_shading(__global float *d_normals,
						  __global float *d_alpha,
						  __constant float *invM,
						  __constant float *invP,
						  __global float *d_output)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);
  uint Nx = get_global_size(0);
  uint Ny = get_global_size(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  float4 normal;
  normal.x = d_normals[0+3*x+3*Nx*y];
  normal.y = d_normals[1+3*x+3*Nx*y];
  normal.z = d_normals[2+3*x+3*Nx*y];
  normal.w = 0.f;

  normal = normalize(normal);

  float4 reflect;

  float colVal = 0;
  float alphaVal = 0;

  float4 light = (float4)(2,-1,-2,0);

  float c_ambient = .3;
  float c_diffuse = .4;
  float c_specular = .3;

  light = mult(invM,light);
  light = normalize(light);

  reflect = 2*dot(light,normal)*normal-light;

  float diffuse = fmax(0.f,-dot(light,normal));
  float specular = pow(fmax(0.f,-dot(normalize(reflect),normalize(direc))),10);

  colVal = c_ambient
	+ c_diffuse*diffuse
	+ (diffuse>0)*c_specular*specular;

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = (d_alpha[x+Nx*y]>0)?colVal:0.f;
  }

  // if (x==300 &&y ==300)
  // 	printf("diffuse: %.4f \n",dot(light,normal));

}

/*
  adapted from the Nvidia sdk sample
  http://developer.download.nvidia.com/compute/cuda/4_2/rel/sdk/website/OpenCL/html/samples.html

  mweigert@mpi-cbg.de
 */

#define maxSteps 200
#define tstep 0.01f

inline
float random(uint x, uint y)
{
    uint a = 4421 +(1+x)*(1+y) +x +y;

    for(int i=0; i < 10; i++)
    {
        a = (1664525 * a + 1013904223) % 79197919;
    }

    float rnd = (a*1.0f)/(79197919);

    // return .5f*(rnd-.5f);
	return -rnd;

}

// intersect ray with a box
// http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm

int intersectBox(float4 r_o, float4 r_d, float4 boxmin, float4 boxmax, float *tnear, float *tfar)
{
    // compute intersection of ray with all six bbox planes
    float4 invR = (float4)(1.0f,1.0f,1.0f,1.0f) / r_d;
    float4 tbot = invR * (boxmin - r_o);
    float4 ttop = invR * (boxmax - r_o);

    // re-order intersections to find smallest and largest on each axis
    float4 tmin = min(ttop, tbot);
    float4 tmax = max(ttop, tbot);

    // find the largest tmin and the smallest tmax
    float largest_tmin = max(max(tmin.x, tmin.y), max(tmin.x, tmin.z));
    float smallest_tmax = min(min(tmax.x, tmax.y), min(tmax.x, tmax.z));

	*tnear = largest_tmin;
	*tfar = smallest_tmax;

	return smallest_tmax > largest_tmin;
}

// void printf4(const float4 v)
// {
//   printf("kernel: %.2f  %.2f  %.2f  %.2f\n",v.x,v.y,v.z,v.w);
// }

float4 mult(__constant float* M, float4 v){
  float4 res;
  res.x = dot(v, (float4)(M[0],M[1],M[2],M[3]));
  res.y = dot(v, (float4)(M[4],M[5],M[6],M[7]));
  res.z = dot(v, (float4)(M[8],M[9],M[10],M[11]));
  res.w = dot(v, (float4)(M[12],M[13],M[14],M[15]));
  return res;
}

__kernel void
max_project_old(__global float *d_output,
			uint Nx, uint Ny,
			float boxMin_x,
			float boxMax_x,
			float boxMin_y,
			float boxMax_y,
			float boxMin_z,
			float boxMax_z,
			float maxVal,
			float gamma,
			__constant float* invP,
			__constant float* invM,
			__read_only image3d_t volume,
			int isShortType)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;

  float t = tnear;

  float4 pos;
  uint i;
  for(i=0; i<maxSteps; i++) {
  	pos = orig + t*direc;
	pos = pos*0.5f+0.5f;    // map position to [0, 1] coordinates

  	// read from 3D texture
	float newVal;
	if (isShortType)
	  newVal = 1.f*read_imageui(volume, volumeSampler, pos).x;
	else
	  newVal = read_imagef(volume, volumeSampler, pos).x;

	// newVal *= (1+2*exp(-10.f*i/maxSteps));
	// newVal *= exp(-2.f*i/maxSteps);

  	colVal = max(colVal, newVal);

  	t += tstep;
  	if (t > tfar) break;
  }

  colVal = (maxVal == 0)?colVal:colVal/maxVal;
  colVal = pow(colVal,gamma);

  if ((x < Nx) && (y < Ny))
	d_output[x+Nx*y] = colVal;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf4((float4)(tnear,tfar,0,0));

}

__kernel void
max_project(__global float *d_output, __global float *d_alpha_output,
			uint Nx, uint Ny,
			float boxMin_x,
			float boxMax_x,
			float boxMin_y,
			float boxMax_y,
			float boxMin_z,
			float boxMax_z,
			float minVal,

			float maxVal,
			float gamma,
			float alpha_pow,
			__constant float* invP,
			__constant float* invM,
			__read_only image3d_t volume,
			int isShortType)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;

  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;
  float alphaVal = 0;

  float t = tnear;

  float4 pos;
  uint i;

  float dt = (tfar-tnear)/maxSteps;

  float tmax = tnear;

  //dither the original

  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  // dt = tstep;

  for(i=0; i<=maxSteps; i++) {
  	pos = orig + t*direc;
	pos = pos*0.5f+0.5f;    // map position to [0, 1] coordinates

  	// read from 3D texture
	float newVal;
	if (isShortType)
	  newVal = 1.f*read_imageui(volume, volumeSampler, pos).x;
	else
	  newVal = read_imagef(volume, volumeSampler, pos).x;

	// // this is still slow as hell...

	// newVal = (maxVal == 0)?newVal:newVal/maxVal;
	// colVal = max(colVal, newVal*(1-alphaVal));

  	// alphaVal += (1.f-alphaVal)*pow(newVal,alpha_pow);

	// // this ist still slow as hell...
	// alphaVal += maxSteps*dt*(1.f-alphaVal)*pow(newVal,alpha_pow);

	if (alpha_pow>.02)
	  newVal *= 1./(1+alpha_pow*i);

	colVal = max(colVal, newVal);

	t += dt;

  	// if ((t > tfar) || (alphaVal >=1.f))
	//   break;

	// if (t > tfar)
	//   break;

  }

  colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  // alphaVal = .3f*(tfar-tnear);

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("start:  %.2f %.2f %.2f %.2f\n",tnear,tfar,tmax,alphaVal);

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("%.5f %.5f\n",tnear,tfar);

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = colVal;

  	// d_alpha_output[x+Nx*y] = alphaVal*alphaVal+(1-alphaVal)*colVal;
	// d_alpha_output[x+Nx*y] = colVal+(1.-colVal)*exp(-alpha_pow);
	d_alpha_output[x+Nx*y] = alphaVal;
  }

}

#define read_image(volume,sampler, pos,isShortType) (isShortType?1.f*read_imageui(volume, sampler, pos).x:read_imagef(volume, sampler, pos).x)

__kernel void iso_surface(
						  __global float *d_output,
						  __global float *d_alpha_output,
						  uint Nx, uint Ny,
						  float boxMin_x,
						  float boxMax_x,
						  float boxMin_y,
						  float boxMax_y,
						  float boxMin_z,
						  float boxMax_z,
						  float isoVal,
						  float gamma,
						  __constant float* invP,
						  __constant float* invM,
						  __read_only image3d_t volume,
						  int isShortType)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;
  float alphaVal = 0;

  float4 light = (float4)(2,-1,-2,0);

  float c_ambient = .3;
  float c_diffuse = .4;
  float c_specular = .3;

  // c_ambient = 0.;
  // c_diffuse = 1.;
  // c_specular = .0;

  light = mult(invM,light);
  light = normalize(light);

  float t = tnear;

  float4 pos = orig + tnear*direc;;
  uint i;

  float dt = (tfar-tnear)/maxSteps;

  float newVal = read_image(volume, volumeSampler, pos*0.5f+0.5f, isShortType);
  bool isGreater = newVal>isoVal;
  bool hitIso = false;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("start:  %.2f %.2f %d\n",newVal,isoVal,isGreater);

  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  // orig += dt*random(entropy+x,entropy+y)*direc;

  for(i=1; i<maxSteps; i++) {
  	pos = orig + (t+dt*i)*direc;
	pos = pos*0.5f+0.5f;    // map position to [0, 1] coordinates

	// newVal = read_imagef(volume, volumeSampler, pos).x;
	newVal = read_image(volume, volumeSampler, pos, isShortType);

	// if ((x == Nx/2) && (y == Ny/2))
	//   printf("%.3f %d %d %d \n",newVal,i,newVal>isoVal,hitIso);

	if ((newVal>isoVal) != isGreater){
	  hitIso = true;
	  break;
	}
  }

  // find real intersection point
  // still broken
  // float oldVal = read_image(volume, volumeSampler, .5f*(orig + (t+dt*(i-1))*direc)+.5f, isShortType);
  // float lam = (newVal - isoVal)/(newVal-oldVal);
  // pos = .5f*(orig + (t+dt*((i-1)*(1-lam)+i*lam) )*direc)+.5f;

  // now phong shading

  // the normal

  float4 normal;
  float4 reflect;
  float h = dt;

  h*= pow(gamma,2);

  // normal.x = read_image(volume,volumeSampler,pos+(float4)(h,0,0,0), isShortType)-
  // 	read_image(volume,volumeSampler,pos+(float4)(-h,0,0,0), isShortType);
  // normal.y = read_image(volume,volumeSampler,pos+(float4)(0,h,0,0), isShortType)-
  // 	read_image(volume,volumeSampler,pos+(float4)(0,-h,0,0), isShortType);
  // normal.z = read_image(volume,volumeSampler,pos+(float4)(0,0,h,0), isShortType)-
  // 	read_image(volume,volumeSampler,pos+(float4)(0,0,-h,0), isShortType);

  // robust 2nd order
  normal.x = 2.f*read_image(volume,volumeSampler,pos+(float4)(h,0,0,0), isShortType)-
  	2.f*read_image(volume,volumeSampler,pos+(float4)(-h,0,0,0), isShortType)+
	read_image(volume,volumeSampler,pos+(float4)(2.f*h,0,0,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(-2.f*h,0,0,0), isShortType);

  normal.y = 2.f*read_image(volume,volumeSampler,pos+(float4)(0,h,0,0), isShortType)-
  	2.f*read_image(volume,volumeSampler,pos+(float4)(0,-h,0,0), isShortType)+
	read_image(volume,volumeSampler,pos+(float4)(0,2.f*h,0,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,-2.f*h,0,0), isShortType);

  normal.z = read_image(volume,volumeSampler,pos+(float4)(0,0,h,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,0,-h,0), isShortType)+
	read_image(volume,volumeSampler,pos+(float4)(0,0,2.f*h,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,0,-2.f*h,0), isShortType);

  normal.w = 0;

  //flip normal if we are comming from values greater than isoVal...
  normal = (1.f-2*isGreater)*normalize(normal);

  reflect = 2*dot(light,normal)*normal-light;

  float diffuse = fmax(0.f,dot(light,normal));
  float specular = pow(fmax(0.f,dot(normalize(reflect),normalize(direc))),10);

  // phong shading
  if (hitIso){
	colVal = c_ambient
	  + c_diffuse*diffuse
	  + (diffuse>0)*c_specular*specular;

  }

  // for depth test...
  alphaVal = tnear;

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = colVal;
	d_alpha_output[x+Nx*y] = alphaVal;

  }

}

__kernel void
max_project_float(__global float *d_output, __global float *d_alpha_output,
			uint Nx, uint Ny,
			float boxMin_x,
			float boxMax_x,
			float boxMin_y,
			float boxMax_y,
			float boxMin_z,
			float boxMax_z,
			float minVal,
			float maxVal,
			float gamma,
			float alpha_pow,
			__constant float* invP,
			__constant float* invM,
			__read_only image3d_t volume)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);

  // if (x==300 && y == 300)
  // 	printf("%.2f  %.2f %.2f  %.2f \n",invP[0],invP[1],invP[2],invP[3]);

  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;
  float alphaVal = 0;

  float t = tnear;
  float dt = (tfar-tnear)/maxSteps;

  //dither the original
  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  float4 dpos = .5f*dt*direc;
  float4 pos = 0.5f *(1.f + orig + tnear*direc);

  uint i;

  for(i=0; i<=maxSteps; i++) {
	colVal = max(colVal, read_imagef(volume, volumeSampler, pos+i*dpos).x);
  }

  colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = colVal;
	d_alpha_output[x+Nx*y] = alphaVal;
  }
}

__kernel void
max_project_short(__global float *d_output, __global float *d_alpha_output,
			uint Nx, uint Ny,
			float boxMin_x,
			float boxMax_x,
			float boxMin_y,
			float boxMax_y,
			float boxMin_z,
			float boxMax_z,
			float minVal,
			float maxVal,
			float gamma,
			float alpha_pow,
			__constant float* invP,
			__constant float* invM,
			__read_only image3d_t volume)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float colVal = 0;
  float alphaVal = 0;

  float t = tnear;
  float dt = (tfar-tnear)/maxSteps;

  //dither the original
  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  float4 dpos = .5f*dt*direc;
  float4 pos = 0.5f *(1.f + orig + tnear*direc);

  uint i;

  for(i=0; i<=maxSteps; i++) {
	colVal = max(colVal, 1.f*read_imageui(volume, volumeSampler, pos+i*dpos).x);
  }

  colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = colVal;
	d_alpha_output[x+Nx*y] = alphaVal;
  }
}

__kernel void
max_project_part_float(__global float *d_output, __global float *d_alpha_output,
				 uint Nx, uint Ny,
				 float boxMin_x,
				 float boxMax_x,
				 float boxMin_y,
				 float boxMax_y,
				 float boxMin_z,
				 float boxMax_z,
				 float minVal,
				 float maxVal,
				 float gamma,
				 float alpha_pow,
				 int numParts,
				 int currentPart,
				 __constant float* invP,
				 __constant float* invM,
				 __read_only image3d_t volume
				 )
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);

  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;

  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  // dt = tstep;

  float colVal = 0;
  float alphaVal = 0;

  float dt = (tfar-tnear)/maxSteps*numParts;
  float t0 = tnear + dt*currentPart/numParts;

  //  dither the original
  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  float4 delta_pos = .5f*dt*direc;
  float4 pos = 0.5f *(1.f + orig + t0*direc);

  uint i;

  float cumsum = 1;
  float newVal;

  for(i=0; i<=maxSteps/numParts; i++) {
	// colVal = max(colVal, read_imagef(volume, volumeSampler, pos+i*delta_pos).x);
	newVal = read_imagef(volume, volumeSampler, pos+i*delta_pos).x;
	newVal = (maxVal == 0)?newVal:(newVal-minVal)/(maxVal-minVal);
	colVal = max(colVal,cumsum*newVal);
	cumsum *= (1.f-.1f*alpha_pow*newVal);

  }

  // colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("%.5f %.5f\n",tnear,tfar);

  if ((x < Nx) && (y < Ny)){
	if (currentPart==0){
	  d_output[x+Nx*y] = colVal;
	  d_alpha_output[x+Nx*y] = alphaVal;
	}
	else{
	  d_output[x+Nx*y] = max(colVal,d_output[x+Nx*y]);
	  d_alpha_output[x+Nx*y] = max(alphaVal,d_alpha_output[x+Nx*y]);
	}

  }

}
__kernel void
max_project_part_short(__global float *d_output, __global float *d_alpha_output,
				 uint Nx, uint Ny,
				 float boxMin_x,
				 float boxMax_x,
				 float boxMin_y,
				 float boxMax_y,
				 float boxMin_z,
				 float boxMax_z,
				 float minVal,
				 float maxVal,
				 float gamma,
				 float alpha_pow,
				 int numParts,
				 int currentPart,
				 __constant float* invP,
				 __constant float* invM,
				 __read_only image3d_t volume
				 )
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_output[x+Nx*y] = 0.f;
	  d_alpha_output[x+Nx*y] = 0.f;

  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  // dt = tstep;

  float colVal = 0;
  float alphaVal = 0;

  float dt = (tfar-tnear)/maxSteps*numParts;
  float t0 = tnear + dt*currentPart/numParts;

  //  dither the original
  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  orig += dt*random(entropy+x,entropy+y)*direc;

  float4 dpos = .5f*dt*direc;
  float4 pos = 0.5f *(1.f + orig + t0*direc);

  uint i;

  float newVal;
  float cumsum = 1.f;

  for(i=0; i<=maxSteps/numParts; i++) {
	// colVal = max(colVal, 1.f*read_imageui(volume, volumeSampler, pos+i*dpos).x);
	newVal = 1.f*read_imageui(volume, volumeSampler, pos+i*dpos).x;
	newVal = (maxVal == 0)?newVal:(newVal-minVal)/(maxVal-minVal);
	colVal = max(colVal,cumsum*newVal);
	cumsum *= (1.f-.1f*alpha_pow*newVal);

  }

  // colVal = (maxVal == 0)?colVal:(colVal-minVal)/(maxVal-minVal);

  alphaVal = colVal;

  // alphaVal = .3f*(tfar-tnear);

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("start:  %.2f %.2f %.2f %.2f\n",tnear,tfar,tmax,alphaVal);

  colVal = pow(colVal,gamma);

  colVal = clamp(colVal,0.f,1.f);

  alphaVal = clamp(alphaVal,0.f,1.f);

  // for depth test...
  alphaVal = tnear;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("%.5f %.5f\n",tnear,tfar);

  if ((x < Nx) && (y < Ny)){
	if (currentPart==0){
	  d_output[x+Nx*y] = colVal;
	  d_alpha_output[x+Nx*y] = alphaVal;
	}
	else{
	  d_output[x+Nx*y] = max(colVal,d_output[x+Nx*y]);
	  d_alpha_output[x+Nx*y] = max(alphaVal,d_alpha_output[x+Nx*y]);
	}

  }

}

__kernel void iso_surface_new(
						  __global float *d_normals,
						  __global float *d_alpha,
						  uint Nx, uint Ny,
						  float boxMin_x,
						  float boxMax_x,
						  float boxMin_y,
						  float boxMax_y,
						  float boxMin_z,
						  float boxMax_z,
						  float isoVal,
						  float gamma,
						  __constant float* invP,
						  __constant float* invM,
						  __read_only image3d_t volume,
						  int isShortType)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  float4 boxMin = (float4)(boxMin_x,boxMin_y,boxMin_z,1.f);
  float4 boxMax = (float4)(boxMax_x,boxMax_y,boxMax_z,1.f);

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  // find intersection with box
  float tnear, tfar;
  int hit = intersectBox(orig,direc, boxMin, boxMax, &tnear, &tfar);
  if (!hit) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_normals[0+3*x+3*Nx*y] = 0.f;
	  d_normals[1+3*x+3*Nx*y] = 0.f;
	  d_normals[2+3*x+3*Nx*y] = 0.f;
	  d_alpha[x+Nx*y] = 0.f;
  	}
  	return;
  }
  if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

  float t = tnear;

  float4 pos = orig + tnear*direc;;

  uint i;

  float dt = (tfar-tnear)/maxSteps;

  float newVal = read_image(volume, volumeSampler, pos*0.5f+0.5f, isShortType);
  bool isGreater = newVal>isoVal;
  bool hitIso = false;

  // if ((x == Nx/2) && (y == Ny/2))
  // 	printf("start:  %.2f %.2f %d\n",newVal,isoVal,isGreater);

  uint entropy = (uint)( 6779514*length(orig) + 6257327*length(direc) );
  // orig += dt*random(entropy+x,entropy+y)*direc;

  for(t=tnear; t<tfar; t+=dt) {
  	pos = orig + t*direc;
	pos = pos*0.5f+0.5f;    // map position to [0, 1] coordinates

	newVal = read_image(volume, volumeSampler, pos, isShortType);

	if ((newVal>isoVal) != isGreater){
	  hitIso = true;
	  break;
	}
  }

  if (!hitIso) {
  	if ((x < Nx) && (y < Ny)) {
  	  d_normals[0+3*x+3*Nx*y] = 0.f;
	  d_normals[1+3*x+3*Nx*y] = 0.f;
	  d_normals[2+3*x+3*Nx*y] = 0.f;
	  d_alpha[x+Nx*y] = 0.f;
  	}
  	return;
  }

  // the normal

  // if (x==300 &&y ==300)
  // 	printf("diffuse: %.4f \n",tnear);

  float4 normal;
  float h = dt;

  h*= pow(gamma,2);

  normal.x = read_image(volume,volumeSampler,pos+(float4)(h,0,0,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(-h,0,0,0), isShortType);
  normal.y = read_image(volume,volumeSampler,pos+(float4)(0,h,0,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,-h,0,0), isShortType);
  normal.z = read_image(volume,volumeSampler,pos+(float4)(0,0,h,0), isShortType)-
  	read_image(volume,volumeSampler,pos+(float4)(0,0,-h,0), isShortType);

  normal.w = 0;

  //flip normal if we are comming from values greater than isoVal...
  normal = (1.f-2*isGreater)*normalize(normal);

  if ((x < Nx) && (y < Ny)){
	  d_normals[0+3*x+3*Nx*y] = normal.x;
	  d_normals[1+3*x+3*Nx*y] = normal.y;
	  d_normals[2+3*x+3*Nx*y] = normal.z;
	  d_alpha[x+Nx*y] = t;
  }

}

__kernel void blur_normals_x(__global float *d_input,
							 __global float *d_output,
							 int N)

{

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  uint Nx = get_global_size(0);
  uint Ny = get_global_size(1);

  float4 res = (float4)(0.f,0.f,0.f,0.f);
  float hsum = 0.f;

  float fac = -.1f/N/N;

  for (int i = -N; i <= N; ++i){
	float h = exp(fac*i*i);
	hsum += h;

	res.x += h*d_input[0+3*(x+i)+3*Nx*y];
	res.y += h*d_input[1+3*(x+i)+3*Nx*y];
	res.z += h*d_input[2+3*(x+i)+3*Nx*y];

  }

  // if (x==300 &&y ==300)
  // 	  printf("%.2f \n",hsum);

  res *= 1./hsum;

  //res = normalize(res);

  d_output[0+3*x+3*Nx*y] = res.x;
  d_output[1+3*x+3*Nx*y] = res.y;
  d_output[2+3*x+3*Nx*y] = res.z;

}

__kernel void blur_normals_y(__global float *d_input,
							 __global float *d_output,
							 int N)

{

  uint x = get_global_id(0);
  uint y = get_global_id(1);

  uint Nx = get_global_size(0);
  uint Ny = get_global_size(1);

  float4 res = (float4)(0.f,0.f,0.f,0.f);
  float hsum = 0.f;

  float fac = -.1f/N/N;

  for (int i = -N; i <= N; ++i){
	float h = exp(fac*i*i);
	hsum += h;

	res.x += h*d_input[0+3*x+3*Nx*(y+i)];
	res.y += h*d_input[1+3*x+3*Nx*(y+i)];
	res.z += h*d_input[2+3*x+3*Nx*(y+i)];

  }

  // if (x==300 &&y ==300)
  // 	  printf("%.2f \n",hsum);

  res *= 1./hsum;

  //res = normalize(res);

  d_output[0+3*x+3*Nx*y] = res.x;
  d_output[1+3*x+3*Nx*y] = res.y;
  d_output[2+3*x+3*Nx*y] = res.z;

}

__kernel void iso_shading(__global float *d_normals,
						  __global float *d_alpha,
						  __constant float *invM,
						  __constant float *invP,
						  __global float *d_output)
{
  const sampler_t volumeSampler =   CLK_NORMALIZED_COORDS_TRUE |
	CLK_ADDRESS_CLAMP_TO_EDGE |
	// CLK_FILTER_NEAREST ;
	CLK_FILTER_LINEAR ;

  uint x = get_global_id(0);
  uint y = get_global_id(1);
  uint Nx = get_global_size(0);
  uint Ny = get_global_size(1);

  float u = (x / (float) Nx)*2.0f-1.0f;
  float v = (y / (float) Ny)*2.0f-1.0f;

  // calculate eye ray in world space
  float4 orig0, orig;
  float4 direc0, direc;
  float4 temp;
  float4 back,front;

  front = (float4)(u,v,-1,1);
  back = (float4)(u,v,1,1);

  orig0 = mult(invP,front);
  orig0 *= 1.f/orig0.w;

  orig = mult(invM,orig0);
  orig *= 1.f/orig.w;

  temp = mult(invP,back);

  temp *= 1.f/temp.w;

  direc = mult(invM,normalize(temp-orig0));
  direc.w = 0.0f;

  float4 normal;
  normal.x = d_normals[0+3*x+3*Nx*y];
  normal.y = d_normals[1+3*x+3*Nx*y];
  normal.z = d_normals[2+3*x+3*Nx*y];
  normal.w = 0.f;

  normal = normalize(normal);

  float4 reflect;

  float colVal = 0;
  float alphaVal = 0;

  float4 light = (float4)(2,-1,-2,0);

  float c_ambient = .3;
  float c_diffuse = .4;
  float c_specular = .3;

  light = mult(invM,light);
  light = normalize(light);

  reflect = 2*dot(light,normal)*normal-light;

  float diffuse = fmax(0.f,-dot(light,normal));
  float specular = pow(fmax(0.f,-dot(normalize(reflect),normalize(direc))),10);

  colVal = c_ambient
	+ c_diffuse*diffuse
	+ (diffuse>0)*c_specular*specular;

  if ((x < Nx) && (y < Ny)){
	d_output[x+Nx*y] = (d_alpha[x+Nx*y]>0)?colVal:0.f;
  }

  // if (x==300 &&y ==300)
  // 	printf("diffuse: %.4f \n",dot(light,normal));

}


Cast between address spaces via an intermediate integer

/* OpenCL built-in library: atomic operations

   Copyright (c) 2012 Universidad Rey Juan Carlos

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

// Repeat the content of this file several times with different values
// for Q, T, and U:
#if !defined(Q)

#  define Q __global
#  include "atomics.cl"
#  undef Q

#  define Q __local
#  include "atomics.cl"
#  undef Q

#elif !defined(T)

#  define T int
#  define MIN __sync_fetch_and_min
#  define MAX __sync_fetch_and_max
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

#  define T uint
#  define MIN __sync_fetch_and_umin
#  define MAX __sync_fetch_and_umax
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

// NOTE: Here and below we convert between an address-space qualified
// pointer and a regular pointer. To avoid internal errors in LLVM, we
// need to transform this via an intermediate int, since LLVM refuses
// to cast between different address spaces.

// On CPUs, we use -ffake-address-space-map to artifically introduce
// address spaces. They do not exist in the hardware. Thus, the
// bitwise casting between different address spaces is correct.

// On other devices this may not be correct. To handle this case
// correctly, LLVM would need to provide atomic builtins for different
// address spaces. These do not exist yet, so bitwise casting is our
// best hope anyway.

// xchg is also supported for float as a special case
__attribute__((overloadable))
float atomic_xchg(volatile Q float *p, float val)
{
  // NOTE: We compare the float as int here...
  union { volatile Q float *p; intptr_t i; } u1;
  union { intptr_t i; volatile int *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return __atomic_exchange_n(u2.p, val, __ATOMIC_RELAXED);
}

#else

// basic

// read, add, store
__attribute__((overloadable))
T atomic_add(volatile Q T *p, T val)
{
  return __sync_fetch_and_add(p, val, __ATOMIC_RELAXED);
}

// read, subtract, store
__attribute__((overloadable))
T atomic_sub(volatile Q T *p, T val)
{
  return __sync_fetch_and_sub(p, val, __ATOMIC_RELAXED);
}

// read, swap, store
__attribute__((overloadable))
T atomic_xchg(volatile Q T *p, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return __atomic_exchange_n(u2.p, val, __ATOMIC_RELAXED);
}

// read, increment, store
__attribute__((overloadable))
T atomic_inc(volatile Q T *p)
{
  return atomic_add(p, (T)1);
}

// read, decrement, store
__attribute__((overloadable))
T atomic_dec(volatile Q T *p)
{
  return atomic_sub(p, (T)1);
}

// read, store
__attribute__((overloadable))
T atomic_cmpxchg(volatile Q T *p, T cmp, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  __atomic_compare_exchange_n(u2.p, &cmp, val, false,
                              __ATOMIC_RELAXED, __ATOMIC_RELAXED);
  return cmp;
}

// extended

__attribute__((overloadable))
T atomic_min(volatile Q T *p, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return MIN(u2.p, val);
}

__attribute__((overloadable))
T atomic_max(volatile Q T *p, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return MAX(u2.p, val);
}

__attribute__((overloadable))
T atomic_and(volatile Q T *p, T val)
{
  return __sync_fetch_and_and(p, val, __ATOMIC_RELAXED);
}

__attribute__((overloadable))
T atomic_or(volatile Q T *p, T val)
{
  return __sync_fetch_and_or(p, val, __ATOMIC_RELAXED);
}

__attribute__((overloadable))
T atomic_xor(volatile Q T *p, T val)
{
  return __sync_fetch_and_xor(p, val, __ATOMIC_RELAXED);
}

#endif

/* OpenCL built-in library: atomic operations

   Copyright (c) 2012 Universidad Rey Juan Carlos

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

// Repeat the content of this file several times with different values
// for Q, T, and U:
#if !defined(Q)

#  define Q __global
#  include "atomics.cl"
#  undef Q

#  define Q __local
#  include "atomics.cl"
#  undef Q

#elif !defined(T)

#  define T int
#  define MIN __sync_fetch_and_min
#  define MAX __sync_fetch_and_max
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

#  define T uint
#  define MIN __sync_fetch_and_umin
#  define MAX __sync_fetch_and_umax
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

// xchg is also supported for float as a special case
__attribute__((overloadable))
float atomic_xchg(volatile Q float *p, float val)
{
  // NOTE: We compare the float as int here...
  return __atomic_exchange_n((volatile int*)p, val, __ATOMIC_RELAXED);
}

#else

// basic

// read, add, store
__attribute__((overloadable))
T atomic_add(volatile Q T *p, T val)
{
  return __sync_fetch_and_add((volatile T*)p, val, __ATOMIC_RELAXED);
}

// read, subtract, store
__attribute__((overloadable))
T atomic_sub(volatile Q T *p, T val)
{
  return __sync_fetch_and_sub(p, val, __ATOMIC_RELAXED);
}

// read, swap, store
__attribute__((overloadable))
T atomic_xchg(volatile Q T *p, T val)
{
  return __atomic_exchange_n(p, val, __ATOMIC_RELAXED);
}

// read, increment, store
__attribute__((overloadable))
T atomic_inc(volatile Q T *p)
{
  return atomic_add(p, (T)1);
}

// read, decrement, store
__attribute__((overloadable))
T atomic_dec(volatile Q T *p)
{
  return atomic_sub(p, (T)1);
}

// read, store
__attribute__((overloadable))
T atomic_cmpxchg(volatile Q T *p, T cmp, T val)
{
  __atomic_compare_exchange_n(p, &cmp, val, false,
                              __ATOMIC_RELAXED, __ATOMIC_RELAXED);
  return cmp;
}

// extended

__attribute__((overloadable))
T atomic_min(volatile Q T *p, T val)
{
  return MIN((volatile T*)p, val);
}

__attribute__((overloadable))
T atomic_max(volatile Q T *p, T val)
{
  return MAX((volatile T*)p, val);
}

__attribute__((overloadable))
T atomic_and(volatile Q T *p, T val)
{
  return __sync_fetch_and_and(p, val, __ATOMIC_RELAXED);
}

__attribute__((overloadable))
T atomic_or(volatile Q T *p, T val)
{
  return __sync_fetch_and_or(p, val, __ATOMIC_RELAXED);
}

__attribute__((overloadable))
T atomic_xor(volatile Q T *p, T val)
{
  return __sync_fetch_and_xor(p, val, __ATOMIC_RELAXED);
}

#endif