

#define SOFT_CUBE_LOD 1
float4 texCUBElod_soft(samplerCUBE envMap, float4 v)
{
    // float4 return - a texture lookup pixel
    // envMap - the cubemap to use
    // v - 3 coordinate direction, +1 point mipmap level.
	// ok better explain what this function does
	// basically, expand a spherical vector onto
	// the unit CUBE, where the textures are
	// anything where 2 or 3 coordinates are near 1
	// is consequently the edge.
	// use the 4th element in v to determine the width
	// of the blur to apply - too narrow would look funny
	// at higher mipmaps.
	// 0.002 is a constant that should be adjusted appropriate
	// to the envmap's texture size. 1/512 is probably
	// about right.
	float mipmap = v.w;
	float borderSize = min(0.002*pow(2.0f,mipmap),0.48);
	float b1 = 1.0f-borderSize;
	float3 d = normalize(v.xyz);
	// absolute value for max/min proportionally
	float3 a = abs(d);
	float3 s = sign(d);
	float dmax = max(max(a.x,a.y),a.z);
	float dmin = min(min(a.x,a.y),a.z);
	// these contain the indices, like direction[vmax]
	int vmax = 1*(dmax==a.y) + 2*(dmax==a.z && dmax!=a.y);
	int vmin = 1*(dmin==a.y) + 2*(dmin==a.z && dmin!=a.y);
	// thanks to math, this gets the third one.
	// (0,1) -> 2, (0,2) -> 1, (1,2) -> 0
	int vmid = 3-vmax-vmin;
	// now begins the fun math
	// oh yeah, don't pass 0,0,0 direction vectors in.  that would be bad.
	float3 dcube = d/a[vmax];
	float3 acube = abs(dcube);
	if (acube[vmid] > b1) {
		if (acube[vmin] > b1) {
			// it's on a corner.
			// this means mixing 3 sides together, so 2 proportions.  other than that, similar.
			float3 i1 = float3(0.0,0.0,0.0);
			// it's harder to think about this stuff :\
			// start by establishing the actual corner of the cube in question
			i1[vmax] = s[vmax];
			i1[vmid] = s[vmid];
			i1[vmin] = s[vmin];
			float3 i2 = i1;
			float3 i3 = i1;
			// ok, now reduce down the other 2 coordinates
			i1[vmid] *= b1;
			i1[vmin] *= b1;
			i2[vmax] *= b1;
			i2[vmin] *= b1;
			i3[vmax] *= b1;
			i3[vmid] *= b1;
			// establish proportions on two axes!
			float p2 = (acube[vmid]-b1)/borderSize;
			float p3 = (acube[vmin]-b1)/borderSize;
			// break up the env so it's easier to read
			float4 env = texCUBElod(envMap,float4(i1,mipmap));
			env += p2*texCUBElod(envMap,float4(i2,mipmap));
			env += p3*texCUBElod(envMap,float4(i3,mipmap));
			env /= (1.0f+p2+p3);
			// debug
			//return(env+float4(0.0f,10.0f,0.0f,0.0f));
			return(env);
		}
		else {
			// it's on two edges
			// construct a 2 direction interpolation.
			float3 i1 = float3(0.0,0.0,0.0);
			// start with the coordinates right at the edge
			i1[vmin] = dcube[vmin];
			i1[vmax] = s[vmax];
			i1[vmid] = s[vmid];
			// on the other one too
			float3 i2 = i1;
			// now spread them away from the edge in different directions
			i1[vmid] *= b1;
			i2[vmax] *= b1;
			// figure out the proportion of vmid to mix in - 1.0 if it's at the edge
			// 0.0 if it's at b1.
			float proportion = (acube[vmid]-b1)/borderSize;
			float4 env = texCUBElod(envMap, float4(i1,mipmap));
			env += proportion*texCUBElod(envMap, float4(i2,mipmap));
			env /= (1.0f+proportion);
			// add a red tint to make sure all edges are actually getting hit
			//return(env+float4(10.0f,0.0f,0.0f,0.0f));
			return(env);
		}
	} else {
		// if it makes it here without returning a blended one,
		return float4(texCUBElod(envMap,v));
	}
}