[androidkit] Relative-sized cube sample

Update the cube sample to be centered and sized relative to the target
surface.

Also simplify projection handling:

  - pre-compute a full view matrix in onSurfaceInitialized()
  - set the origin to the surface center
  - compute perspective and camera transforms in local coordinates
    (instead of unit view cube)

Also fix (invert) fling Y direction.

Change-Id: I48a3d0b4547812fb3c9b49a9842fb18c0ed0d863
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/413436
Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
This commit is contained in:
Florin Malita 2021-05-27 23:01:20 -04:00 committed by Florin Malita
parent 491f412c94
commit 4abf558c9f

View File

@ -135,22 +135,10 @@ class VSphereAnimator {
class CubeRenderer extends SurfaceRenderer implements GestureDetector.OnGestureListener {
private VSphereAnimator mVSphere;
private Matrix mViewMatrix;
private float mCubeSideLength;
private long mPrevMS;
// TODO: make these relative to surface size
private float mCubeSideLength = 500;
private int DX = 200;
private int DY = 300;
private long mPrevMS;
private float fAngle = (float)Math.PI / 12;
private float eyeZ = (float)(1.0f/tan(fAngle/2) - 1);
private Matrix cam = Matrix.makeLookAt(0, 0, eyeZ, 0, 0, 0, 0, 1, 0);
private Matrix perspective = Matrix.makePerspective(0.05f, 4, fAngle);
private Matrix viewport;
private final float rot = (float) Math.PI;
private Face[] faces;
public CubeRenderer(Resources res) {
@ -164,6 +152,7 @@ class CubeRenderer extends SurfaceRenderer implements GestureDetector.OnGestureL
brickPaint.setShader(shader);
} catch (Exception e) {}
final float rot = (float) Math.PI;
faces = new Face[] {
new Face(0, -rot/2, brickPaint),
new Face(0, 0 , new Paint().setColor(new Color(1, 0, 0, 1))),
@ -176,12 +165,28 @@ class CubeRenderer extends SurfaceRenderer implements GestureDetector.OnGestureL
@Override
protected void onSurfaceInitialized(Surface surface) {
float hw = surface.getWidth() / 2,
hh = surface.getHeight() / 2;
mVSphere = new VSphereAnimator(hw, hh, Math.min(hw, hh));
float cx = surface.getWidth() / 2,
cy = surface.getHeight() / 2,
r = Math.min(cx, cy);
viewport = new Matrix().translate(mCubeSideLength/2, mCubeSideLength/2, 0)
.scale(mCubeSideLength/2, mCubeSideLength/2, surface.getWidth());
mVSphere = new VSphereAnimator(cx, cy, r);
// square viewport size fitting the given surface
float vsz = r * 2;
mCubeSideLength = vsz * 0.5f;
float viewAngle = (float)Math.PI / 4f,
viewDistance = (float)(r / tan(viewAngle/2));
mViewMatrix = new Matrix()
// centered viewport
.translate(cx, cy)
// perspective
.scale(vsz/2, vsz/2, 1)
.preConcat(Matrix.makePerspective(0.05f, viewDistance, viewAngle))
// camera
.preConcat(Matrix.makeLookAt(0, 0, -viewDistance, 0, 0, 0, 0, 1, 0));
}
@Override
@ -198,24 +203,17 @@ class CubeRenderer extends SurfaceRenderer implements GestureDetector.OnGestureL
canvas.drawColor(0xffffffff);
canvas.save();
canvas.concat(new Matrix().translate(DX, DY, 0));
canvas.concat(viewport.preConcat(perspective)
.preConcat(cam)
.preConcat(Matrix.makeInverse(viewport)));
canvas.concat(mViewMatrix);
canvas.concat(mVSphere.getMatrix());
for (Face f : faces) {
//TODO: auto restore
canvas.save();
Matrix trans = new Matrix().translate(mCubeSideLength/2, mCubeSideLength/2, 0);
Matrix m = new Matrix().preConcat(mVSphere.getMatrix())
.preConcat(f.asMatrix(mCubeSideLength/2));
canvas.concat(trans);
Matrix localToWorld = m.preConcat(Matrix.makeInverse(trans));
canvas.concat(localToWorld);
canvas.concat(f.asMatrix(mCubeSideLength/2));
if (front(canvas.getLocalToDevice())) {
canvas.drawRect(0, 0, mCubeSideLength, mCubeSideLength, f.paint);
canvas.drawRect(-mCubeSideLength/2, -mCubeSideLength/2,
mCubeSideLength/2, mCubeSideLength/2, f.paint);
}
canvas.restore();
}
@ -224,7 +222,7 @@ class CubeRenderer extends SurfaceRenderer implements GestureDetector.OnGestureL
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float dx, float dy) {
mVSphere.fling(dx, dy);
mVSphere.fling(dx, -dy);
return true;
}