SkAR Java: better UI for finger painting
Merge branch 'master' of https://skia.googlesource.com/skia into skar-java SkAR Java: smooth finger painting, planes draw with outlines SkAR Java: better finger painting. Cleaner UI FREEZE.unindexed SkAR Java: drawing planes as paths Bug: skia: Change-Id: If138d1d840c013848b1482830713affa5b5d815b Reviewed-on: https://skia-review.googlesource.com/143502 Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
parent
1347144e3e
commit
90edd336ee
@ -33,7 +33,7 @@ dependencies {
|
||||
implementation 'de.javagl:obj:0.2.1'
|
||||
|
||||
implementation 'com.android.support:appcompat-v7:27.0.2'
|
||||
implementation 'com.android.support:design:27.0.2'
|
||||
implementation 'com.android.support:design:27.1.1'
|
||||
|
||||
// Required -- JUnit 4 framework
|
||||
testImplementation 'junit:junit:4.12'
|
||||
|
@ -143,7 +143,7 @@ public class DrawManager {
|
||||
fingerPainting.buildPath();
|
||||
|
||||
// If path empty, return
|
||||
if (fingerPainting.path.isEmpty()) {
|
||||
if (fingerPainting.getPaths().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -164,35 +164,37 @@ public class DrawManager {
|
||||
float[][] matrices = {scale, initRot, in, viewMatrix, projectionMatrix, SkARMatrix.createViewportMatrix(viewportWidth, viewportHeight)};
|
||||
android.graphics.Matrix mvpv = SkARMatrix.createMatrixFrom4x4(SkARMatrix.multiplyMatrices4x4(matrices));
|
||||
|
||||
// Set up paint
|
||||
Paint p = new Paint();
|
||||
if (fingerPainting.getSmoothness()) {
|
||||
p.setColor(Color.CYAN);
|
||||
} else {
|
||||
p.setColor(Color.GREEN);
|
||||
for (Path path : fingerPainting.getPaths()) {
|
||||
if (path.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// Set up paint
|
||||
Paint p = new Paint();
|
||||
p.setColor(fingerPainting.getPathColor(path));
|
||||
|
||||
p.setStyle(Paint.Style.STROKE);
|
||||
p.setStrokeWidth(30f);
|
||||
p.setAlpha(120);
|
||||
|
||||
if (true) {
|
||||
// Transform applied through canvas
|
||||
canvas.save();
|
||||
canvas.setMatrix(mvpv);
|
||||
canvas.drawPath(path, p);
|
||||
canvas.restore();
|
||||
} else {
|
||||
// Transform path directly
|
||||
Path pathDst = new Path();
|
||||
path.transform(mvpv, pathDst);
|
||||
|
||||
// Draw dest path
|
||||
canvas.save();
|
||||
canvas.setMatrix(new android.graphics.Matrix());
|
||||
canvas.drawPath(pathDst, p);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
p.setStyle(Paint.Style.STROKE);
|
||||
p.setStrokeWidth(30f);
|
||||
p.setAlpha(120);
|
||||
|
||||
if (true) {
|
||||
// Transform applied through canvas
|
||||
canvas.save();
|
||||
canvas.setMatrix(mvpv);
|
||||
canvas.drawPath(fingerPainting.path, p);
|
||||
canvas.restore();
|
||||
} else {
|
||||
// Transform path directly
|
||||
Path pathDst = new Path();
|
||||
fingerPainting.path.transform(mvpv, pathDst);
|
||||
|
||||
// Draw dest path
|
||||
canvas.save();
|
||||
canvas.setMatrix(new android.graphics.Matrix());
|
||||
canvas.drawPath(pathDst, p);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
// Sample function for drawing the AR point cloud
|
||||
|
@ -26,6 +26,9 @@ import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.opengl.Matrix;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.internal.BottomNavigationMenuView;
|
||||
import android.support.design.widget.BottomNavigationView;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
@ -104,12 +107,12 @@ public class HelloSkARActivity extends AppCompatActivity implements GLSurfaceVie
|
||||
// 2D Renderer
|
||||
private DrawManager drawManager = new DrawManager();
|
||||
private DrawingType currentDrawabletype = DrawingType.circle;
|
||||
private boolean drawSmoothPainting = false;
|
||||
private boolean drawSmoothPainting = true;
|
||||
|
||||
// Temporary matrix allocated here to reduce number of allocations for each frame.
|
||||
private final float[] anchorMatrix = new float[16];
|
||||
|
||||
PointF previousEvent;;
|
||||
PointF previousEvent;
|
||||
|
||||
// Anchors created from taps used for object placing.
|
||||
private final ArrayList<Anchor> anchors = new ArrayList<>();
|
||||
@ -151,6 +154,26 @@ public class HelloSkARActivity extends AppCompatActivity implements GLSurfaceVie
|
||||
|
||||
installRequested = false;
|
||||
|
||||
BottomNavigationView bottomNav = findViewById(R.id.palette);
|
||||
bottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.palette_green:
|
||||
drawManager.fingerPainting.setColor(Color.GREEN);
|
||||
return true;
|
||||
case R.id.palette_red:
|
||||
drawManager.fingerPainting.setColor(Color.RED);
|
||||
return true;
|
||||
case R.id.palette_reset:
|
||||
drawManager.fingerPainting.reset();
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Animator set up
|
||||
PropertyValuesHolder propertyRadius = PropertyValuesHolder.ofFloat(PROPERTY_RADIUS, 0, 0.5f);
|
||||
animator = new ValueAnimator();
|
||||
@ -353,9 +376,9 @@ public class HelloSkARActivity extends AppCompatActivity implements GLSurfaceVie
|
||||
drawManager.updateLightColorFilter(colorCorrectionRgba);
|
||||
|
||||
// Building finger painting
|
||||
MotionEvent holdTap = tapHelper.holdPoll();
|
||||
TapHelper.ScrollEvent holdTap = tapHelper.holdPoll();
|
||||
if (holdTap != null && camera.getTrackingState() == TrackingState.TRACKING) {
|
||||
for (HitResult hit : frame.hitTest(holdTap)) {
|
||||
for (HitResult hit : frame.hitTest(holdTap.e)) {
|
||||
// Check if any plane was hit, and if it was hit inside the plane polygon
|
||||
Trackable trackable = hit.getTrackable();
|
||||
// Creates an anchor if a plane or an oriented point was hit.
|
||||
@ -374,7 +397,7 @@ public class HelloSkARActivity extends AppCompatActivity implements GLSurfaceVie
|
||||
Matrix.multiplyMV(point, 0, gm, 0, point, 0);
|
||||
|
||||
if (drawManager.fingerPainting.isEmpty()) {
|
||||
drawManager.fingerPainting.addPoint(new PointF(0, 0));
|
||||
drawManager.fingerPainting.addPoint(new PointF(0, 0), true);
|
||||
|
||||
// Get model matrix of first point
|
||||
float[] m = new float[16];
|
||||
@ -395,7 +418,7 @@ public class HelloSkARActivity extends AppCompatActivity implements GLSurfaceVie
|
||||
distance.y * localDistanceScale
|
||||
+ drawManager.fingerPainting.previousPoint.y);
|
||||
|
||||
drawManager.fingerPainting.addPoint(p);
|
||||
drawManager.fingerPainting.addPoint(p, holdTap.isStartOfScroll);
|
||||
}
|
||||
|
||||
previousEvent = new PointF(point[0], point[2]);
|
||||
|
@ -1,16 +1,25 @@
|
||||
package com.google.skar;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PointF;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SkARFingerPainting {
|
||||
// Points obtained by touching the screen. The first point is always brough to (0,0).
|
||||
// All subsequent points are translated by the same amount.
|
||||
public ArrayList<PointF> points = new ArrayList<>();
|
||||
|
||||
public Path path = new Path();
|
||||
private ArrayList<PointF> points = new ArrayList<>();
|
||||
private ArrayList<Integer> jumpPoints = new ArrayList<>();
|
||||
private Map<Integer, Integer> indexColors = new HashMap<>();
|
||||
private Map<Path, Integer> pathColors = new HashMap<>();
|
||||
private ArrayList<Path> paths = new ArrayList<>();
|
||||
private int color = Color.RED;
|
||||
|
||||
// Previous point added to the path. This points belongs to the path in local space.
|
||||
public PointF previousPoint;
|
||||
@ -34,49 +43,87 @@ public class SkARFingerPainting {
|
||||
}
|
||||
|
||||
// Adds another point to the path in Local space
|
||||
public void addPoint(PointF p) {
|
||||
public void addPoint(PointF p, boolean jumpPoint) {
|
||||
points.add(p);
|
||||
if (jumpPoint) {
|
||||
Log.i("Jumped!", Integer.toString(points.size() - 1));
|
||||
jumpPoints.add(points.size() - 1);
|
||||
indexColors.put(points.size() - 1, color);
|
||||
}
|
||||
previousPoint = p;
|
||||
}
|
||||
|
||||
// Used to build a path before rendering it
|
||||
public void buildPath() {
|
||||
if (points.size() < 1) {
|
||||
paths = new ArrayList<>();
|
||||
if (points.size() <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
path = new Path();
|
||||
|
||||
if (isSmooth) {
|
||||
// If less than 3 points, than draw a line between the two points
|
||||
if (points.size() <= 2 && points.size() > 0) {
|
||||
path.moveTo(points.get(0).x, points.get(0).y);
|
||||
path.lineTo(points.get(1).x, points.get(1).y);
|
||||
} else if (points.size() >= 3){
|
||||
// Else, essentially run deCasteljau
|
||||
path.moveTo(points.get(0).x, points.get(0).y);
|
||||
PointF mid = new PointF((points.get(0).x + points.get(1).x) / 2,
|
||||
(points.get(0).y + points.get(1).y) / 2);
|
||||
path.lineTo(mid.x, mid.y);
|
||||
int start = 0;
|
||||
for (int j = 1; j < jumpPoints.size(); j++) {
|
||||
|
||||
for (int i = 1; i < points.size() - 1; i++) {
|
||||
PointF p1 = points.get(i);
|
||||
PointF p2 = points.get(i + 1);
|
||||
PointF midP = new PointF((p1.x + p2.x) / 2,(p1.y + p2.y) / 2);
|
||||
path.quadTo(p1.x, p1.y, midP.x, midP.y);
|
||||
}
|
||||
|
||||
path.lineTo(points.get(points.size() - 1).x, points.get(points.size() - 1).y);
|
||||
int finish = jumpPoints.get(j);
|
||||
buildSmoothFromTo(start, finish);
|
||||
start = finish;
|
||||
}
|
||||
|
||||
buildSmoothFromTo(start, points.size());
|
||||
} else {
|
||||
path.moveTo(points.get(0).x, points.get(0).y);
|
||||
for (int i = 1; i < points.size(); i++) {
|
||||
path.lineTo(points.get(i).x, points.get(i).y);
|
||||
|
||||
int start = 0;
|
||||
for (int j = 1; j < jumpPoints.size(); j++) {
|
||||
int finish = jumpPoints.get(j);
|
||||
buildRoughFromTo(start, finish);
|
||||
start = finish;
|
||||
}
|
||||
|
||||
buildRoughFromTo(start, points.size());
|
||||
}
|
||||
}
|
||||
|
||||
private void buildRoughFromTo(int start, int finish) {
|
||||
Path p = new Path();
|
||||
int c = indexColors.get(start);
|
||||
p.moveTo(points.get(start).x, points.get(start).y);
|
||||
for (int i = start + 1; i < finish; i++) {
|
||||
p.lineTo(points.get(i).x, points.get(i).y);
|
||||
}
|
||||
paths.add(p);
|
||||
pathColors.put(p, c);
|
||||
}
|
||||
|
||||
private void buildSmoothFromTo(int start, int finish) {
|
||||
Path p = new Path();
|
||||
int c = indexColors.get(start);
|
||||
int nbPts = finish - start;
|
||||
// If less than 3 points, than draw a line between the two points
|
||||
if (nbPts <= 2 && nbPts > 1) {
|
||||
p.moveTo(points.get(start).x, points.get(start).y);
|
||||
p.lineTo(points.get(start + 1).x, points.get(start + 1).y);
|
||||
} else if (nbPts >= 3){
|
||||
// Else, essentially run deCasteljau
|
||||
p.moveTo(points.get(start).x, points.get(start).y);
|
||||
PointF mid = new PointF((points.get(start).x + points.get(start + 1).x) / 2,
|
||||
(points.get(start).y + points.get(start + 1).y) / 2);
|
||||
p.lineTo(mid.x, mid.y);
|
||||
|
||||
for (int i = start + 1; i < finish - 1; i++) {
|
||||
PointF p1 = points.get(i);
|
||||
PointF p2 = points.get(i + 1);
|
||||
p.quadTo(p1.x, p1.y, (p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
|
||||
}
|
||||
|
||||
p.lineTo(points.get(finish - 1).x, points.get(finish - 1).y);
|
||||
}
|
||||
paths.add(p);
|
||||
pathColors.put(p, c);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return path.isEmpty();
|
||||
return points.isEmpty();
|
||||
}
|
||||
|
||||
public float[] getModelMatrix() {
|
||||
@ -87,8 +134,23 @@ public class SkARFingerPainting {
|
||||
modelMatrix = m;
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public int getPathColor(Path p) {
|
||||
return pathColors.get(p);
|
||||
}
|
||||
|
||||
public ArrayList<Path> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
points = new ArrayList<>();
|
||||
path = new Path();
|
||||
points.clear();
|
||||
jumpPoints.clear();
|
||||
paths.clear();
|
||||
pathColors.clear();
|
||||
indexColors.clear();
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,13 @@
|
||||
android:id="@+id/glsurfaceview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<android.support.design.widget.BottomNavigationView
|
||||
android:id="@+id/palette"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
app:menu="@menu/platte_bar"
|
||||
style="@style/BottomNavigation" />
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/palette_red"
|
||||
android:title="Red" />
|
||||
<item
|
||||
android:id="@+id/palette_green"
|
||||
android:title="Green" />
|
||||
<item
|
||||
android:id="@+id/palette_reset"
|
||||
android:title="Reset" />
|
||||
</menu>
|
@ -32,4 +32,17 @@
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
<style name="QText" parent="Widget.Design.BottomNavigationView">
|
||||
<item name="android:textSize">20sp</item>
|
||||
<item name="android:textColor">@android:color/holo_red_dark</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:typeface">sans</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomNavigation" parent="Widget.Design.BottomNavigationView">
|
||||
<item name="itemBackground">@android:color/darker_gray</item>
|
||||
<!-- <item name="paddingStart">10dp</item>
|
||||
<item name="paddingEnd">10dp</item>-->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user