mirror of
https://github.com/Dark98/SliceBeam.git
synced 2026-07-03 00:38:53 +00:00
566 lines
22 KiB
Java
566 lines
22 KiB
Java
package ru.ytkab0bp.slicebeam.view;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.content.Context;
|
|
import android.content.res.Configuration;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Path;
|
|
import android.graphics.PorterDuff;
|
|
import android.graphics.PorterDuffXfermode;
|
|
import android.graphics.Region;
|
|
import android.graphics.Typeface;
|
|
import android.opengl.GLES30;
|
|
import android.opengl.GLException;
|
|
import android.opengl.GLSurfaceView;
|
|
import android.text.Layout;
|
|
import android.text.StaticLayout;
|
|
import android.text.TextPaint;
|
|
import android.view.HapticFeedbackConstants;
|
|
import android.view.MotionEvent;
|
|
import android.view.SurfaceHolder;
|
|
import android.view.ViewConfiguration;
|
|
|
|
import java.nio.IntBuffer;
|
|
import java.util.ArrayList;
|
|
|
|
import javax.microedition.khronos.egl.EGL10;
|
|
import javax.microedition.khronos.egl.EGLConfig;
|
|
import javax.microedition.khronos.egl.EGLDisplay;
|
|
|
|
import ru.ytkab0bp.slicebeam.R;
|
|
import ru.ytkab0bp.slicebeam.SliceBeam;
|
|
import ru.ytkab0bp.slicebeam.events.LongClickTranslationEvent;
|
|
import ru.ytkab0bp.slicebeam.render.GLRenderer;
|
|
import ru.ytkab0bp.slicebeam.slic3r.GLModel;
|
|
import ru.ytkab0bp.slicebeam.theme.IThemeView;
|
|
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
|
|
import ru.ytkab0bp.slicebeam.utils.Prefs;
|
|
import ru.ytkab0bp.slicebeam.utils.Vec3d;
|
|
import ru.ytkab0bp.slicebeam.utils.ViewUtils;
|
|
|
|
public class GLView extends GLSurfaceView implements IThemeView {
|
|
private GLRenderer renderer;
|
|
|
|
private float lastX, lastY;
|
|
private float lastLength;
|
|
private int touchSlop;
|
|
|
|
private boolean fromTwoPointers;
|
|
private boolean onePointerGesture;
|
|
private boolean twoPointerGesture;
|
|
private boolean longClickGesture;
|
|
private boolean isScaling;
|
|
|
|
private Vec3d tempVec = new Vec3d();
|
|
private Vec3d longClickOffset = new Vec3d();
|
|
private Vec3d longClickTranslation = new Vec3d();
|
|
private ArrayList<GLModel.HitResult> longClickHitResults = new ArrayList<>();
|
|
private long lastActionTime = System.currentTimeMillis();
|
|
private Runnable longClick = () -> {
|
|
getRenderer().getBed().getRaycaster().raycast(getRenderer(), longClickHitResults, lastX, lastY);
|
|
if (!longClickHitResults.isEmpty()) {
|
|
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
|
longClickGesture = true;
|
|
|
|
GLModel.HitResult result = longClickHitResults.get(0);
|
|
getRenderer().getModel().getTranslation(getRenderer().getSelectedObject(), tempVec);
|
|
longClickOffset.x = result.position.x - tempVec.x;
|
|
longClickOffset.y = result.position.y - tempVec.y;
|
|
}
|
|
};
|
|
|
|
private Path path = new Path();
|
|
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
private Paint xferPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
|
|
private TextPaint invalidBedText = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
|
private StaticLayout invalidBedDescriptionLayout;
|
|
|
|
private float lastScale;
|
|
|
|
private long lastDraw;
|
|
private float invalidOffset;
|
|
|
|
public GLView(Context context) {
|
|
super(context);
|
|
|
|
xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
|
|
|
setEGLContextClientVersion(3);
|
|
setEGLConfigChooser(new MultisampleConfigChooser());
|
|
renderer = new GLRenderer(this);
|
|
|
|
setRenderer(renderer);
|
|
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
|
|
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
|
setWillNotDraw(false);
|
|
}
|
|
|
|
public void arrange() {
|
|
if (renderer.getModel() == null) return;
|
|
|
|
queueEvent(() -> {
|
|
renderer.getBed().arrange(renderer.getModel());
|
|
renderer.resetGlModels();
|
|
requestRender();
|
|
});
|
|
}
|
|
|
|
public GLRenderer getRenderer() {
|
|
return renderer;
|
|
}
|
|
|
|
public void drawOverlay(Canvas canvas, boolean toBitmap) {
|
|
long dt = Math.min(System.currentTimeMillis() - lastDraw, 16);
|
|
lastDraw = System.currentTimeMillis();
|
|
|
|
int rad = ViewUtils.dp(16);
|
|
float offsetX = getTranslationX(), offsetY = -getTranslationY();
|
|
if (toBitmap) {
|
|
paint.setColor(ThemesRepo.getColor(android.R.attr.windowBackground));
|
|
canvas.drawRect(offsetX, offsetY, getWidth() - offsetX, getHeight() - offsetY, paint);
|
|
canvas.drawRoundRect(offsetX, offsetY, getWidth() - offsetX, getHeight() - offsetY, rad, rad, xferPaint);
|
|
} else {
|
|
path.rewind();
|
|
path.addRoundRect(offsetX, offsetY, getWidth() - offsetX, getHeight() - offsetY, rad, rad, Path.Direction.CW);
|
|
|
|
canvas.save();
|
|
canvas.clipPath(path, Region.Op.DIFFERENCE);
|
|
canvas.drawColor(ThemesRepo.getColor(android.R.attr.windowBackground));
|
|
canvas.restore();
|
|
|
|
if (getRenderer().getBed() != null && !getRenderer().getBed().isValid()) {
|
|
invalidOffset += dt / 10000f;
|
|
|
|
paint.setColor(ThemesRepo.getColor(android.R.attr.windowBackground));
|
|
int size = ViewUtils.dp(200);
|
|
canvas.drawRect(0, (getHeight() - size) / 2f, getWidth(), (getHeight() + size) / 2f, paint);
|
|
|
|
double angle = Math.toRadians(60);
|
|
int stableWidth = ViewUtils.dp(16);
|
|
int lineHeight = ViewUtils.dp(16);
|
|
int lineWidth = ViewUtils.dp(16 + (float) (32 * Math.sin(angle)));
|
|
Path linePath = new Path();
|
|
linePath.moveTo(0, 0);
|
|
linePath.lineTo(stableWidth, 0);
|
|
linePath.lineTo(lineWidth, lineHeight);
|
|
linePath.lineTo(lineWidth - stableWidth, lineHeight);
|
|
linePath.lineTo(0, 0);
|
|
linePath.close();
|
|
|
|
paint.setColor(ThemesRepo.getColor(android.R.attr.colorAccent));
|
|
int x = (int) (-lineWidth - invalidOffset * getWidth());
|
|
while (x < getWidth()) {
|
|
canvas.save();
|
|
canvas.translate(x, (getHeight() - size) / 2f);
|
|
canvas.drawPath(linePath, paint);
|
|
|
|
canvas.translate(stableWidth, 0);
|
|
int alpha = paint.getAlpha();
|
|
paint.setAlpha((int) (alpha * 0.5f));
|
|
canvas.drawPath(linePath, paint);
|
|
canvas.restore();
|
|
paint.setAlpha(alpha);
|
|
|
|
x += stableWidth * 2;
|
|
}
|
|
|
|
x = (int) (getWidth() + lineWidth + invalidOffset * getWidth());
|
|
while (x >= -lineWidth) {
|
|
canvas.save();
|
|
canvas.translate(x, (getHeight() + size) / 2f - lineHeight);
|
|
canvas.drawPath(linePath, paint);
|
|
|
|
canvas.translate(-stableWidth, 0);
|
|
int alpha = paint.getAlpha();
|
|
paint.setAlpha((int) (alpha * 0.5f));
|
|
canvas.drawPath(linePath, paint);
|
|
canvas.restore();
|
|
paint.setAlpha(alpha);
|
|
|
|
x -= stableWidth * 2;
|
|
}
|
|
|
|
if (invalidBedDescriptionLayout == null) {
|
|
invalidBedText.setTextSize(ViewUtils.dp(16));
|
|
invalidBedText.setColor(ThemesRepo.getColor(android.R.attr.textColorSecondary));
|
|
invalidBedText.setTypeface(Typeface.DEFAULT);
|
|
invalidBedDescriptionLayout = new StaticLayout(getContext().getString(R.string.BedConfigurationErrorDesc), invalidBedText, getWidth() - ViewUtils.dp(32), Layout.Alignment.ALIGN_CENTER, 1, 0, false);
|
|
}
|
|
|
|
int realTextSize = ViewUtils.dp(22);
|
|
int padding = ViewUtils.dp(12);
|
|
int totalHeight = realTextSize + invalidBedDescriptionLayout.getHeight();
|
|
|
|
invalidBedText.setTextSize(ViewUtils.dp(18));
|
|
invalidBedText.setColor(ThemesRepo.getColor(android.R.attr.textColorPrimary));
|
|
invalidBedText.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM));
|
|
String errString = getContext().getString(R.string.BedConfigurationError);
|
|
canvas.drawText(errString, 0, errString.length(), (getWidth() - invalidBedText.measureText(errString)) / 2f, getHeight() / 2f - totalHeight / 2f + realTextSize - padding / 2f, invalidBedText);
|
|
|
|
invalidBedText.setTextSize(ViewUtils.dp(16));
|
|
invalidBedText.setColor(ThemesRepo.getColor(android.R.attr.textColorSecondary));
|
|
invalidBedText.setTypeface(Typeface.DEFAULT);
|
|
|
|
canvas.save();
|
|
canvas.translate((getWidth() - invalidBedDescriptionLayout.getWidth()) / 2f, getHeight() / 2f + totalHeight / 2f - invalidBedDescriptionLayout.getHeight() + padding / 2f);
|
|
invalidBedDescriptionLayout.draw(canvas);
|
|
canvas.restore();
|
|
|
|
invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void draw(Canvas canvas) {
|
|
super.draw(canvas);
|
|
|
|
drawOverlay(canvas, false);
|
|
}
|
|
|
|
public Bitmap snapshotBitmap() {
|
|
int w = getWidth(), h = getHeight();
|
|
int[] bitmapBuffer = new int[w * h];
|
|
int[] bitmapSource = new int[w * h];
|
|
IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
|
|
intBuffer.position(0);
|
|
try {
|
|
GLES30.glReadPixels(0, 0, w, h, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, intBuffer);
|
|
int offset1, offset2;
|
|
for (int i = 0; i < h; i++) {
|
|
offset1 = i * w;
|
|
offset2 = (h - i - 1) * w;
|
|
for (int j = 0; j < w; j++) {
|
|
int texturePixel = bitmapBuffer[offset1 + j];
|
|
int blue = (texturePixel >> 16) & 0xff;
|
|
int red = (texturePixel << 16) & 0x00ff0000;
|
|
int pixel = (texturePixel & 0xff00ff00) | red | blue;
|
|
bitmapSource[offset2 + j] = pixel;
|
|
}
|
|
}
|
|
} catch (GLException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);
|
|
}
|
|
|
|
public Bitmap snapshotBitmap(boolean hideBed) {
|
|
if (!hideBed) {
|
|
return snapshotBitmap();
|
|
}
|
|
|
|
boolean prev = renderer.isBedVisible();
|
|
renderer.setBedVisible(false);
|
|
renderer.onDrawFrame(null);
|
|
Bitmap snapshot = snapshotBitmap();
|
|
renderer.setBedVisible(prev);
|
|
return snapshot;
|
|
}
|
|
|
|
public Bitmap snapshotBitmap(boolean hideBed, int scaleFactor) {
|
|
if (scaleFactor <= 1) {
|
|
return snapshotBitmap(hideBed);
|
|
}
|
|
int w = getWidth();
|
|
int h = getHeight();
|
|
if (w <= 0 || h <= 0) {
|
|
return null;
|
|
}
|
|
return renderer.renderToBitmap(w * scaleFactor, h * scaleFactor, hideBed, false);
|
|
}
|
|
|
|
public Bitmap snapshotBitmap(int width, int height, boolean hideBed) {
|
|
return renderer.renderToBitmap(width, height, hideBed, false);
|
|
}
|
|
|
|
public Bitmap snapshotBitmap(int width, int height, boolean hideBed, boolean topView) {
|
|
return renderer.renderToBitmap(width, height, hideBed, topView);
|
|
}
|
|
|
|
private static final class MultisampleConfigChooser implements EGLConfigChooser {
|
|
private static final int EGL_OPENGL_ES2_BIT = 4;
|
|
|
|
@Override
|
|
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
|
|
int[] configSpec = {
|
|
EGL10.EGL_RED_SIZE, 8,
|
|
EGL10.EGL_GREEN_SIZE, 8,
|
|
EGL10.EGL_BLUE_SIZE, 8,
|
|
EGL10.EGL_ALPHA_SIZE, 8,
|
|
EGL10.EGL_DEPTH_SIZE, 16,
|
|
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
EGL10.EGL_SAMPLE_BUFFERS, 1,
|
|
EGL10.EGL_SAMPLES, 4,
|
|
EGL10.EGL_NONE
|
|
};
|
|
EGLConfig config = chooseConfig(egl, display, configSpec);
|
|
if (config != null) {
|
|
return config;
|
|
}
|
|
|
|
int[] fallbackSpec = {
|
|
EGL10.EGL_RED_SIZE, 8,
|
|
EGL10.EGL_GREEN_SIZE, 8,
|
|
EGL10.EGL_BLUE_SIZE, 8,
|
|
EGL10.EGL_ALPHA_SIZE, 8,
|
|
EGL10.EGL_DEPTH_SIZE, 16,
|
|
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
EGL10.EGL_NONE
|
|
};
|
|
return chooseConfig(egl, display, fallbackSpec);
|
|
}
|
|
|
|
private EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, int[] configSpec) {
|
|
int[] numConfigs = new int[1];
|
|
if (!egl.eglChooseConfig(display, configSpec, null, 0, numConfigs)) {
|
|
return null;
|
|
}
|
|
int count = numConfigs[0];
|
|
if (count <= 0) {
|
|
return null;
|
|
}
|
|
EGLConfig[] configs = new EGLConfig[count];
|
|
if (!egl.eglChooseConfig(display, configSpec, configs, count, numConfigs)) {
|
|
return null;
|
|
}
|
|
return configs[0];
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onConfigurationChanged(Configuration newConfig) {
|
|
super.onConfigurationChanged(newConfig);
|
|
touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
|
}
|
|
|
|
private void calcStartFocus(MotionEvent e) {
|
|
lastX = (e.getX(0) + e.getX(1)) / 2f;
|
|
lastY = (e.getY(0) + e.getY(1)) / 2f;
|
|
|
|
float x = e.getX(0) - e.getX(1), y = e.getY(0) - e.getY(1);
|
|
lastLength = (float) Math.sqrt(x * x + y * y);
|
|
}
|
|
|
|
@Override
|
|
public boolean onHoverEvent(MotionEvent event) {
|
|
if (event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT ? renderer.stopHover() : renderer.hover(event.getX() * Prefs.getRenderScale(), event.getY() * Prefs.getRenderScale())) {
|
|
queueEvent(this::requestRender);
|
|
}
|
|
return super.onHoverEvent(event);
|
|
}
|
|
|
|
@SuppressLint("ClickableViewAccessibility")
|
|
@Override
|
|
public boolean onTouchEvent(MotionEvent e) {
|
|
long deltaMs = System.currentTimeMillis() - lastActionTime;
|
|
lastActionTime = System.currentTimeMillis();
|
|
int action = e.getActionMasked();
|
|
|
|
if (e.getPointerCount() > 2) {
|
|
removeCallbacks(longClick);
|
|
longClickGesture = false;
|
|
return true;
|
|
}
|
|
|
|
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
|
|
if (e.getPointerCount() == 2) {
|
|
removeCallbacks(longClick);
|
|
longClickGesture = false;
|
|
calcStartFocus(e);
|
|
fromTwoPointers = true;
|
|
} else {
|
|
lastX = e.getX();
|
|
lastY = e.getY();
|
|
|
|
int j = renderer.raycastObjectIndex(lastX, lastY);
|
|
if (renderer.getGcodeResult() == null && j == renderer.getSelectedObject() && j != -1) {
|
|
postDelayed(longClick, 300);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_CANCEL) {
|
|
removeCallbacks(longClick);
|
|
if (longClickGesture) {
|
|
queueEvent(()->{
|
|
int j = getRenderer().getSelectedObject();
|
|
getRenderer().getModel().getTranslation(j, tempVec);
|
|
getRenderer().setSelectionTranslation(0, 0, 0);
|
|
getRenderer().getModel().translate(j, longClickTranslation.x, longClickTranslation.y, 0);
|
|
getRenderer().invalidateGlModel(j);
|
|
requestRender();
|
|
SliceBeam.EVENT_BUS.fireEvent(new LongClickTranslationEvent(longClickTranslation.x, longClickTranslation.y, false));
|
|
});
|
|
}
|
|
longClickGesture = false;
|
|
if (fromTwoPointers) {
|
|
if (e.getPointerCount() == 1) {
|
|
fromTwoPointers = false;
|
|
isScaling = false;
|
|
twoPointerGesture = false;
|
|
lastActionTime = 0;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (e.getPointerCount() == 1) {
|
|
if (!onePointerGesture && action != MotionEvent.ACTION_CANCEL) {
|
|
if (renderer.onClick(e.getX() * Prefs.getRenderScale(), e.getY() * Prefs.getRenderScale())) {
|
|
requestRender();
|
|
}
|
|
}
|
|
|
|
lastX = e.getX(0);
|
|
lastY = e.getY(0);
|
|
onePointerGesture = false;
|
|
}
|
|
|
|
// TODO: Rotate with inertia?
|
|
return true;
|
|
}
|
|
if (action == MotionEvent.ACTION_MOVE) {
|
|
if (e.getPointerCount() == 2) {
|
|
float x = (e.getX(0) + e.getX(1)) / 2f;
|
|
float y = (e.getY(0) + e.getY(1)) / 2f;
|
|
|
|
float lenX = e.getX(0) - e.getX(1), lenY = e.getY(0) - e.getY(1);
|
|
float len = (float) Math.sqrt(lenX * lenX + lenY * lenY);
|
|
float distanceX = lastX - x, distanceY = lastY - y;
|
|
|
|
if (deltaMs > 128) {
|
|
isScaling = false;
|
|
twoPointerGesture = false;
|
|
}
|
|
|
|
boolean startingGesture = false;
|
|
if (!isScaling && !twoPointerGesture) {
|
|
if (Math.abs(distanceX) < touchSlop && Math.abs(distanceY) < touchSlop && Math.abs(len - lastLength) > touchSlop * 1.5f) {
|
|
isScaling = true;
|
|
startingGesture = true;
|
|
} else if (Math.sqrt(distanceX * distanceX + distanceY * distanceY) >= touchSlop) {
|
|
twoPointerGesture = true;
|
|
startingGesture = true;
|
|
}
|
|
}
|
|
if (isScaling) {
|
|
float delta = len - lastLength;
|
|
lastLength = len;
|
|
|
|
if (!startingGesture) {
|
|
renderer.getCamera().zoom(delta / touchSlop * Prefs.getCameraSensitivity());
|
|
renderer.updateProjection();
|
|
requestRender();
|
|
}
|
|
|
|
lastX = x;
|
|
lastY = y;
|
|
} else if (twoPointerGesture) {
|
|
if (!startingGesture) {
|
|
int mode = Prefs.getCameraControlMode();
|
|
if (mode == Prefs.CAMERA_CONTROL_MODE_ROTATE_MOVE || mode == Prefs.CAMERA_CONTROL_MODE_MOVE_ONLY) {
|
|
renderer.getCamera().move(distanceX / touchSlop * Prefs.getCameraSensitivity(), distanceY / touchSlop * Prefs.getCameraSensitivity());
|
|
} else {
|
|
renderer.getCamera().rotateAround(distanceX / touchSlop * Prefs.getCameraSensitivity(), distanceY / touchSlop * Prefs.getCameraSensitivity());
|
|
}
|
|
requestRender();
|
|
}
|
|
|
|
lastX = x;
|
|
lastY = y;
|
|
}
|
|
} else if (!fromTwoPointers) {
|
|
float distanceX = lastX - e.getX(), distanceY = lastY - e.getY();
|
|
boolean startingGesture = false;
|
|
|
|
if (!onePointerGesture) {
|
|
if (Math.sqrt(distanceX * distanceX + distanceY * distanceY) >= touchSlop) {
|
|
onePointerGesture = true;
|
|
startingGesture = true;
|
|
removeCallbacks(longClick);
|
|
}
|
|
}
|
|
|
|
if (onePointerGesture) {
|
|
if (!startingGesture) {
|
|
if (longClickGesture) {
|
|
getRenderer().getModel().getTranslation(getRenderer().getSelectedObject(), tempVec);
|
|
getRenderer().getBed().getRaycaster().raycast(getRenderer(), longClickHitResults, e.getX(), e.getY());
|
|
if (!longClickHitResults.isEmpty()) {
|
|
GLModel.HitResult result = longClickHitResults.get(0);
|
|
longClickTranslation.x = result.position.x - tempVec.x - longClickOffset.x;
|
|
longClickTranslation.y = result.position.y - tempVec.y - longClickOffset.y;
|
|
getRenderer().setSelectionTranslation(longClickTranslation.x, longClickTranslation.y, 0);
|
|
SliceBeam.EVENT_BUS.fireEvent(new LongClickTranslationEvent(longClickTranslation.x, longClickTranslation.y, true));
|
|
}
|
|
|
|
requestRender();
|
|
} else {
|
|
int mode = Prefs.getCameraControlMode();
|
|
if (mode == Prefs.CAMERA_CONTROL_MODE_ROTATE_MOVE) {
|
|
renderer.getCamera().rotateAround(distanceX / touchSlop * Prefs.getCameraSensitivity(), distanceY / touchSlop * Prefs.getCameraSensitivity());
|
|
} else {
|
|
renderer.getCamera().move(distanceX / touchSlop * Prefs.getCameraSensitivity(), distanceY / touchSlop * Prefs.getCameraSensitivity());
|
|
}
|
|
requestRender();
|
|
}
|
|
}
|
|
|
|
lastX = e.getX();
|
|
lastY = e.getY();
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void applyScale() {
|
|
int w = getWidth(), h = getHeight();
|
|
float realScale = Math.round(w * (lastScale = Prefs.getRenderScale())) / (float) w;
|
|
getHolder().setFixedSize((int) (w * realScale), (int) (h * realScale));
|
|
}
|
|
|
|
@Override
|
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
|
super.onSizeChanged(w, h, oldw, oldh);
|
|
if (w != 0 && h != 0) {
|
|
applyScale();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onAttachedToWindow() {
|
|
super.onAttachedToWindow();
|
|
if (getWidth() > 0 && getHeight() > 0 && lastScale != Prefs.getRenderScale()) {
|
|
applyScale();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void surfaceCreated(SurfaceHolder holder) {
|
|
super.surfaceCreated(holder);
|
|
requestRender();
|
|
}
|
|
|
|
@Override
|
|
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
|
|
super.surfaceChanged(holder, format, w, h);
|
|
requestRender();
|
|
}
|
|
|
|
@Override
|
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
|
super.surfaceDestroyed(holder);
|
|
renderer.onDestroy();
|
|
}
|
|
|
|
@Override
|
|
public void onApplyTheme() {
|
|
requestRender();
|
|
}
|
|
}
|