uint findMSB_(uint x)
{
	uint i;
	uint mask;
	uint res = -1;

	for (i = 0; i < 32; i++)
	{
		mask = 0x80000000 >> i;

		if ((x & mask) != 0)
		{
			res = 31 - i;
			break;
		}
	}

	return res;
}

uint parentKey(in uint key)
{
	return (key >> 1u);
}

void childrenKeys(in uint key, out uint children[2])
{
	children[0] = (key << 1u) | 0u;
	children[1] = (key << 1u) | 1u;
}

bool isRootKey(in uint key)
{
	return (key == 1u);
}

bool isLeafKey(in uint key)
{
	return findMSB_(key) == 31;
}

bool isChildZeroKey(in uint key)
{
	return ((key & 1u) == 0u);
}

// barycentric interpolation
vec3 berp(in vec3 v[3], in vec2 u)
{
	return v[0] + u.x * (v[1] - v[0]) + u.y * (v[2] - v[0]);
}

vec4 berp(in vec4 v[3], in vec2 u)
{
	return v[0] + u.x * (v[1] - v[0]) + u.y * (v[2] - v[0]);
}

// get xform from bit value
mat3 bitToXform(in uint bit)
{
	float b = float(bit);
	float c = 1.0f - b;

	vec3 c1 = vec3(0.0f, c   , b   );
	vec3 c2 = vec3(0.5f, b   , 0.0f);
	vec3 c3 = vec3(0.5f, 0.0f, c   );

	return mtxFromCols(c1, c2, c3);
}

// get xform from key
mat3 keyToXform(in uint key)
{
	vec3 c1 = vec3(1.0f, 0.0f, 0.0f);
	vec3 c2 = vec3(0.0f, 1.0f, 0.0f);
	vec3 c3 = vec3(0.0f, 0.0f, 1.0f);

	mat3 xf = mtxFromCols(c1, c2, c3);

	while (key > 1u) {
		xf = mul(xf, bitToXform(key & 1u));
		key = key >> 1u;
	}

	return xf;
}

// get xform from key as well as xform from parent key
mat3 keyToXform(in uint key, out mat3 xfp)
{
	xfp = keyToXform(parentKey(key));
	return keyToXform(key);
}

// subdivision routine (vertex position only)
void subd(in uint key, in vec4 v_in[3], out vec4 v_out[3])
{
	mat3 xf = keyToXform(key);

	mat4x3 m = mtxFromRows(v_in[0], v_in[1], v_in[2]);

	mat4x3 v = mul(xf, m);

	v_out[0] = mtxGetRow(v, 0);
	v_out[1] = mtxGetRow(v, 1);
	v_out[2] = mtxGetRow(v, 2);
}

// subdivision routine (vertex position only)
// also computes parent position
void subd(in uint key, in vec4 v_in[3], out vec4 v_out[3], out vec4 v_out_p[3])
{
	mat3 xfp; mat3 xf = keyToXform(key, xfp);

	mat4x3 m = mtxFromRows(v_in[0], v_in[1], v_in[2]);

	mat4x3 v = mul(xf, m);
	mat4x3 vp = mul(xfp, m);

	v_out[0] = mtxGetRow(v, 0);
	v_out[1] = mtxGetRow(v, 1);
	v_out[2] = mtxGetRow(v, 2);

	v_out_p[0] = mtxGetRow(vp, 0);
	v_out_p[1] = mtxGetRow(vp, 1);
	v_out_p[2] = mtxGetRow(vp, 2);
}
