// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.

CCEffect %{
  techniques:
  - name: opaque
    passes:
    - vert: standard-vs
      frag: standard-fs
      properties: &props
        tilingOffset:         { value: [1.0, 1.0, 0.0, 0.0] }
        mainColor:            { value: [1.0, 1.0, 1.0, 1.0], target: albedo, linear: true, editor: { displayName: Albedo, type: color } }
        albedoScale:          { value: [1.0, 1.0, 1.0], target: albedoScaleAndCutoff.xyz }
        alphaThreshold:       { value: 0.5, target: albedoScaleAndCutoff.w, editor: { parent: USE_ALPHA_TEST, slide: true, range: [0, 1.0], step: 0.001 } }
        occlusion:            { value: 0.0, target: pbrParams.x, editor: { slide: true, range: [0, 1.0], step: 0.001 } }
        roughness:            { value: 0.8, target: pbrParams.y, editor: { slide: true, range: [0, 1.0], step: 0.001 } }
        metallic:             { value: 0.6, target: pbrParams.z, editor: { slide: true, range: [0, 1.0], step: 0.001 } }
        specularIntensity:    { value: 0.5, target: pbrParams.w, editor: { slide: true, range: [0.0, 1.0], step: 0.001 } }
        emissive:             { value: [0.0, 0.0, 0.0, 1.0], linear: true, editor: { type: color } }
        emissiveScale:        { value: [1.0, 1.0, 1.0], target: emissiveScaleParam.xyz }
        normalStrength:       { value: 1.0, target: emissiveScaleParam.w, editor: { parent: USE_NORMAL_MAP, slide: true, range: [0, 5.0], step: 0.001 } }
        mainTexture:          { value: grey, target: albedoMap, editor: { displayName: AlbedoMap } }
        normalMap:            { value: normal }
        pbrMap:               { value: grey }
        metallicRoughnessMap: { value: grey }
        occlusionMap:         { value: white }
        emissiveMap:          { value: grey }
    - &forward-add
      vert: standard-vs
      frag: standard-fs
      phase: forward-add
      propertyIndex: 0
      embeddedMacros: { CC_FORWARD_ADD: true }
      depthStencilState:
        depthFunc: equal
        depthTest: true
        depthWrite: false
      blendState:
        targets:
        - blend: true
          blendSrc: one
          blendDst: one
          blendSrcAlpha: zero
          blendDstAlpha: one
    - &shadow-caster
      vert: shadow-caster-vs:vert
      frag: shadow-caster-fs:frag
      phase: shadow-caster
      propertyIndex: 0
      rasterizerState:
        cullMode: front
      properties:
        tilingOffset:   { value: [1.0, 1.0, 0.0, 0.0] }
        mainColor:      { value: [1.0, 1.0, 1.0, 1.0], target: albedo, editor: { displayName: Albedo, type: color } }
        albedoScale:    { value: [1.0, 1.0, 1.0], target: albedoScaleAndCutoff.xyz }
        alphaThreshold: { value: 0.5, target: albedoScaleAndCutoff.w, editor: { parent: USE_ALPHA_TEST } }
        mainTexture:    { value: grey, target: albedoMap, editor: { displayName: AlbedoMap } }
  - name: transparent
    passes:
    - vert: standard-vs
      frag: standard-fs
      embeddedMacros: { CC_FORCE_FORWARD_SHADING: true }
      depthStencilState:
        depthTest: true
        depthWrite: false
      blendState:
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one_minus_src_alpha
          blendDstAlpha: one_minus_src_alpha
      properties: *props
    - *forward-add
    - *shadow-caster
}%

CCProgram shared-ubos %{
  uniform Constants {
    vec4 tilingOffset;
    vec4 albedo;
    vec4 albedoScaleAndCutoff;
    vec4 pbrParams;
    vec4 emissive;
    vec4 emissiveScaleParam;
  };
}%

CCProgram standard-vs %{
  precision highp float;
  #include <legacy/input-standard>
  #include <builtin/uniforms/cc-global>
  #include <legacy/decode-base>
  #include <legacy/local-batch>
  #include <shared-ubos>
  #include <legacy/fog-vs>
  #include <legacy/shadow-map-vs>

  #if USE_VERTEX_COLOR
    in vec4 a_color;
    out lowp vec4 v_color;
  #endif

  #if USE_INSTANCING // when instancing is enabled
    in vec4 a_tilingOffset;
  #endif

  out vec3 v_position;
  out mediump vec3 v_normal;
  out vec2 v_uv;
  #if HAS_SECOND_UV
    out mediump vec2 v_uv1;
  #endif

  #if CC_RECEIVE_SHADOW
    out mediump vec2 v_shadowBias;
  #endif

  #if USE_NORMAL_MAP
    out mediump vec4 v_tangent;
  #endif

  #if HAS_SECOND_UV || CC_USE_LIGHTMAP
    in vec2 a_texCoord1;
  #endif

  #if CC_USE_LIGHTMAP && !CC_FORWARD_ADD
    #include <legacy/lightingmap-vs>
  #endif

  void main () {
    StandardVertInput In;
    CCVertInput(In);

    mat4 matWorld, matWorldIT;
    CCGetWorldMatrixFull(matWorld, matWorldIT);

    vec4 pos = matWorld * In.position;

    v_position = pos.xyz;
    v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);

    #if CC_RECEIVE_SHADOW
      v_shadowBias = CCGetShadowBias();
    #endif

    #if USE_TWOSIDE
      vec3 viewDirect = normalize(cc_cameraPos.xyz - v_position);
      v_normal *= dot(v_normal, viewDirect) < 0.0 ? -1.0 : 1.0;
    #endif

    #if USE_NORMAL_MAP
      v_tangent.xyz = normalize((matWorld * vec4(In.tangent.xyz, 0.0)).xyz);
      v_tangent.w = In.tangent.w;
    #endif

    vec4 vTilingOffset = tilingOffset;
    #if USE_INSTANCING // when instancing is enabled
      vTilingOffset = a_tilingOffset;
    #endif

    v_uv = a_texCoord * vTilingOffset.xy + vTilingOffset.zw;
    #if SAMPLE_FROM_RT
      CC_HANDLE_RT_SAMPLE_FLIP(v_uv);
    #endif
    #if HAS_SECOND_UV
      v_uv1 = a_texCoord1 * vTilingOffset.xy + vTilingOffset.zw;
      #if SAMPLE_FROM_RT
        CC_HANDLE_RT_SAMPLE_FLIP(v_uv1);
      #endif
    #endif

    #if USE_VERTEX_COLOR
      v_color = a_color;
    #endif

    CC_TRANSFER_FOG(pos);
    CC_TRANSFER_SHADOW(pos);

    #if CC_USE_LIGHTMAP && !CC_FORWARD_ADD
      CCLightingMapCaclUV();
    #endif

    gl_Position = cc_matProj * (cc_matView * matWorld) * In.position;
  }
}%

CCProgram standard-fs %{
  precision highp float;
  #include <builtin/uniforms/cc-global>
  #include <shared-ubos>
  #include <legacy/fog-fs>
  #include <legacy/standard-surface-entry>
  #if CC_USE_LIGHTMAP && !CC_FORWARD_ADD
    #include <legacy/lightingmap-fs>
  #endif

  in vec3 v_position;
  in vec2 v_uv;
  #if HAS_SECOND_UV
    in mediump vec2 v_uv1;
  #endif
  in mediump vec3 v_normal;

  #if CC_RECEIVE_SHADOW
    in mediump vec2 v_shadowBias;
  #endif

  #if USE_VERTEX_COLOR
    in lowp vec4 v_color;
  #endif

  #if USE_ALBEDO_MAP
    uniform sampler2D albedoMap;
    #pragma define-meta ALBEDO_UV options([v_uv, v_uv1])
  #endif
  #if USE_NORMAL_MAP
    in mediump vec4 v_tangent;
    uniform sampler2D normalMap;
    #pragma define-meta NORMAL_UV options([v_uv, v_uv1])
  #endif
  #pragma define-meta PBR_UV options([v_uv, v_uv1])
  #if USE_PBR_MAP
    uniform sampler2D pbrMap;
  #endif
  #if USE_METALLIC_ROUGHNESS_MAP
    uniform sampler2D metallicRoughnessMap;
  #endif
  #if USE_OCCLUSION_MAP
    uniform sampler2D occlusionMap;
  #endif
  #if USE_EMISSIVE_MAP
    uniform sampler2D emissiveMap;
    #pragma define-meta EMISSIVE_UV options([v_uv, v_uv1])
  #endif

  #pragma define OCCLUSION_CHANNEL          r
  #pragma define ROUGHNESS_CHANNEL          g
  #pragma define METALLIC_CHANNEL           b
  #pragma define SPECULAR_INTENSITY_CHANNEL a

  #if USE_ALPHA_TEST
    #pragma define-meta ALPHA_TEST_CHANNEL options([a, r])
  #endif

  void surf (out StandardSurface s) {
    vec4 baseColor = albedo;
    #if USE_VERTEX_COLOR
      baseColor.rgb *= SRGBToLinear(v_color.rgb); // use linear
      baseColor.a *= v_color.a;
    #endif
    #if USE_ALBEDO_MAP
      vec4 texColor = texture(albedoMap, ALBEDO_UV);
      texColor.rgb = SRGBToLinear(texColor.rgb);
      baseColor *= texColor;
    #endif
    s.albedo = baseColor;
    s.albedo.rgb *= albedoScaleAndCutoff.xyz;

    #if USE_ALPHA_TEST
      if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;
    #endif

    #if CC_USE_LIGHTMAP && !CC_FORWARD_ADD
      vec4 lightColor = texture(cc_lightingMap, v_luv.xy);
      s.lightmap.a = lightColor.a;
      s.lightmap.rgb = lightColor.xyz * v_luv.z;
      s.lightmap_test = v_luv.z; /*lum*/
    #endif

    s.normal = v_normal;

    #if CC_RECEIVE_SHADOW
      s.shadowBias = v_shadowBias;
    #endif

    #if USE_NORMAL_MAP
      vec3 nmmp = texture(normalMap, NORMAL_UV).xyz - vec3(0.5);
      vec3 bitangent = cross(v_normal, v_tangent.xyz) * (v_tangent.w > 0.0 ? 1.0 : -1.0); // note the cross order
      s.normal =
        (nmmp.x * emissiveScaleParam.w) * normalize(v_tangent.xyz) +
        (nmmp.y * emissiveScaleParam.w) * normalize(bitangent) +
        nmmp.z * normalize(s.normal);
    #endif

    HIGHP_VALUE_TO_STRUCT_DEFINED(v_position, s.position);

    vec4 pbr = pbrParams;
    pbr.x = 1.0;
    #if USE_PBR_MAP
      vec4 res = texture(pbrMap, PBR_UV);
      pbr.x *= res.OCCLUSION_CHANNEL;
      pbr.y *= res.ROUGHNESS_CHANNEL;
      pbr.z *= res.METALLIC_CHANNEL;
      pbr.w *= res.SPECULAR_INTENSITY_CHANNEL;
    #endif
    #if USE_METALLIC_ROUGHNESS_MAP
      vec4 metallicRoughness = texture(metallicRoughnessMap, PBR_UV);
      pbr.z *= metallicRoughness.METALLIC_CHANNEL;
      pbr.y *= metallicRoughness.ROUGHNESS_CHANNEL;
    #endif
    #if USE_OCCLUSION_MAP
      pbr.x = mix(1.0, texture(occlusionMap, PBR_UV).OCCLUSION_CHANNEL, pbrParams.x);
    #endif
    s.occlusion = pbr.x;
    s.roughness = pbr.y;
    s.metallic = pbr.z;
    s.specularIntensity = pbr.w;

    s.emissive = emissive.rgb;
    #if USE_EMISSIVE_MAP
      s.emissive = SRGBToLinear(texture(emissiveMap, EMISSIVE_UV).rgb);
    #endif
    s.emissive *= emissiveScaleParam.xyz;
  }

  CC_STANDARD_SURFACE_ENTRY()
}%

CCProgram shadow-caster-vs %{
  precision highp float;
  #include <legacy/input-standard>
  #include <legacy/decode-base>
  #include <legacy/local-batch>
  #include <shared-ubos>
  #include <builtin/uniforms/cc-shadow>

  #if HAS_SECOND_UV || CC_USE_LIGHTMAP
    in vec2 a_texCoord1;
  #endif

  #if USE_INSTANCING // when instancing is enabled
    in vec4 a_tilingOffset;
  #endif

  out vec2 v_uv;
  #if HAS_SECOND_UV
    out vec2 v_uv1;
  #endif
  out vec4 v_worldPos;
  out highp vec2 v_clip_depth;

  vec4 vert () {
    StandardVertInput In;
    CCVertInput(In);

    mat4 matWorld, matWorldIT;
    CCGetWorldMatrixFull(matWorld, matWorldIT);

    v_worldPos = matWorld * In.position;
    vec4 clipPos = cc_matLightViewProj * v_worldPos;

    vec4 vTilingOffset = tilingOffset;
    #if USE_INSTANCING // when instancing is enabled
      vTilingOffset = a_tilingOffset;
    #endif

    v_uv = a_texCoord * vTilingOffset.xy + vTilingOffset.zw;
    #if HAS_SECOND_UV
      v_uv1 = a_texCoord1 * vTilingOffset.xy + vTilingOffset.zw;
    #endif

    v_clip_depth = clipPos.zw;

    return clipPos;
  }
}%

CCProgram shadow-caster-fs %{
  precision highp float;
  #include <shared-ubos>
  #include <common/data/packing>
  #include <legacy/shadow-map-base>

  in vec2 v_uv;
  #if HAS_SECOND_UV
    in vec2 v_uv1;
  #endif
  in vec4 v_worldPos;
  in highp vec2 v_clip_depth;

  #if USE_ALBEDO_MAP
    uniform sampler2D albedoMap;
    #pragma define-meta ALBEDO_UV options([v_uv, v_uv1])
  #endif

  #if USE_ALPHA_TEST
    #pragma define-meta ALPHA_TEST_CHANNEL options([a, r])
  #endif

  vec4 frag () {
    vec4 baseColor = albedo;

    #if USE_ALPHA_TEST
      #if USE_ALBEDO_MAP
        baseColor *= texture(albedoMap, ALBEDO_UV);
      #endif
      if (baseColor.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;
    #endif

    highp float clipDepth = v_clip_depth.x / v_clip_depth.y * 0.5 + 0.5;
    // spot use linear
    if(cc_shadowLPNNInfo.x > 0.000001 && cc_shadowLPNNInfo.x < 1.999999) {
      // enabled linear depth
      #if CC_SHADOWMAP_USE_LINEAR_DEPTH
        clipDepth = CCGetLinearDepth(v_worldPos.xyz);
      #endif
    }

    #if CC_SHADOWMAP_FORMAT == SHADOWMAP_FORMAT_RGBA8
      return packDepthToRGBA(clipDepth);
    #else
      return vec4(clipDepth, 1.0, 1.0, 1.0);
    #endif
  }
}%