NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/BlobDrawable.java

199 lines
6.3 KiB
Java

package org.telegram.ui.Components;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import org.telegram.messenger.AndroidUtilities;
import java.util.Random;
public class BlobDrawable {
public static float MAX_SPEED = 8.2f;
public static float MIN_SPEED = 0.8f;
public static float AMPLITUDE_SPEED = 0.33f;
public static float SCALE_BIG = 0.807f;
public static float SCALE_SMALL = 0.704f;
public static float SCALE_BIG_MIN = 0.878f;
public static float SCALE_SMALL_MIN = 0.926f;
public static float FORM_BIG_MAX = 0.6f;
public static float FORM_SMALL_MAX = 0.6f;
public static float GLOBAL_SCALE = 1f;
public static float FORM_BUTTON_MAX = 0f;
public static float GRADIENT_SPEED_MIN = 0.5f;
public static float GRADIENT_SPEED_MAX = 0.01f;
public static float LIGHT_GRADIENT_SIZE = 0.5f;
public float minRadius;
public float maxRadius;
private Path path = new Path();
public Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float[] radius;
private float[] angle;
private float[] radiusNext;
private float[] angleNext;
private float[] progress;
private float[] speed;
private float[] pointStart = new float[4];
private float[] pointEnd = new float[4];
final Random random = new Random();
private final float N;
private final float L;
public float cubicBezierK = 1f;
private final Matrix m = new Matrix();
public BlobDrawable(int n) {
N = n;
L = (float) ((4.0 / 3.0) * Math.tan(Math.PI / (2 * N)));
radius = new float[n];
angle = new float[n];
radiusNext = new float[n];
angleNext = new float[n];
progress = new float[n];
speed = new float[n];
for (int i = 0; i < N; i++) {
generateBlob(radius, angle, i);
generateBlob(radiusNext, angleNext, i);
progress[i] = 0;
}
}
private void generateBlob(float[] radius, float[] angle, int i) {
float angleDif = 360f / N * 0.05f;
float radDif = maxRadius - minRadius;
radius[i] = minRadius + Math.abs(((random.nextInt() % 100f) / 100f)) * radDif;
angle[i] = 360f / N * i + ((random.nextInt() % 100f) / 100f) * angleDif;
speed[i] = (float) (0.017 + 0.003 * (Math.abs(random.nextInt() % 100f) / 100f));
}
public void update(float amplitude, float speedScale) {
for (int i = 0; i < N; i++) {
progress[i] += (speed[i] * MIN_SPEED) + amplitude * speed[i] * MAX_SPEED * speedScale;
if (progress[i] >= 1f) {
progress[i] = 0;
radius[i] = radiusNext[i];
angle[i] = angleNext[i];
generateBlob(radiusNext, angleNext, i);
}
}
}
public void draw(float cX, float cY, Canvas canvas, Paint paint) {
path.reset();
for (int i = 0; i < N; i++) {
float progress = this.progress[i];
int nextIndex = i + 1 < N ? i + 1 : 0;
float progressNext = this.progress[nextIndex];
float r1 = radius[i] * (1f - progress) + radiusNext[i] * progress;
float r2 = radius[nextIndex] * (1f - progressNext) + radiusNext[nextIndex] * progressNext;
float angle1 = angle[i] * (1f - progress) + angleNext[i] * progress;
float angle2 = angle[nextIndex] * (1f - progressNext) + angleNext[nextIndex] * progressNext;
float l = L * (Math.min(r1, r2) + (Math.max(r1, r2) - Math.min(r1, r2)) / 2f) * cubicBezierK;
m.reset();
m.setRotate(angle1, cX, cY);
pointStart[0] = cX;
pointStart[1] = cY - r1;
pointStart[2] = cX + l;
pointStart[3] = cY - r1;
m.mapPoints(pointStart);
pointEnd[0] = cX;
pointEnd[1] = cY - r2;
pointEnd[2] = cX - l;
pointEnd[3] = cY - r2;
m.reset();
m.setRotate(angle2, cX, cY);
m.mapPoints(pointEnd);
if (i == 0) {
path.moveTo(pointStart[0], pointStart[1]);
}
path.cubicTo(
pointStart[2], pointStart[3],
pointEnd[2], pointEnd[3],
pointEnd[0], pointEnd[1]
);
}
canvas.save();
canvas.drawPath(path, paint);
canvas.restore();
}
public void generateBlob() {
for (int i = 0; i < N; i++) {
generateBlob(radius, angle, i);
generateBlob(radiusNext, angleNext, i);
progress[i] = 0;
}
}
private float animateToAmplitude;
public float amplitude;
private float animateAmplitudeDiff;
private final static float ANIMATION_SPEED_WAVE_HUGE = 0.65f;
private final static float ANIMATION_SPEED_WAVE_SMALL = 0.45f;
private final static float animationSpeed = 1f - ANIMATION_SPEED_WAVE_HUGE;
private final static float animationSpeedTiny = 1f - ANIMATION_SPEED_WAVE_SMALL;
public void setValue(float value, boolean isBig) {
animateToAmplitude = value;
if (isBig) {
if (animateToAmplitude > amplitude) {
animateAmplitudeDiff = (animateToAmplitude - amplitude) / (100f + 300f * animationSpeed);
} else {
animateAmplitudeDiff = (animateToAmplitude - amplitude) / (100 + 500f * animationSpeed);
}
} else {
if (animateToAmplitude > amplitude) {
animateAmplitudeDiff = (animateToAmplitude - amplitude) / (100f + 400f * animationSpeedTiny);
} else {
animateAmplitudeDiff = (animateToAmplitude - amplitude) / (100f + 500f * animationSpeedTiny);
}
}
}
public void updateAmplitude(long dt) {
if (animateToAmplitude != amplitude) {
amplitude += animateAmplitudeDiff * dt;
if (animateAmplitudeDiff > 0) {
if (amplitude > animateToAmplitude) {
amplitude = animateToAmplitude;
}
} else {
if (amplitude < animateToAmplitude) {
amplitude = animateToAmplitude;
}
}
}
}
}