NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Render.java

208 lines
6.6 KiB
Java

package org.telegram.ui.Components.Paint;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.opengl.GLES20;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class Render {
public static RectF RenderPath(Path path, RenderState state) {
state.baseWeight = path.getBaseWeight();
state.spacing = path.getBrush().getSpacing();
state.alpha = path.getBrush().getAlpha();
state.angle = path.getBrush().getAngle();
state.scale = path.getBrush().getScale();
int length = path.getLength();
if (length == 0) {
return null;
}
if (length == 1) {
PaintStamp(path.getPoints()[0], state);
} else {
Point[] points = path.getPoints();
state.prepare();
for (int i = 0; i < points.length - 1; i++) {
PaintSegment(points[i], points[i + 1], state);
}
}
path.remainder = state.remainder;
return Draw(state);
}
private static void PaintSegment(Point lastPoint, Point point, RenderState state) {
double distance = lastPoint.getDistanceTo(point);
Point vector = point.substract(lastPoint);
Point unitVector = new Point(1.0f, 1.0f, 0.0f);
float vectorAngle = Math.abs(state.angle) > 0.0f ? state.angle : (float) Math.atan2(vector.y, vector.x);
float brushWeight = state.baseWeight * state.scale;
double step = Math.max(1.0f, state.spacing * brushWeight);
if (distance > 0.0) {
unitVector = vector.multiplyByScalar(1.0 / distance);
}
float boldenedAlpha = Math.min(1.0f, state.alpha * 1.15f);
boolean boldenHead = lastPoint.edge;
boolean boldenTail = point.edge;
int count = (int) Math.ceil((distance - state.remainder) / step);
int currentCount = state.getCount();
state.appendValuesCount(count);
state.setPosition(currentCount);
Point start = lastPoint.add(unitVector.multiplyByScalar(state.remainder));
boolean succeed = true;
double f = state.remainder;
for (; f <= distance; f += step) {
float alpha = boldenHead ? boldenedAlpha : state.alpha;
succeed = state.addPoint(start.toPointF(), brushWeight, vectorAngle, alpha, -1);
if (!succeed) {
break;
}
start = start.add(unitVector.multiplyByScalar(step));
boldenHead = false;
}
if (succeed && boldenTail) {
state.appendValuesCount(1);
state.addPoint(point.toPointF(), brushWeight, vectorAngle, boldenedAlpha, -1);
}
state.remainder = f - distance;
}
private static void PaintStamp(Point point, RenderState state) {
float brushWeight = state.baseWeight * state.scale;
PointF start = point.toPointF();
float angle = Math.abs(state.angle) > 0.0f ? state.angle : 0.0f;
float alpha = state.alpha;
state.prepare();
state.appendValuesCount(1);
state.addPoint(start, brushWeight, angle, alpha, 0);
}
private static RectF Draw(RenderState state) {
RectF dataBounds = new RectF(0, 0, 0, 0);
int count = state.getCount();
if (count == 0) {
return dataBounds;
}
int vertexDataSize = 5 * Float.SIZE / 8;
int capacity = vertexDataSize * (count * 4 + (count - 1) * 2);
ByteBuffer bb = ByteBuffer.allocateDirect(capacity);
bb.order(ByteOrder.nativeOrder());
FloatBuffer vertexData = bb.asFloatBuffer();
vertexData.position(0);
state.setPosition(0);
int n = 0;
for (int i = 0; i < count; i++) {
float x = state.read();
float y = state.read();
float size = state.read();
float angle = state.read();
float alpha = state.read();
RectF rect = new RectF(x - size, y - size, x + size, y + size);
float[] points = new float[]{
rect.left, rect.top,
rect.right, rect.top,
rect.left, rect.bottom,
rect.right, rect.bottom
};
float centerX = rect.centerX();
float centerY = rect.centerY();
Matrix t = new Matrix();
t.setRotate((float) Math.toDegrees(angle), centerX, centerY);
t.mapPoints(points);
t.mapRect(rect);
Utils.RectFIntegral(rect);
dataBounds.union(rect);
if (n != 0) {
vertexData.put(points[0]);
vertexData.put(points[1]);
vertexData.put(0);
vertexData.put(0);
vertexData.put(alpha);
n++;
}
vertexData.put(points[0]);
vertexData.put(points[1]);
vertexData.put(0);
vertexData.put(0);
vertexData.put(alpha);
n++;
vertexData.put(points[2]);
vertexData.put(points[3]);
vertexData.put(1);
vertexData.put(0);
vertexData.put(alpha);
n++;
vertexData.put(points[4]);
vertexData.put(points[5]);
vertexData.put(0);
vertexData.put(1);
vertexData.put(alpha);
n++;
vertexData.put(points[6]);
vertexData.put(points[7]);
vertexData.put(1);
vertexData.put(1);
vertexData.put(alpha);
n++;
if (i != count - 1) {
vertexData.put(points[6]);
vertexData.put(points[7]);
vertexData.put(1);
vertexData.put(1);
vertexData.put(alpha);
n++;
}
}
vertexData.position(0);
FloatBuffer coordData = vertexData.slice();
GLES20.glVertexAttribPointer(0, 2, GLES20.GL_FLOAT, false, vertexDataSize, coordData);
GLES20.glEnableVertexAttribArray(0);
vertexData.position(2);
FloatBuffer texData = vertexData.slice();
GLES20.glVertexAttribPointer(1, 2, GLES20.GL_FLOAT, true, vertexDataSize, texData);
GLES20.glEnableVertexAttribArray(1);
vertexData.position(4);
FloatBuffer alphaData = vertexData.slice();
GLES20.glVertexAttribPointer(2, 1, GLES20.GL_FLOAT, true, vertexDataSize, alphaData);
GLES20.glEnableVertexAttribArray(2);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, n);
return dataBounds;
}
}