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:
ziadb 2018-07-26 11:52:55 -04:00 committed by Ziad Ben Hadj-Alouane
parent 1347144e3e
commit 90edd336ee
7 changed files with 184 additions and 65 deletions

View File

@ -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'

View File

@ -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

View File

@ -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]);

View File

@ -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();
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>