; constants
.constf const0(0.0, 0.5, 1.0, 2.0)
.constf const1(0.00392156886, 3.05185094e-005, 0.00001, 0.00787401574)

.alias ZERO      const0.x
.alias HALF      const0.y
.alias ONE       const0.z
.alias TWO       const0.w
.alias INV_BYTE  const1.x
.alias INV_SHORT const1.y
.alias EPS       const1.z
.alias INV_127   const1.w

; uniforms
.fvec uViewProj[4]
.fvec uLightPos[4]
.fvec uLightColor[4]
.fvec uMaterial
.fvec uBasis[32*2]

.alias MAT_AMBIENT uMaterial.y
.alias MAT_ALPHA   uMaterial.w

; in
.alias aCoord    v0
.alias aNormal   v1
.alias aTexCoord v2
.alias aColor    v3
.alias aLight    v4

; variables
.alias lv0     r0
.alias lv1     r1
.alias lv2     r2
.alias lv3     r3
.alias normal  r4
.alias att     r5
.alias light   r6
.alias pos     r7
.alias tmp     r8
.alias diffuse r5

; out
.out vPosition position
.out vTexCoord texcoord0
.out vColor    color


; underwater block --------------------------------------------------
.constf const2(6.28318530718, 0.15915494309, 0.63661977236, 0.0)
.constf const3(1.0, 3.0, 0.0009765625, 0.75)
.constf const4(0.6, 0.9, 0.9, 1.0)

.alias TWO_PI      const2.x
.alias INV_TWO_PI  const2.y
.alias INV_HALF_PI const2.z
.alias ONE_THREE   const3.xy
.alias WAVE_SIZE   const3.z
.alias WAVE_LUM    const3.w
.alias UW_COLOR    const4

.fvec uParam
.alias TIME uParam.x

; tmp.x = abs(tmp.x)
.proc abs
    max tmp.x, tmp.x, -tmp.x
.end

; tmp.x = mod(tmp.x, TWO_PI)
.proc mod2pi
    mul tmp.y, INV_TWO_PI, tmp.x
    flr tmp.y, tmp.y
    mul tmp.y, TWO_PI, tmp.y
    add tmp.x, tmp.x, -tmp.y
.end

; tmp.x = sin(tmp.x)
.proc sin
    mul tmp.x, INV_HALF_PI, tmp.x
    add tmp.xy, -ONE_THREE, tmp.xx
    mad tmp.xy, tmp.xy, -tmp.xy, ONE_THREE.xx
    max tmp.xy, ZERO, tmp.xy
    add tmp.x, tmp.x, tmp.y
.end

.proc applyUnderwater
    ; k = dot(pos, 1/1024) + time
    dp3 tmp.x, WAVE_SIZE, pos
    add tmp.x, TIME, tmp.x
    
    call mod2pi
    call sin
    call abs

    mul tmp.x, WAVE_LUM, tmp.x
    add tmp.x, HALF, tmp.x
    mul tmp.xyz, UW_COLOR, tmp.xxx
    mul diffuse.xyz, diffuse.xyz, tmp.xyz    
    mul vColor, HALF, diffuse 
.end
; -------------------------------------------------------------------


.proc main
; joint = int(aCoord.w)
    mova a0.x, aCoord.w

; pos = mulQuatPos(uBasis[joint], aCoord)
    mul pos.xyz, uBasis[a0.x], aCoord.zxyw
    mad pos.xyz, aCoord, uBasis[a0.x].zxyw, -pos
    mad pos.xyz, aCoord.yzxw, uBasis[a0.x].w, pos
    mul tmp.xyz, uBasis[a0.x].zxyw, pos
    mad pos.xyz, pos.yzxw, uBasis[a0.x].yzxw, -tmp
    mad pos.xyz, pos, TWO, aCoord
    add pos.xyz, uBasis[a0.x + 1], pos
    mov pos.w, uBasis[a0.x + 1].w

; vPosition = uViewProj * pos
    mul tmp, uViewProj[0], pos.x
    mad tmp, pos.y, uViewProj[1], tmp
    mad tmp, pos.z, uViewProj[2], tmp
    mad vPosition, pos.w, uViewProj[3], tmp

; lighting
    ; lv[0..3] = (uLightPos[0..3].xyz - pos) * uLightColor[0..3].w;
    add lv0.xyz, uLightPos[0], -pos
    add lv1.xyz, uLightPos[1], -pos
    add lv2.xyz, uLightPos[2], -pos
    add lv3.xyz, uLightPos[3], -pos
    mul lv0.xyz, uLightColor[0].w, lv0
    mul lv1.xyz, uLightColor[1].w, lv1
    mul lv2.xyz, uLightColor[2].w, lv2
    mul lv3.xyz, uLightColor[3].w, lv3

    ; att[0..3] = dot(lv[0..3], lv[0..3])
    dp3 att.x, lv0, lv0
    dp3 att.y, lv1, lv1
    dp3 att.z, lv2, lv2
    dp3 att.w, lv3, lv3

    ; att = max(0, 1 - att) / sqrt(att)
    rsq tmp.x, att.x
    rsq tmp.y, att.y
    rsq tmp.z, att.z
    rsq tmp.w, att.w

    add att, ONE, -att
    max att, ZERO, att
    mul att, tmp,  att

    ; normal = mulQuat(uBasis[joint], aNormal/127 - 1)
    mul normal.xyz, INV_127, aNormal
    add normal.xyz, -ONE, normal
    mul pos.xyz, uBasis[a0.x], normal.zxyw
    mad pos.xyz, normal, uBasis[a0.x].zxyw, -pos
    mad pos.xyz, normal.yzxw, uBasis[a0.x].w, pos
    mul tmp.xyz, uBasis[a0.x].zxyw, pos
    mad pos.xyz, pos.yzxw, uBasis[a0.x].yzxw, -tmp
    mad normal.xyz, pos, TWO, normal

    ; light = max(0, dot(normal, lv[0..3]))
    dp3 light.x, lv0, normal
    dp3 light.y, lv1, normal
    dp3 light.z, lv2, normal
    dp3 light.w, lv3, normal

    ; light = max(0, light) * att
    max light, ZERO, light
    mul light, light, att

; vColor = aColor/255 * material.alpha * (material.ambient + light[0..3] * uLightColor[0..3])
    mul diffuse, INV_BYTE, aColor
    mul diffuse, MAT_ALPHA, diffuse
    mov tmp.xyz, MAT_AMBIENT
    mov tmp.w, ONE
    mad tmp.xyz, light.x, uLightColor[0], tmp
    mad tmp.xyz, light.y, uLightColor[1], tmp
    mad tmp.xyz, light.z, uLightColor[2], tmp
    mad tmp.xyz, light.w, uLightColor[3], tmp
    mul diffuse, diffuse, tmp

; vColor = applyUnderwater(diffuse, pos)
    call applyUnderwater

; vTecCoord = aTexCoord/32767
    mul vTexCoord, INV_SHORT, aTexCoord

    end
.end
