Skip to content

Commit

Permalink
* added GLScissor
Browse files Browse the repository at this point in the history
 * added bitmap brush with pressure support

Change-Id: Ia75745bc4b0b5ea9d2956a903594bc389518b5b5
  • Loading branch information
cedricferry committed Sep 13, 2023
1 parent 54d2fca commit 8bc44fc
Show file tree
Hide file tree
Showing 21 changed files with 2,129 additions and 188 deletions.
10 changes: 5 additions & 5 deletions StylusLowLatency/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The word *pointer* refers to anything that can act as a pointer, such as:
- It is appropriate for small changes to the display (extending an ink stroke) but not large changes (panning, zooming).
- Rendering can be approximate (prediction)

### Double buffered layer is used to persist the pixels
### Multi buffered layer is used to persist the pixels
- It operates when pointer is lifted (`ACTION_UP`)
- Pixels are accurate, true to user input

Expand All @@ -37,7 +37,7 @@ We need to import `graphics-core` into our project
📄 app/build.gradle
dependencies {
implementation 'androidx.graphics:graphics-core:1.0.0-alpha03'
implementation 'androidx.graphics:graphics-core:1.0.0-alpha04'
}
```

Expand All @@ -47,7 +47,7 @@ dependencies {
`GLFrontBufferedRenderer` will take care of Front and Multi buffered layers. It is in charge of optimizing
a [SurfaceView](https://developer.android.com/reference/kotlin/android/view/SurfaceView)
for fast rendering at first on the Front buffered layer (onDrawFrontBufferedLayer). It then will provide data
for rendering Double buffered layer (onDrawDoubleBufferedLayer)
for rendering Multi buffered layer (onDrawMultiBufferedLayer)


### Data points
Expand Down Expand Up @@ -103,7 +103,7 @@ val callbacks = object : GLFrontBufferedRenderer.Callback<DATA_TYPE> {
// OpenGL work for Wet layer, affecting a small area of the screen
}

override fun onDrawDoubleBufferedLayer(
override fun onDrawMultiBufferedLayer(
eglManager: EGLManager,
bufferInfo: BufferInfo,
transform: FloatArray,
Expand Down Expand Up @@ -149,7 +149,7 @@ mySurfaceView.setOnTouchListener { _, event ->
MotionEvent.ACTION_UP -> {
// persist all data points
// triggers the callback onDrawDoubleBufferedLayer
// triggers the callback onDrawMultiBufferedLayer
frontBufferRenderer?.commit()
}
}
Expand Down
19 changes: 17 additions & 2 deletions StylusLowLatency/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright (c) 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
Expand All @@ -9,7 +24,7 @@ android {

defaultConfig {
applicationId "com.example.lowlatencysample"
minSdk 21
minSdk 29
targetSdk 33
versionCode 1
versionName "1.0"
Expand Down Expand Up @@ -63,7 +78,7 @@ dependencies {
// Integration with ViewModels
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'

implementation 'androidx.graphics:graphics-core:1.0.0-alpha03'
implementation 'androidx.graphics:graphics-core:1.0.0-alpha04'
implementation 'androidx.input:input-motionprediction:1.0.0-beta01'

implementation('org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4')
Expand Down
15 changes: 15 additions & 0 deletions StylusLowLatency/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2023 Google, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,15 @@

package com.example.lowlatencysample

import androidx.graphics.opengl.GLRenderer

interface DrawingManager {
fun saveLines(lines: Collection<FloatArray>)
fun saveLines(lines: FloatArray)
fun getLines(): Collection<FloatArray>
var isPredictionEnabled: Boolean
var isGLSurfaceScissorEnabled: Boolean
var isDebugColorEnabled: Boolean
var orientation: Int
var displayRotation: Int
val glRenderer: GLRenderer
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/*
* Copyright (c) 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.lowlatencysample.data

import com.example.lowlatencysample.ui.Brush



/**
* lineLineIntersection
* returns true if the 2 lines intersect
*
* @param line1_x1: Float,
* @param line1_y1: Float,
* @param line1_x2: Float,
* @param line1_y2: Float,
* @param line2_x1: Float,
* @param line2_y1: Float,
* @param line2_x2: Float,
* @param line2_y2: Float
* @return Boolean (true if lines intersect)
*/
fun lineLineIntersection(
line1_x1: Float,
line1_y1: Float,
line1_x2: Float,
line1_y2: Float,
line2_x1: Float,
line2_y1: Float,
line2_x2: Float,
line2_y2: Float
): Boolean {

// calculate the direction of the lines
val uA =
((line2_x2 - line2_x1) * (line1_y1 - line2_y1) - (line2_y2 - line2_y1) * (line1_x1 - line2_x1)) / ((line2_y2 - line2_y1) * (line1_x2 - line1_x1) - (line2_x2 - line2_x1) * (line1_y2 - line1_y1))

if(uA >= 0f && uA <= 1f) { // uA must be between 0-1 to continue

val uB =
((line1_x2 - line1_x1) * (line1_y1 - line2_y1) - (line1_y2 - line1_y1) * (line1_x1 - line2_x1)) / ((line2_y2 - line2_y1) * (line1_x2 - line1_x1) - (line2_x2 - line2_x1) * (line1_y2 - line1_y1))

if(uB >= 0f && uB <= 1f) { // uB is also between 0-1
return true
}

}

return false

}


/**
* lineRectIntersection
* returns true if the line intersects the rectangle
*
* @param x1: Float,
* @param y1: Float,
* @param x2: Float,
* @param y2: Float,
* @param rx: Float,
* @param ry: Float,
* @param rw: Float,
* @param rh: Float
*
* @return Boolean (true if line intersect the rectangle)
*/
fun lineRectIntersection(
x1: Float,
y1: Float,
x2: Float,
y2: Float,
rx: Float,
ry: Float,
rw: Float,
rh: Float
): Boolean {
// check if the line has hit any of the rectangle's sides
// uses the Line/Line function below
val left = lineLineIntersection(x1, y1, x2, y2, rx, ry, rx, ry + rh)
if(left) {
return true
}
val right = lineLineIntersection(x1, y1, x2, y2, rx + rw, ry, rx + rw, ry + rh)
if(right) {
return true
}
val top = lineLineIntersection(x1, y1, x2, y2, rx, ry, rx + rw, ry)
if(top) {
return true
}
val bottom = lineLineIntersection(x1, y1, x2, y2, rx, ry + rh, rx + rw, ry + rh)
if(bottom) {
return true
}

return false
}

/**
* pointInRect
* returns true if the point is in the rectangle or false over wise
*
* @param x: Float
* @param y: Float
* @param rx: Float
* @param ry: Float
* @param rw: Float
* @param rh: Float
* @return Boolean
*/
fun pointInRect(x: Float, y: Float, rx: Float, ry: Float, rw: Float, rh: Float): Boolean {
return x >= rx && x <= rx + rw && y >= ry && y <= ry + rh
}

/**
* lineInOrIntersectRect
* returns true if the line is in or intersects the rectangle
*
* @param x1: Float,
* @param y1: Float,
* @param x2: Float,
* @param y2: Float,
* @param rx: Float,
* @param ry: Float,
* @param rw: Float,
* @param rh: Float
*
* @return Boolean
*/
fun lineInOrIntersectRect(x1: Float,
y1: Float,
x2: Float,
y2: Float,
rx: Float,
ry: Float,
rw: Float,
rh: Float): Boolean {
return pointInRect(x1,y1, rx, ry, rw, rh)
|| pointInRect(x2,y2, rx, ry, rw, rh)
|| lineRectIntersection(x1,y1, x2,y2, rx, ry, rw, rh)
}


/**
* getIntersect
* @param rect: Rect
* returns a sub-line as a Float array for the lines that intersects the rect
*
* @return FloatArray (sub-line)
*/
fun FloatArray.getIntersect(rx: Float,
ry: Float,
rw: Float,
rh: Float): FloatArray {
val floatArrayList = mutableListOf<FloatArray>()

for (i in this.indices step Brush.DATA_STRUCTURE_SIZE) {
val x1 = this[i + Brush.X1_INDEX]
val y1 = this[i + Brush.Y1_INDEX]
val x2 = this[i + Brush.X2_INDEX]
val y2 = this[i + Brush.Y2_INDEX]

if(lineInOrIntersectRect(x1,
y1,
x2,
y2,
rx,
ry,
rw,
rh)) {

floatArrayList.add(floatArrayOf(
x1,
y1,
x2,
y2,
Brush.IS_USER_EVENT,
this[i + Brush.PRESSURE]
))
}
}
return floatArrayList.toFloatArrayLineClean()
}
Loading

0 comments on commit 8bc44fc

Please sign in to comment.