Merge "Fix sun effect is too bright and parallax translation is not accurate" into main
diff --git a/weathereffects/graphics/assets/shaders/sun_effect.agsl b/weathereffects/graphics/assets/shaders/sun_effect.agsl
index 601b3d3..3886eb3 100644
--- a/weathereffects/graphics/assets/shaders/sun_effect.agsl
+++ b/weathereffects/graphics/assets/shaders/sun_effect.agsl
@@ -30,8 +30,8 @@
 
 #include "shaders/lens_flare.agsl"
 
-const vec2 sunCenter = vec2(0.57, -0.8);
 const vec3 godRaysColor = vec3(1., 0.857, 0.71428);
+const vec2 sunCenter = vec2(0.67, -1.0);
 
 float calculateRay(float angle, float time) {
     /*
@@ -94,16 +94,25 @@
 }
 
 vec4 main(float2 fragCoord) {
+    float2 aspectRatioAdj = vec2(1.);
+    if (screenAspectRatio > 1) {
+        aspectRatioAdj.x = screenAspectRatio;
+    } else {
+        aspectRatioAdj.y = 1. / screenAspectRatio;
+    }
     // Apply transform matrix to fragCoord
     float2 adjustedUv = transformPoint(transformMatrixBitmap, fragCoord);
 
     float2 uv = transformPoint(transformMatrixWeather, fragCoord) / screenSize;
     uv -= vec2(0.5, 0.5);
-    uv.y /= screenAspectRatio;
-    vec2 sunVariation = vec2(0.1 * sin(time * 0.3), 0.14 * cos(time * 0.5));
-    sunVariation += 0.1 * (0.5 * sin(time * 0.456) + 0.5) * sunCenter / vec2(1., screenAspectRatio);
-    vec2 sunPos = sunVariation + sunCenter / vec2(1., screenAspectRatio);
-    //TODO(b/375214506): fix the uv position of the sun
+    uv *= aspectRatioAdj;
+    // Random sun variation based on sin/cos signal.
+    vec2 sunVariation = 0.08 * vec2(sin(time * 0.3), cos(time * 0.5));
+    // Variation that moves sun on the same direction than the vector that goes from (0,0)
+    // to sunCenter, but scaling distance.
+    sunVariation += 0.1 * (0.5 * sin(time * 0.456) + 0.5) * sunCenter;
+    vec2 sunPos = sunVariation + sunCenter;
+    sunPos *= aspectRatioAdj;
 
     vec4 colorForeground = foreground.eval(adjustedUv);
     vec4 color = background.eval(adjustedUv);
diff --git a/weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/WeatherEffectBase.kt b/weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/WeatherEffectBase.kt
index e2739b2..405d1df 100644
--- a/weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/WeatherEffectBase.kt
+++ b/weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/WeatherEffectBase.kt
@@ -24,9 +24,9 @@
 import android.graphics.Shader
 import android.util.SizeF
 import com.google.android.wallpaper.weathereffects.graphics.utils.GraphicsUtils
-import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.calculateTransformDifference
+import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.calculateTranslationDifference
 import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.centerCropMatrix
-import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.getScale
+import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.getScaleFromMatrixValues
 import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.invertAndTransposeMatrix
 import kotlin.random.Random
 
@@ -42,13 +42,22 @@
             surfaceSize,
             SizeF(background.width.toFloat(), background.height.toFloat()),
         )
+        set(value) {
+            field = value
+            value.getValues(centerCropMatrixValues)
+        }
+
     protected var parallaxMatrix = Matrix(centerCropMatrix)
+    private val centerCropMatrixValues: FloatArray =
+        FloatArray(9).apply { centerCropMatrix.getValues(this) }
+    private val parallaxMatrixValues: FloatArray =
+        FloatArray(9).apply { parallaxMatrix.getValues(this) }
     // Currently, we use same transform for both foreground and background
     protected open val transformMatrixBitmap: FloatArray = FloatArray(9)
     // Apply to weather components not rely on image textures
     // Should be identity matrix in editor, and only change when parallax applied in homescreen
     private val transformMatrixWeather: FloatArray = FloatArray(9)
-    protected var bitmapScale = getScale(centerCropMatrix)
+    protected var bitmapScale = getScaleFromMatrixValues(centerCropMatrixValues)
     protected var elapsedTime: Float = 0f
 
     abstract val shader: RuntimeShader
@@ -57,14 +66,19 @@
     abstract val colorGradingIntensity: Float
 
     override fun setMatrix(matrix: Matrix) {
-        this.parallaxMatrix.set(matrix)
-        bitmapScale = getScale(parallaxMatrix)
+        this.parallaxMatrix.setAndUpdateFloatArray(matrix, parallaxMatrixValues)
+        bitmapScale = getScaleFromMatrixValues(parallaxMatrixValues)
         adjustCropping(surfaceSize)
     }
 
+    /** This function will be called every time parallax changes, don't do heavy things here */
     open fun adjustCropping(newSurfaceSize: SizeF) {
         invertAndTransposeMatrix(parallaxMatrix, transformMatrixBitmap)
-        calculateTransformDifference(centerCropMatrix, parallaxMatrix, transformMatrixWeather)
+        calculateTranslationDifference(
+            centerCropMatrixValues,
+            parallaxMatrixValues,
+            transformMatrixWeather,
+        )
         shader.setFloatUniform("transformMatrixBitmap", transformMatrixBitmap)
         shader.setFloatUniform("transformMatrixWeather", transformMatrixWeather)
         shader.setFloatUniform("screenSize", newSurfaceSize.width, newSurfaceSize.height)
@@ -75,6 +89,11 @@
 
     override fun resize(newSurfaceSize: SizeF) {
         surfaceSize = newSurfaceSize
+        centerCropMatrix =
+            centerCropMatrix(
+                surfaceSize,
+                SizeF(background.width.toFloat(), background.height.toFloat()),
+            )
         adjustCropping(newSurfaceSize)
         updateGridSize(newSurfaceSize)
     }
@@ -113,8 +132,8 @@
                 surfaceSize,
                 SizeF(background.width.toFloat(), background.height.toFloat()),
             )
-        parallaxMatrix.set(centerCropMatrix)
-        bitmapScale = getScale(centerCropMatrix)
+        parallaxMatrix.setAndUpdateFloatArray(centerCropMatrix, parallaxMatrixValues)
+        bitmapScale = getScaleFromMatrixValues(centerCropMatrixValues)
         shader.setInputBuffer(
             "background",
             BitmapShader(this.background, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR),
@@ -139,6 +158,11 @@
         )
     }
 
+    private fun Matrix.setAndUpdateFloatArray(src: Matrix, targetFloatArray: FloatArray) {
+        set(src)
+        src.getValues(targetFloatArray)
+    }
+
     companion object {
         // When extracting the scale from the parallax matrix, there will be a very small difference
         // due to floating-point precision.
diff --git a/weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/utils/MatrixUtils.kt b/weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/utils/MatrixUtils.kt
index 7d2afa6..4aa053a 100644
--- a/weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/utils/MatrixUtils.kt
+++ b/weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/utils/MatrixUtils.kt
@@ -55,6 +55,10 @@
         return matrixValues[0]
     }
 
+    fun getScaleFromMatrixValues(matrixValuesArray: FloatArray): Float {
+        return matrixValuesArray[0]
+    }
+
     /**
      * Calculates the transformation matrix that, when applied to `originMatrix`, results in
      * `targetMatrix`. Current use case: Calculating parallax effect for the homescreen compared
@@ -77,6 +81,53 @@
         return transposeMatrixArray(matrixValues, outArray)
     }
 
+    /**
+     * Calculates the difference in translation between two transformation matrices, represented as
+     * FloatArrays (`centerCropMatrixValues` and `parallaxMatrixValues`), after scaling
+     * `parallaxMatrixValues` to match the scale of `centerCropMatrixValues`. The resulting
+     * translation difference is then stored in the provided `outArray` as a 3x3 translation matrix
+     * (in column-major order).
+     *
+     * @param centerCropMatrixValues A FloatArray of length 9 representing the reference
+     *   transformation matrix (center-cropped view) in row-major order.
+     * @param parallaxMatrixValues A FloatArray of length 9 representing the transformation matrix
+     *   whose translation difference relative to `centerCropMatrixValues` is to be calculated, also
+     *   in row-major order. This array will be scaled to match the scale of
+     *   `centerCropMatrixValues`.
+     * @param outArray A FloatArray of length 9 to store the resulting 3x3 translation matrix. The
+     *   translation components (deltaX, deltaY) will be placed in the appropriate positions for a
+     *   column-major matrix.
+     */
+    fun calculateTranslationDifference(
+        centerCropMatrixValues: FloatArray,
+        parallaxMatrixValues: FloatArray,
+        outArray: FloatArray,
+    ): FloatArray {
+        val scaleX = centerCropMatrixValues[0] / parallaxMatrixValues[0]
+        val scaleY = centerCropMatrixValues[4] / parallaxMatrixValues[4]
+
+        val scaledParallaxTransX = parallaxMatrixValues[2] * scaleX
+        val scaledParallaxTransY = parallaxMatrixValues[5] * scaleY
+
+        val originTransX = centerCropMatrixValues[2]
+        val originTransY = centerCropMatrixValues[5]
+
+        val deltaTransX = originTransX - scaledParallaxTransX
+        val deltaTransY = originTransY - scaledParallaxTransY
+
+        outArray[0] = 1f
+        outArray[1] = 0f
+        outArray[2] = 0f
+        outArray[3] = 0f
+        outArray[4] = 1f
+        outArray[5] = 0f
+        outArray[6] = deltaTransX
+        outArray[7] = deltaTransY
+        outArray[8] = 1f
+
+        return outArray
+    }
+
     // Transpose 3x3 matrix values as a FloatArray[9], write results to outArray
     private fun transposeMatrixArray(inMatrixArray: FloatArray, outArray: FloatArray): FloatArray {
         for (i in 0 until 3) {