1 /*
2  * 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 package androidx.graphics.lowlatency
17 
18 import android.graphics.Color
19 import android.opengl.GLES20
20 import java.nio.ByteBuffer
21 import java.nio.ByteOrder
22 import java.nio.FloatBuffer
23 import java.nio.ShortBuffer
24 
25 class Rectangle {
26 
27     private val mVertexBuffer: FloatBuffer
28     private val mDrawListBuffer: ShortBuffer
29     private val mProgram: Int
30     private var mPositionHandle = 0
31     private var mColorHandle = 0
32     private var mMVPMatrixHandle = 0
33     private var mColor = floatArrayOf(1f, 0f, 0f, 1f)
34     private var mSquareCoords = FloatArray(12)
35 
36     /** Sets up the drawing object data for use in an OpenGL ES context. */
37     init {
38         // initialize vertex byte buffer for shape coordinates
39         val bb =
40             ByteBuffer.allocateDirect( // (# of coordinate values * 4 bytes per float)
41                 mSquareCoords.size * 4
42             )
43         bb.order(ByteOrder.nativeOrder())
44         mVertexBuffer = bb.asFloatBuffer()
45         mVertexBuffer.put(mSquareCoords)
46         mVertexBuffer.position(0)
47         // initialize byte buffer for the draw list
48         val dlb =
49             ByteBuffer.allocateDirect( // (# of coordinate values * 2 bytes per short)
50                 DRAW_ORDER.size * 2
51             )
52         dlb.order(ByteOrder.nativeOrder())
53         mDrawListBuffer = dlb.asShortBuffer()
54         mDrawListBuffer.put(DRAW_ORDER)
55         mDrawListBuffer.position(0)
56         // prepare shaders and OpenGL program
57         val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
58         val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
59         mProgram = GLES20.glCreateProgram() // create empty OpenGL Program
60         GLES20.glAttachShader(mProgram, vertexShader) // add the vertex shader to program
61         GLES20.glAttachShader(mProgram, fragmentShader) // add the fragment shader to program
62         GLES20.glLinkProgram(mProgram) // create OpenGL program executables
63     }
64 
drawnull65     fun draw(
66         mvpMatrix: FloatArray?,
67         color: Int,
68         left: Float,
69         top: Float,
70         right: Float,
71         bottom: Float
72     ) {
73 
74         mColor[0] = Color.red(color) / 255f
75         mColor[1] = Color.green(color) / 255f
76         mColor[2] = Color.blue(color) / 255f
77         mColor[3] = Color.alpha(color) / 255f
78 
79         // top left
80         mSquareCoords[0] = left
81         mSquareCoords[1] = top
82         mSquareCoords[2] = 0f
83         // bottom left
84         mSquareCoords[3] = left
85         mSquareCoords[4] = bottom
86         mSquareCoords[5] = 0f
87         // bottom right
88         mSquareCoords[6] = right
89         mSquareCoords[7] = bottom
90         mSquareCoords[8] = 0f
91         // top right
92         mSquareCoords[9] = right
93         mSquareCoords[10] = top
94         mSquareCoords[11] = 0f
95 
96         mVertexBuffer.clear()
97         mVertexBuffer.put(mSquareCoords)
98         mVertexBuffer.position(0)
99 
100         GLES20.glUseProgram(mProgram)
101         // get handle to vertex shader's vPosition member
102         mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition")
103         // Enable a handle to the triangle vertices
104         GLES20.glEnableVertexAttribArray(mPositionHandle)
105         // Prepare the triangle coordinate data
106         // 4 bytes per vertex
107         val vertexStride = COORDS_PER_VERTEX * 4
108         GLES20.glVertexAttribPointer(
109             mPositionHandle,
110             COORDS_PER_VERTEX,
111             GLES20.GL_FLOAT,
112             false,
113             vertexStride,
114             mVertexBuffer
115         )
116         // get handle to fragment shader's vColor member
117         mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor")
118         // Set color for drawing the triangle
119         GLES20.glUniform4fv(mColorHandle, 1, mColor, 0)
120         // get handle to shape's transformation matrix
121         mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix")
122         // Apply the projection and view transformation
123         GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0)
124         // Draw the square
125         GLES20.glDrawElements(
126             GLES20.GL_TRIANGLES,
127             DRAW_ORDER.size,
128             GLES20.GL_UNSIGNED_SHORT,
129             mDrawListBuffer
130         )
131         // Disable vertex array
132         GLES20.glDisableVertexAttribArray(mPositionHandle)
133     }
134 
135     companion object {
136         private val vertexShaderCode =
137             """
138                 uniform mat4 uMVPMatrix;
139                 attribute vec4 vPosition;
140                 void main() {
141                   gl_Position = uMVPMatrix * vPosition;
142                 }
143             """
144         private val fragmentShaderCode =
145             """
146                 precision mediump float;
147                 uniform vec4 vColor;
148                 void main() {
149                   gl_FragColor = vColor;
150                 }
151             """
152 
153         // number of coordinates per vertex in this array
154         val COORDS_PER_VERTEX = 3
155         val DRAW_ORDER = shortArrayOf(0, 1, 2, 0, 2, 3) // order to draw vertices
156     }
157 }
158