1/*
2 * Copyright 2018 Google Inc. All rights reserved.
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
17package androidx.heifwriter;
18
19import android.graphics.Rect;
20
21import java.nio.ByteBuffer;
22import java.nio.ByteOrder;
23import java.nio.FloatBuffer;
24
25/**
26 * This class represents a viewport-sized sprite that will be rendered with
27 * a subrect from a texture.
28 *
29 * @hide
30 */
31public class EglRectBlt {
32    private static final int SIZEOF_FLOAT = 4;
33
34    /**
35     * A "full" square, extending from -1 to +1 in both dimensions. When the
36     * model/view/projection matrix is identity, this will exactly cover the viewport.
37     */
38    private static final float FULL_RECTANGLE_COORDS[] = {
39            -1.0f, -1.0f,   // 0 bottom left
40             1.0f, -1.0f,   // 1 bottom right
41            -1.0f,  1.0f,   // 2 top left
42             1.0f,  1.0f,   // 3 top right
43    };
44
45    private static final FloatBuffer FULL_RECTANGLE_BUF =
46            createFloatBuffer(FULL_RECTANGLE_COORDS);
47
48    private final float mTexCoords[] = new float[8];
49    private final FloatBuffer mTexCoordArray = createFloatBuffer(mTexCoords);
50    private final int mTexWidth;
51    private final int mTexHeight;
52
53    private Texture2dProgram mProgram;
54
55    /**
56     * Allocates a direct float buffer, and populates it with the float array data.
57     */
58    public static FloatBuffer createFloatBuffer(float[] coords) {
59        // Allocate a direct ByteBuffer, using 4 bytes per float, and copy coords into it.
60        ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * SIZEOF_FLOAT);
61        bb.order(ByteOrder.nativeOrder());
62        FloatBuffer fb = bb.asFloatBuffer();
63        fb.put(coords);
64        fb.position(0);
65        return fb;
66    }
67
68    /**
69     * Prepares the object.
70     *
71     * @param program The program to use. EglRectBlitter takes ownership, and will release
72     *     the program when no longer needed.
73     */
74    public EglRectBlt(Texture2dProgram program, int texWidth, int texHeight) {
75        mProgram = program;
76
77        mTexWidth = texWidth;
78        mTexHeight = texHeight;
79    }
80
81    /**
82     * Releases resources.
83     * <p>
84     * This must be called with the appropriate EGL context current (i.e. the one that was
85     * current when the constructor was called). If we're about to destroy the EGL context,
86     * there's no value in having the caller make it current just to do this cleanup, so you
87     * can pass a flag that will tell this function to skip any EGL-context-specific cleanup.
88     */
89    public void release(boolean doEglCleanup) {
90        if (mProgram != null) {
91            if (doEglCleanup) {
92                mProgram.release();
93            }
94            mProgram = null;
95        }
96    }
97
98    /**
99     * Creates a texture object suitable for use with drawFrame().
100     */
101    public int createTextureObject() {
102        return mProgram.createTextureObject();
103    }
104
105    /**
106     * Draws a viewport-filling rect, texturing it with the specified texture object and rect.
107     */
108    public void copyRect(int textureId, float[] texMatrix, Rect texRect) {
109        setTexRect(texRect);
110
111        // Use the identity matrix for MVP so our 2x2 FULL_RECTANGLE covers the viewport.
112        mProgram.draw(Texture2dProgram.IDENTITY_MATRIX, FULL_RECTANGLE_BUF, 0,
113                4, 2, 2 * SIZEOF_FLOAT,
114                texMatrix, mTexCoordArray, textureId, 2 * SIZEOF_FLOAT);
115    }
116
117    void setTexRect(Rect rect) {
118        mTexCoords[0] = rect.left / (float)mTexWidth;
119        mTexCoords[1] = 1.0f - rect.bottom / (float)mTexHeight;
120        mTexCoords[2] = rect.right / (float)mTexWidth;
121        mTexCoords[3] = 1.0f - rect.bottom / (float)mTexHeight;
122        mTexCoords[4] = rect.left / (float)mTexWidth;
123        mTexCoords[5] = 1.0f - rect.top / (float)mTexHeight;
124        mTexCoords[6] = rect.right / (float)mTexWidth;
125        mTexCoords[7] = 1.0f - rect.top / (float)mTexHeight;
126
127        mTexCoordArray.put(mTexCoords);
128        mTexCoordArray.position(0);
129    }
130}
131