
// simple and inaccurate tangent space generation that can be used from the vertex shader
void per_vertex_tangent_space(in mat3 mn, inout vec3 normal, out vec3 tangent, out vec3 binormal)
{
	vec3 a = cross(normal, vec3(0.0, 0.0, 1.0));
	vec3 b = cross(normal, vec3(0.0, 1.0, 0.0));
	if ( length(a) > length(b) ) tangent = mn * a;
	else tangent = mn * b;

	normal = mn * normal;
	binormal = cross(normal, tangent);
}

// don't use this unless you want to hurt performance
void per_fragment_tangent_space(in vec3 view_pos, in vec2 uv, out vec3 tangent, out vec3 binormal)
{
	vec3 dv1 = dFdx(view_pos);
	vec3 dv2 = dFdy(view_pos);
	vec3 dv3 = cross(dv1, dv2);
	
	vec2 duv1 = dFdx(uv);
	vec2 duv2 = dFdy(uv);
	
	mat3 mi = mat3(cross(dv2, dv3), cross(dv3,dv1), vec3(0.0));
	tangent = normalize(mi * vec3(duv1.x, duv2.x, 0.0));
	binormal = normalize(mi * vec3(duv1.y, duv2.y, 0.0));
}

/**
 * va = vertex[1] - vertex[0]
 * vb = vertex[2] - vertex[0]
 * ta = uv[1] - uv[0]
 * tb = uv[2] - uv[0]
 **/
void per_triangle_tangent_space(in vec3 va, in vec3 vb, in vec2 ta, in vec2 tb, out vec3 t, out vec3 b)
{
	float r = 1.0 / (ta.x*tb.y - tb.x*ta.y);

	t.x = tb.y*va.x - ta.y*vb.x * r;
	t.y = tb.y*va.y - ta.y*vb.y * r;
	t.z = tb.y*va.z - ta.y*vb.z * r;
	t = normalize(t);
		
	b.x = ta.x*vb.x - tb.x*va.x * r;
	b.y = ta.x*vb.y - tb.x*va.y * r;
	b.z = ta.x*vb.z - tb.x*va.z * r;
	b = normalize(b);
}
