mirror of https://github.com/NekoX-Dev/NekoX.git
208 lines
6.6 KiB
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;
|
||
|
}
|
||
|
}
|