public class

Texture2dProgram

extends java.lang.Object

 java.lang.Object

↳androidx.heifwriter.Texture2dProgram

Gradle dependencies

compile group: 'androidx.heifwriter', name: 'heifwriter', version: '1.1.0-alpha01'

  • groupId: androidx.heifwriter
  • artifactId: heifwriter
  • version: 1.1.0-alpha01

Artifact androidx.heifwriter:heifwriter:1.1.0-alpha01 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.heifwriter:heifwriter com.android.support:heifwriter

Overview

GL program and supporting functions for textured 2D shapes. (Contains mostly code borrowed from Grafika)

Summary

Fields
public static final float[]IDENTITY_MATRIX

Identity matrix for general use.

public static final intTEXTURE_2D

public static final intTEXTURE_EXT

public static final float[]V_FLIP_MATRIX

Following matrix is for texturing from bitmap.

Constructors
publicTexture2dProgram(int programType)

Prepares the program in the current EGL context.

Methods
public static voidcheckGlError(java.lang.String op)

Checks to see if a GLES error has been raised.

public static voidcheckLocation(int location, java.lang.String label)

Checks to see if the location we obtained is valid.

public static intcreateProgram(java.lang.String vertexSource, java.lang.String fragmentSource)

Creates a new program from the supplied vertex and fragment shaders.

public intcreateTextureObject()

Creates a texture object suitable for use with this program.

public voiddraw(float[] mvpMatrix[], java.nio.FloatBuffer vertexBuffer, int firstVertex, int vertexCount, int coordsPerVertex, int vertexStride, float[] texMatrix[], java.nio.FloatBuffer texBuffer, int textureId, int texStride)

Issues the draw call.

public intgetProgramType()

Returns the program type.

public static intloadShader(int shaderType, java.lang.String source)

Compiles the provided shader source.

public voidloadTexture(int texId, Bitmap bitmap)

Bind texture and load bitmap.

public voidrelease()

Releases the program.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final float[] IDENTITY_MATRIX

Identity matrix for general use. Don't modify or life will get weird.

public static final float[] V_FLIP_MATRIX

Following matrix is for texturing from bitmap. We set up the frame rects to work with SurfaceTexture's texcoords and texmatrix, but then the bitmap texturing must flip it vertically. (Don't modify or life gets weird too.)

public static final int TEXTURE_2D

public static final int TEXTURE_EXT

Constructors

public Texture2dProgram(int programType)

Prepares the program in the current EGL context.

Methods

public void release()

Releases the program.

The appropriate EGL context must be current (i.e. the one that was used to create the program).

public int getProgramType()

Returns the program type.

public int createTextureObject()

Creates a texture object suitable for use with this program.

On exit, the texture will be bound.

public void loadTexture(int texId, Bitmap bitmap)

Bind texture and load bitmap.

Parameters:

texId: texture id for the texture.
bitmap: bitmap to load.

public void draw(float[] mvpMatrix[], java.nio.FloatBuffer vertexBuffer, int firstVertex, int vertexCount, int coordsPerVertex, int vertexStride, float[] texMatrix[], java.nio.FloatBuffer texBuffer, int textureId, int texStride)

Issues the draw call. Does the full setup on every call.

Parameters:

mvpMatrix: The 4x4 projection matrix.
vertexBuffer: Buffer with vertex position data.
firstVertex: Index of first vertex to use in vertexBuffer.
vertexCount: Number of vertices in vertexBuffer.
coordsPerVertex: The number of coordinates per vertex (e.g. x,y is 2).
vertexStride: Width, in bytes, of the position data for each vertex (often vertexCount * sizeof(float)).
texMatrix: A 4x4 transformation matrix for texture coords. (Primarily intended for use with SurfaceTexture.)
texBuffer: Buffer with vertex texture data.
texStride: Width, in bytes, of the texture data for each vertex.

public static int createProgram(java.lang.String vertexSource, java.lang.String fragmentSource)

Creates a new program from the supplied vertex and fragment shaders.

Returns:

A handle to the program, or 0 on failure.

public static int loadShader(int shaderType, java.lang.String source)

Compiles the provided shader source.

Returns:

A handle to the shader, or 0 on failure.

public static void checkLocation(int location, java.lang.String label)

Checks to see if the location we obtained is valid. GLES returns -1 if a label could not be found, but does not set the GL error.

Throws a RuntimeException if the location is invalid.

public static void checkGlError(java.lang.String op)

Checks to see if a GLES error has been raised.

Source

/*
 * Copyright 2018 Google Inc. All rights reserved.
 *
 * 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.
 */

package androidx.heifwriter;

import android.graphics.Bitmap;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.util.Log;

import androidx.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.FloatBuffer;

/**
 * GL program and supporting functions for textured 2D shapes.
 *
 * (Contains mostly code borrowed from Grafika)
 *
 * @hide
 */
public class Texture2dProgram {
    private static final String TAG = "Texture2dProgram";
    private static final boolean DEBUG = false;

    /** Identity matrix for general use. Don't modify or life will get weird. */
    public static final float[] IDENTITY_MATRIX;

    /**
     * Following matrix is for texturing from bitmap. We set up the frame rects
     * to work with SurfaceTexture's texcoords and texmatrix, but then the bitmap
     * texturing must flip it vertically. (Don't modify or life gets weird too.)
     */
    public static final float[] V_FLIP_MATRIX;

    static {
        IDENTITY_MATRIX = new float[16];
        Matrix.setIdentityM(IDENTITY_MATRIX, 0);

        V_FLIP_MATRIX = new float[16];
        Matrix.setIdentityM(V_FLIP_MATRIX, 0);
        Matrix.translateM(V_FLIP_MATRIX, 0, 0.0f, 1.0f, 0.0f);
        Matrix.scaleM(V_FLIP_MATRIX, 0, 1.0f, -1.0f, 1.0f);
    }

    public static final int TEXTURE_2D = 0;
    public static final int TEXTURE_EXT = 1;

    /** @hide */
    @IntDef({
        TEXTURE_2D,
        TEXTURE_EXT,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ProgramType {}

    // Simple vertex shader, used for all programs.
    private static final String VERTEX_SHADER =
            "uniform mat4 uMVPMatrix;\n" +
            "uniform mat4 uTexMatrix;\n" +
            "attribute vec4 aPosition;\n" +
            "attribute vec4 aTextureCoord;\n" +
            "varying vec2 vTextureCoord;\n" +
            "void main() {\n" +
            "    gl_Position = uMVPMatrix * aPosition;\n" +
            "    vTextureCoord = (uTexMatrix * aTextureCoord).xy;\n" +
            "}\n";

    // Simple fragment shader for use with "normal" 2D textures.
    private static final String FRAGMENT_SHADER_2D =
            "precision mediump float;\n" +
            "varying vec2 vTextureCoord;\n" +
            "uniform sampler2D sTexture;\n" +
            "void main() {\n" +
            "    gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
            "}\n";

    // Simple fragment shader for use with external 2D textures (e.g. what we get from
    // SurfaceTexture).
    private static final String FRAGMENT_SHADER_EXT =
            "#extension GL_OES_EGL_image_external : require\n" +
            "precision mediump float;\n" +
            "varying vec2 vTextureCoord;\n" +
            "uniform samplerExternalOES sTexture;\n" +
            "void main() {\n" +
            "    gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
            "}\n";

    private @ProgramType int mProgramType;

    // Handles to the GL program and various components of it.
    private int mProgramHandle;
    private int muMVPMatrixLoc;
    private int muTexMatrixLoc;
    private int maPositionLoc;
    private int maTextureCoordLoc;
    private int mTextureTarget;

    /**
     * Prepares the program in the current EGL context.
     */
    public Texture2dProgram(@ProgramType int programType) {
        mProgramType = programType;

        switch (programType) {
            case TEXTURE_2D:
                mTextureTarget = GLES20.GL_TEXTURE_2D;
                mProgramHandle = createProgram(VERTEX_SHADER, FRAGMENT_SHADER_2D);
                break;
            case TEXTURE_EXT:
                mTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES;
                mProgramHandle = createProgram(VERTEX_SHADER, FRAGMENT_SHADER_EXT);
                break;
            default:
                throw new RuntimeException("Unhandled type " + programType);
        }
        if (mProgramHandle == 0) {
            throw new RuntimeException("Unable to create program");
        }
        if (DEBUG) {
            Log.d(TAG, "Created program " + mProgramHandle + " (" + programType + ")");
        }

        // get locations of attributes and uniforms

        maPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "aPosition");
        checkLocation(maPositionLoc, "aPosition");
        maTextureCoordLoc = GLES20.glGetAttribLocation(mProgramHandle, "aTextureCoord");
        checkLocation(maTextureCoordLoc, "aTextureCoord");
        muMVPMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uMVPMatrix");
        checkLocation(muMVPMatrixLoc, "uMVPMatrix");
        muTexMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uTexMatrix");
        checkLocation(muTexMatrixLoc, "uTexMatrix");
    }

    /**
     * Releases the program.
     * <p>
     * The appropriate EGL context must be current (i.e. the one that was used to create
     * the program).
     */
    public void release() {
        Log.d(TAG, "deleting program " + mProgramHandle);
        GLES20.glDeleteProgram(mProgramHandle);
        mProgramHandle = -1;
    }

    /**
     * Returns the program type.
     */
    public @ProgramType int getProgramType() {
        return mProgramType;
    }

    /**
     * Creates a texture object suitable for use with this program.
     * <p>
     * On exit, the texture will be bound.
     */
    public int createTextureObject() {
        int[] textures = new int[1];
        GLES20.glGenTextures(1, textures, 0);
        checkGlError("glGenTextures");

        int texId = textures[0];
        GLES20.glBindTexture(mTextureTarget, texId);
        checkGlError("glBindTexture " + texId);

        GLES20.glTexParameterf(mTextureTarget, GLES20.GL_TEXTURE_MIN_FILTER,
                GLES20.GL_NEAREST);
        GLES20.glTexParameterf(mTextureTarget, GLES20.GL_TEXTURE_MAG_FILTER,
                (mTextureTarget == GLES20.GL_TEXTURE_2D) ? GLES20.GL_NEAREST : GLES20.GL_LINEAR);
        GLES20.glTexParameteri(mTextureTarget, GLES20.GL_TEXTURE_WRAP_S,
                GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(mTextureTarget, GLES20.GL_TEXTURE_WRAP_T,
                GLES20.GL_CLAMP_TO_EDGE);
        checkGlError("glTexParameter");

        return texId;
    }

    /**
     * Bind texture and load bitmap.
     * @param texId texture id for the texture.
     * @param bitmap bitmap to load.
     */
    public void loadTexture(int texId, Bitmap bitmap) {
        // load the bitmap to texture
        GLES20.glBindTexture(mTextureTarget, texId);
        GLUtils.texImage2D(mTextureTarget, 0, bitmap, 0);
    }

    /**
     * Issues the draw call.  Does the full setup on every call.
     *
     * @param mvpMatrix The 4x4 projection matrix.
     * @param vertexBuffer Buffer with vertex position data.
     * @param firstVertex Index of first vertex to use in vertexBuffer.
     * @param vertexCount Number of vertices in vertexBuffer.
     * @param coordsPerVertex The number of coordinates per vertex (e.g. x,y is 2).
     * @param vertexStride Width, in bytes, of the position data for each vertex (often
     *        vertexCount * sizeof(float)).
     * @param texMatrix A 4x4 transformation matrix for texture coords.  (Primarily intended
     *        for use with SurfaceTexture.)
     * @param texBuffer Buffer with vertex texture data.
     * @param texStride Width, in bytes, of the texture data for each vertex.
     */
    public void draw(float[] mvpMatrix, FloatBuffer vertexBuffer, int firstVertex,
            int vertexCount, int coordsPerVertex, int vertexStride,
            float[] texMatrix, FloatBuffer texBuffer, int textureId, int texStride) {
        checkGlError("draw start");

        // Select the program.
        GLES20.glUseProgram(mProgramHandle);
        checkGlError("glUseProgram");

        // Set the texture.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(mTextureTarget, textureId);

        // Copy the model / view / projection matrix over.
        GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mvpMatrix, 0);
        checkGlError("glUniformMatrix4fv");

        // Copy the texture transformation matrix over.
        GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, texMatrix, 0);
        checkGlError("glUniformMatrix4fv");

        // Enable the "aPosition" vertex attribute.
        GLES20.glEnableVertexAttribArray(maPositionLoc);
        checkGlError("glEnableVertexAttribArray");

        // Connect vertexBuffer to "aPosition".
        GLES20.glVertexAttribPointer(maPositionLoc, coordsPerVertex,
            GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
        checkGlError("glVertexAttribPointer");

        // Enable the "aTextureCoord" vertex attribute.
        GLES20.glEnableVertexAttribArray(maTextureCoordLoc);
        checkGlError("glEnableVertexAttribArray");

        // Connect texBuffer to "aTextureCoord".
        GLES20.glVertexAttribPointer(maTextureCoordLoc, 2,
                GLES20.GL_FLOAT, false, texStride, texBuffer);
            checkGlError("glVertexAttribPointer");

        // Draw the rect.
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, firstVertex, vertexCount);
        checkGlError("glDrawArrays");

        // Done -- disable vertex array, texture, and program.
        GLES20.glDisableVertexAttribArray(maPositionLoc);
        GLES20.glDisableVertexAttribArray(maTextureCoordLoc);
        GLES20.glBindTexture(mTextureTarget, 0);
        GLES20.glUseProgram(0);
    }

    /**
     * Creates a new program from the supplied vertex and fragment shaders.
     *
     * @return A handle to the program, or 0 on failure.
     */
    public static int createProgram(String vertexSource, String fragmentSource) {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            return 0;
        }
        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0) {
            return 0;
        }

        int program = GLES20.glCreateProgram();
        checkGlError("glCreateProgram");
        if (program == 0) {
            Log.e(TAG, "Could not create program");
        }
        GLES20.glAttachShader(program, vertexShader);
        checkGlError("glAttachShader");
        GLES20.glAttachShader(program, pixelShader);
        checkGlError("glAttachShader");
        GLES20.glLinkProgram(program);
        int[] linkStatus = new int[1];
        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
        if (linkStatus[0] != GLES20.GL_TRUE) {
            Log.e(TAG, "Could not link program: ");
            Log.e(TAG, GLES20.glGetProgramInfoLog(program));
            GLES20.glDeleteProgram(program);
            program = 0;
        }
        return program;
    }

    /**
     * Compiles the provided shader source.
     *
     * @return A handle to the shader, or 0 on failure.
     */
    public static int loadShader(int shaderType, String source) {
        int shader = GLES20.glCreateShader(shaderType);
        checkGlError("glCreateShader type=" + shaderType);
        GLES20.glShaderSource(shader, source);
        GLES20.glCompileShader(shader);
        int[] compiled = new int[1];
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            Log.e(TAG, "Could not compile shader " + shaderType + ":");
            Log.e(TAG, " " + GLES20.glGetShaderInfoLog(shader));
            GLES20.glDeleteShader(shader);
            shader = 0;
        }
        return shader;
    }

    /**
     * Checks to see if the location we obtained is valid.  GLES returns -1 if a label
     * could not be found, but does not set the GL error.
     * <p>
     * Throws a RuntimeException if the location is invalid.
     */
    public static void checkLocation(int location, String label) {
        if (location < 0) {
            throw new RuntimeException("Unable to locate '" + label + "' in program");
        }
    }

    /**
     * Checks to see if a GLES error has been raised.
     */
    public static void checkGlError(String op) {
        int error = GLES20.glGetError();
        if (error == GLES20.GL_OUT_OF_MEMORY) {
            Log.i(TAG, op + " GL_OUT_OF_MEMORY");
        }
        if (error != GLES20.GL_NO_ERROR && error != GLES20.GL_OUT_OF_MEMORY) {
            String msg = op + ": glError 0x" + Integer.toHexString(error);
            Log.e(TAG, msg);
            throw new RuntimeException(msg);
        }
    }
}