uniform mat4 glstate_matrix_mvp;

attribute vec4 attrVertex;
attribute vec3 attrNormal;
attribute vec4 attrTangent;

mat3 xll_transpose(mat3 m) {
  return mat3( m[0][0], m[1][0], m[2][0],
               m[0][1], m[1][1], m[2][1],
               m[0][2], m[1][2], m[2][2]);
}

mat3 xll_constructMat3(mat4 m) {
  return mat3(vec3(m[0]), vec3(m[1]), vec3(m[2]));
}

struct v2f_surf {
    highp vec4 pos;
    lowp vec3 lightDir;
    lowp vec3 viewDir;
    lowp vec3 worldN;
};

struct appdata {
    highp vec4 vertex;
    highp vec4 tangent;
    highp vec3 normal;
};

uniform highp mat4 _Object2World;
uniform highp mat4 _World2Object;
uniform highp vec3 _WorldSpaceCameraPos;
uniform lowp vec4 _WorldSpaceLightPos0;

uniform highp vec4 unity_Scale;

highp vec3 ObjSpaceViewDir( in highp vec4 v ) {
    highp vec3 objSpaceCameraPos = (_World2Object * vec4(_WorldSpaceCameraPos.xyz, 1.0)).xyz  * unity_Scale.w;
    return objSpaceCameraPos - v.xyz;
}

highp vec3 ObjSpaceLightDir( in highp vec4 v ) {
    highp vec3 objSpaceLightPos = (_World2Object * _WorldSpaceLightPos0).xyz;
    return objSpaceLightPos.xyz;
}

v2f_surf vert_surf (in appdata v) {
    v2f_surf o;
    o.pos = glstate_matrix_mvp * v.vertex;

    highp vec3 worldN = xll_constructMat3(_Object2World) * v.normal;
    o.worldN = worldN;

    highp vec3 binormal = cross(v.normal, v.tangent.xyz) * v.tangent.w;
    highp mat3 rotation = xll_transpose (mat3(v.tangent.xyz, binormal, v.normal));

    highp vec3 lightDir = rotation * ObjSpaceLightDir(v.vertex);
    o.lightDir = lightDir;

    highp vec3 viewDirForLight = rotation * ObjSpaceViewDir(v.vertex);
    o.viewDir = normalize( (lightDir + normalize( viewDirForLight )) );
    return o;
}

varying lowp vec3 varWorldN;
varying lowp vec3 varLightDir;
varying lowp vec3 varViewDir;

void main() {
    appdata v;
    v.vertex = attrVertex;
    v.tangent = attrTangent;
    v.normal = attrNormal;

    v2f_surf rv = vert_surf(v);

    gl_Position = rv.pos;
    varWorldN = rv.worldN;
    varLightDir = rv.lightDir;
    varViewDir = rv.viewDir;
}
