1 /* <lambda>null2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.graphics.lowlatency 18 19 import android.graphics.Color 20 import android.opengl.GLES20 21 import java.nio.ByteBuffer 22 import java.nio.ByteOrder 23 import java.nio.FloatBuffer 24 25 /** OpenGL Renderer class responsible for drawing lines */ 26 class LineRenderer { 27 28 private var mVertexShader: Int = -1 29 private var mFragmentShader: Int = -1 30 private var mGlProgram: Int = -1 31 32 private var mPositionHandle: Int = -1 33 private var mMvpMatrixHandle: Int = -1 34 35 private var mColorHandle: Int = -1 36 private val mColorArray = FloatArray(4) 37 38 private var mVertexBuffer: FloatBuffer? = null 39 private val mLineCoords = FloatArray(6) 40 41 fun initialize() { 42 release() 43 GLES20.glEnable(GLES20.GL_BLEND) 44 GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA) 45 mVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VertexShaderCode) 46 mFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FragmentShaderCode) 47 48 mGlProgram = GLES20.glCreateProgram() 49 50 GLES20.glAttachShader(mGlProgram, mVertexShader) 51 GLES20.glAttachShader(mGlProgram, mFragmentShader) 52 53 GLES20.glLinkProgram(mGlProgram) 54 55 val bb: ByteBuffer = 56 ByteBuffer.allocateDirect( // (number of coordinate values * 4 bytes per float) 57 LineCoordsSize * 4 58 ) 59 // use the device hardware's native byte order 60 bb.order(ByteOrder.nativeOrder()) 61 62 // create a floating point buffer from the ByteBuffer 63 mVertexBuffer = 64 bb.asFloatBuffer().apply { 65 put(mLineCoords) 66 position(0) 67 } 68 69 mPositionHandle = GLES20.glGetAttribLocation(mGlProgram, vPosition) 70 mMvpMatrixHandle = GLES20.glGetUniformLocation(mGlProgram, uMVPMatrix) 71 mColorHandle = GLES20.glGetUniformLocation(mGlProgram, vColor) 72 } 73 74 fun release() { 75 if (mVertexShader != -1) { 76 GLES20.glDeleteShader(mVertexShader) 77 mVertexShader = -1 78 } 79 80 if (mFragmentShader != -1) { 81 GLES20.glDeleteShader(mFragmentShader) 82 mFragmentShader = -1 83 } 84 85 if (mGlProgram != -1) { 86 GLES20.glDeleteProgram(mGlProgram) 87 mGlProgram = -1 88 } 89 } 90 91 fun drawLines( 92 mvpMatrix: FloatArray, 93 lines: FloatArray, 94 color: Int = Color.RED, 95 lineWidth: Float = 10f 96 ) { 97 GLES20.glUseProgram(mGlProgram) 98 GLES20.glLineWidth(lineWidth) 99 GLES20.glEnableVertexAttribArray(mPositionHandle) 100 mColorArray[0] = Color.red(color) / 255f 101 mColorArray[1] = Color.green(color) / 255f 102 mColorArray[2] = Color.blue(color) / 255f 103 mColorArray[3] = Color.alpha(color) / 255f 104 // Set color for drawing the triangle 105 GLES20.glUniform4fv(mColorHandle, 1, mColorArray, 0) 106 GLES20.glUniformMatrix4fv(mMvpMatrixHandle, 1, false, mvpMatrix, 0) 107 108 mVertexBuffer?.let { buffer -> 109 for (i in 0 until lines.size step 4) { 110 mLineCoords[0] = lines[i] 111 mLineCoords[1] = lines[i + 1] 112 mLineCoords[2] = 0f 113 mLineCoords[3] = lines[i + 2] 114 mLineCoords[4] = lines[i + 3] 115 mLineCoords[5] = 0f 116 buffer.put(mLineCoords) 117 buffer.position(0) 118 } 119 120 // Prepare the triangle coordinate data 121 GLES20.glVertexAttribPointer( 122 mPositionHandle, 123 CoordsPerVertex, 124 GLES20.GL_FLOAT, 125 false, 126 VertexStride, 127 buffer 128 ) 129 GLES20.glDrawArrays(GLES20.GL_LINES, 0, VertexCount) 130 } 131 GLES20.glDisableVertexAttribArray(mPositionHandle) 132 } 133 134 companion object { 135 136 const val CoordsPerVertex = 3 137 const val LineCoordsSize = 6 138 private val VertexCount: Int = LineCoordsSize / CoordsPerVertex 139 private val VertexStride: Int = CoordsPerVertex * 4 // 4 bytes per vertex 140 141 private const val uMVPMatrix = "uMVPMatrix" 142 private const val vPosition = "vPosition" 143 private const val VertexShaderCode = 144 """ 145 uniform mat4 $uMVPMatrix; 146 attribute vec4 $vPosition; 147 void main() { // the matrix must be included as a modifier of gl_Position 148 gl_Position = $uMVPMatrix * $vPosition; 149 } 150 """ 151 private const val vColor = "vColor" 152 private const val FragmentShaderCode = 153 """ 154 precision highp float; 155 156 uniform vec4 $vColor; 157 void main() { 158 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 159 gl_FragColor = $vColor; 160 } 161 """ 162 } 163 } 164