Related
If i change the background of GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f) and then try to draw a texture, colors of this last changes unexpectedly. This is the png file:
The result of the application when i try simply to display it is this one:
Im using this code:
public class GLRenderer implements GLSurfaceView.Renderer {
private static final String TAG = "MyGLRenderer";
private float[] vertices = {
-1f, -1f,
1f, -1f,
-1f, 1f,
1f, 1f
};
private float[] textureVertices = {
0f, 1f,
1f, 1f,
0f, 0f,
1f, 0f
};
private final String vertexShaderCode =
"attribute vec4 aPosition;" +
"attribute vec2 aTexPosition;" +
"varying vec2 vTexPosition;" +
"void main() {" +
" gl_Position = aPosition;" +
" vTexPosition = aTexPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D uTexture;" +
"varying vec2 vTexPosition;" +
"void main() {\n" +
"vec4 color = texture2D(uTexture, vTexPosition);\n"+
//"if(color.r == 0.0 && color.g == 0.0 && color.b == 0.0)\n"+
// "color = vec4(1.0,0.5,0.5,1.0);"+
// "discard;"+
" gl_FragColor = color;" +
"}";
private FloatBuffer verticesBuffer;
private FloatBuffer textureBuffer;
private int vertexShader;
private int fragmentShader;
private int program;
private Bitmap bmp;
private int textures[] = new int[2];
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
public GLRenderer() {
bmp=Bitmap.createBitmap(513,912, Bitmap.Config.ARGB_8888);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
checkGlError("glClearColor");
setup();
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
#Override
public void onDrawFrame(GL10 gl) {
Log.d("Drawing_Frame","Working");
float[] scratch = new float[16];
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// Draw Bitmap
drawBinaryImage(bmp,textures[0]);
Matrix.setRotateM(mRotationMatrix, 0, 0, 0, 0, 1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
}
private void setup(){
GLES20.glGenTextures(2, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
//GLES20.glBindTexture(GL);
initializeBuffers();
initializeProgram();
}
private void initializeBuffers() {
ByteBuffer buff = ByteBuffer.allocateDirect(vertices.length * 4);
buff.order(ByteOrder.nativeOrder());
verticesBuffer = buff.asFloatBuffer();
verticesBuffer.put(vertices);
verticesBuffer.position(0);
buff = ByteBuffer.allocateDirect(textureVertices.length * 4);
buff.order(ByteOrder.nativeOrder());
textureBuffer = buff.asFloatBuffer();
textureBuffer.put(textureVertices);
textureBuffer.position(0);
}
private void initializeProgram() {
vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glGetShaderInfoLog(vertexShader);
checkGlError("glCreateShader");
GLES20.glShaderSource(vertexShader, vertexShaderCode);
GLES20.glCompileShader(vertexShader);
fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmentShader, fragmentShaderCode);
GLES20.glCompileShader(fragmentShader);
program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
checkGlError("glLinkProgram");
}
public void updateTexture(Bitmap bmp){
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
}
private void drawBinaryImage(Bitmap bmp,int texture){
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glUseProgram(program);
//Changes Here original Line GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);
int positionHandle = GLES20.glGetAttribLocation(program, "aPosition");
int textureHandle = GLES20.glGetUniformLocation(program, "uTexture");
int texturePositionHandle = GLES20.glGetAttribLocation(program, "aTexPosition");
//Log.d("GL_SETUP",positionHandle+" , "+textureHandle);
GLES20.glVertexAttribPointer(texturePositionHandle, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
GLES20.glEnableVertexAttribArray(texturePositionHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
Log.d("FILTER_APPLY","Applying");
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
GLES20.glUniform1i(textureHandle, 0);
GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, verticesBuffer);
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
checkGlError("glDrawArrays");
}
public void setBitmap(Bitmap bitmap){
updateTexture(bitmap);
this.bmp = bitmap;
}
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e(TAG, glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
}
The framebuffer is cleared by GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f);.
RGBA(1, 1, 0, 1) is yellow. This causes that before rendering the texture, the entire framebuffer is filled in yellow.
The texture contains a blue color RGBA(0, 0, 1, 1) and a black color RGBA(0, 0, 0, 1).
When the quad with the texture is drawn, then blending is enabled with the following function:
(see Blending and glBlendFunc)
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);
At blending the current color of the framebuffer is mixed by the actually drawn color. With the above setup this done by the following function:
destinationColor = sourceColor * 1 + destinationColor * 1
In the regions where the texture is blue, the final color becomes white:
(1, 1, 0) * 1 + (0, 0, 1) * 1 = (1, 1, 1)
In the regions where the texture is black, the color in the framebuffer stays yellow:
(1, 1, 0) * 1 + (0, 0, 0) * 1 = (1, 1, 0)
I need to draw a shape in OpenGL from a binary image. For example, I have this image binary
and I need to draw this shape in OpenGL. The fact is that I need to do this "dynamically" so I will have for example a different binary image every second and I need to draw the shapes from every one of those images. Shapes will not be the only triangles like in the example image. I will use this in Android Studio.
Convert this image to Bitmap object and draw it on the GLSurfaceView. you can check condition in shader code like this.
vec4 color = texture2D(uTexture, vTexPosition);
if(color.r == 0.0 && color.g == 0.0 && color.b == 0.0)
color = vec4(1.0,0.5,0.5,1.0);
gl_FragColor = color;
This is the full GLRenderer
public class GLRenderer implements GLSurfaceView.Renderer {
private static final String TAG = "MyGLRenderer";
private float[] vertices = {
-1f, -1f,
1f, -1f,
-1f, 1f,
1f, 1f
};
private float[] textureVertices = {
0f, 1f,
1f, 1f,
0f, 0f,
1f, 0f
};
private final String vertexShaderCode =
"attribute vec4 aPosition;" +
"attribute vec2 aTexPosition;" +
"varying vec2 vTexPosition;" +
"void main() {" +
" gl_Position = aPosition;" +
" vTexPosition = aTexPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D uTexture;" +
"varying vec2 vTexPosition;" +
"void main() {\n" +
"vec4 color = texture2D(uTexture, vTexPosition);\n"+
"if(color.r == 0.0 && color.g == 0.0 && color.b == 0.0)\n"+
"color = vec4(1.0,0.5,0.5,1.0);"+
" gl_FragColor = color;" +
"}";
private FloatBuffer verticesBuffer;
private FloatBuffer textureBuffer;
private int vertexShader;
private int fragmentShader;
private int program;
private Bitmap bmp;
private int textures[] = new int[2];
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
public GLRenderer() {
bmp=Bitmap.createBitmap(513,912, Bitmap.Config.ARGB_8888);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
checkGlError("glClearColor");
setup();
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
#Override
public void onDrawFrame(GL10 gl) {
Log.d("Drawing_Frame","Working");
float[] scratch = new float[16];
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// Draw Bitmap
drawBinaryImage(bmp,textures[0]);
Matrix.setRotateM(mRotationMatrix, 0, 0, 0, 0, 1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
}
private void setup(){
GLES20.glGenTextures(2, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
//GLES20.glBindTexture(GL);
initializeBuffers();
initializeProgram();
}
private void initializeBuffers() {
ByteBuffer buff = ByteBuffer.allocateDirect(vertices.length * 4);
buff.order(ByteOrder.nativeOrder());
verticesBuffer = buff.asFloatBuffer();
verticesBuffer.put(vertices);
verticesBuffer.position(0);
buff = ByteBuffer.allocateDirect(textureVertices.length * 4);
buff.order(ByteOrder.nativeOrder());
textureBuffer = buff.asFloatBuffer();
textureBuffer.put(textureVertices);
textureBuffer.position(0);
}
private void initializeProgram() {
vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glGetShaderInfoLog(vertexShader);
checkGlError("glCreateShader");
GLES20.glShaderSource(vertexShader, vertexShaderCode);
GLES20.glCompileShader(vertexShader);
fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmentShader, fragmentShaderCode);
GLES20.glCompileShader(fragmentShader);
program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
checkGlError("glLinkProgram");
}
public void updateTexture(Bitmap bmp){
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
}
private void drawBinaryImage(Bitmap bmp,int texture){
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glUseProgram(program);
//Changes Here original Line GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);
int positionHandle = GLES20.glGetAttribLocation(program, "aPosition");
int textureHandle = GLES20.glGetUniformLocation(program, "uTexture");
int texturePositionHandle = GLES20.glGetAttribLocation(program, "aTexPosition");
//Log.d("GL_SETUP",positionHandle+" , "+textureHandle);
GLES20.glVertexAttribPointer(texturePositionHandle, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
GLES20.glEnableVertexAttribArray(texturePositionHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
Log.d("FILTER_APPLY","Applying");
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
GLES20.glUniform1i(textureHandle, 0);
GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, verticesBuffer);
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
checkGlError("glDrawArrays");
}
public void setBitmap(Bitmap bitmap){
updateTexture(bitmap);
this.bmp = bitmap;
}
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e(TAG, glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
}
Use this renderer with GlSurfaceView
Here is main Activity class
public class MainActivity extends AppCompatActivity {
FrameLayout glView;
private GLRenderer renderer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
glView = findViewById(R.id.glview);
setupGL();
}
private void setupGL(){
renderer = new GLRenderer();
//MyGlSurfaceView glSurfaceView = new MyGlSurfaceView(this,renderer);
GLSurfaceView glSurfaceView = new GLSurfaceView(this);
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setRenderer(renderer);
glView.addView(glSurfaceView);
produceFrame();
}
private void produceFrame(){
Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.sample);
renderer.setBitmap(bmp);
}
You can check this for complete project.
I try to display a texture on OpenGLES 3.0 but I can see any image from it.
The GLRenderer is :
public class CameraGLRenderer implements GLSurfaceView.Renderer{
public static final String TAG = "com.example.CameraGLRenderer";
private CameraImage mCameraImage;
public CameraGLRenderer(int width, int heigh) {
mCameraImage = new CameraImage(width,heigh);
}
#Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
// Set the background frame color
GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
#Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
// Adjust the viewport based on geometry changes,
// such as screen rotation
GLES30.glActiveTexture(GLES30.GL_ACTIVE_TEXTURE);
GLES30.glViewport(0, 0, width, height);
// float ratio = (float) width / height;
//
// // this projection matrix is applied to object coordinates
// // in the onDrawFrame() method
// Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
#Override
public void onDrawFrame(GL10 gl10) {
mCameraImage.draw();
}
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES30.GL_VERTEX_SHADER)
// or a fragment shader type (GLES30.GL_FRAGMENT_SHADER)
int shader = GLES30.glCreateShader(type);
// add the source code to the shader and compile it
GLES30.glShaderSource(shader, shaderCode);
GLES30.glCompileShader(shader);
return shader;
}
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES30.glGetError()) != GLES30.GL_NO_ERROR) {
Log.e(TAG, glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
public void onPreviewFrame(byte[] data) {
mCameraImage.onPreviewFrame(data);
}
}
And my camera image class:
public CameraImage(int width,int height) {
Log.d(TAG,"CameraImage constructor");
mWidth = width;
mHeight = height;
U_INDEX = width*height;
V_INDEX = width*height*5/4;
LENGTH = width*height;
LENGTH_4 = width*height/4;
yData = new byte[LENGTH];
uData = new byte[LENGTH_4];
vData = new byte[LENGTH_4];
yBuffer = ByteBuffer.allocate(LENGTH);
uBuffer = ByteBuffer.allocate(LENGTH_4);
vBuffer = ByteBuffer.allocate(LENGTH_4);
mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertices.put(mVerticesData).position(0);
mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2)
.order(ByteOrder.nativeOrder()).asShortBuffer();
mIndices.put(mIndicesData).position(0);
// prepare shaders and OpenGL program
int vertexShader = CameraGLRenderer.loadShader(
GLES30.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = CameraGLRenderer.loadShader(
GLES30.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES30.glCreateProgram(); // create empty OpenGL Program
GLES30.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
CameraGLRenderer.checkGlError("glAttachShader");
GLES30.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
CameraGLRenderer.checkGlError("glAttachShader");
GLES30.glLinkProgram(mProgram); // create OpenGL program executables
CameraGLRenderer.checkGlError("glLinkProgram");
// Get the attribute locations
mPositionLoc = GLES30.glGetAttribLocation(mProgram, "a_position");
CameraGLRenderer.checkGlError("glGetAttribLocation");
mTexCoordLoc = GLES30.glGetAttribLocation(mProgram, "a_texCoord");
CameraGLRenderer.checkGlError("glGetAttribLocation");
GLES30.glEnable(GLES30.GL_TEXTURE_2D);
CameraGLRenderer.checkGlError("glEnable");
yTexture = GLES30.glGetUniformLocation(mProgram, "y_texture");
CameraGLRenderer.checkGlError("glGetUniformLocation");
yTextureNames = new int[1];
GLES30.glGenTextures(1, yTextureNames, 0);
CameraGLRenderer.checkGlError("glGenTextures");
int yTextureName = yTextureNames[0];
GLES30.glActiveTexture(GLES30.GL_TEXTURE1);
CameraGLRenderer.checkGlError("glActiveTexture");
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, yTextureName);
CameraGLRenderer.checkGlError("glBindTexture");
GLES30.glEnable(GLES30.GL_TEXTURE_2D);
CameraGLRenderer.checkGlError("glEnable");
uTexture = GLES30.glGetUniformLocation(mProgram, "u_texture");
CameraGLRenderer.checkGlError("glGetUniformLocation");
uTextureNames = new int[1];
GLES30.glGenTextures(1, uTextureNames, 0);
CameraGLRenderer.checkGlError("glGenTextures");
int uTextureName = uTextureNames[0];
GLES30.glActiveTexture(GLES30.GL_TEXTURE2);
CameraGLRenderer.checkGlError("glActiveTexture");
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, uTextureName);
CameraGLRenderer.checkGlError("glBindTexture");
GLES30.glEnable(GLES30.GL_TEXTURE_2D);
CameraGLRenderer.checkGlError("glBindTexture");
vTexture = GLES30.glGetUniformLocation(mProgram, "v_texture");
CameraGLRenderer.checkGlError("glGetUniformLocation");
vTextureNames = new int[1];
GLES30.glGenTextures(1, vTextureNames, 0);
CameraGLRenderer.checkGlError("glGenTextures");
int vTextureName = vTextureNames[0];
GLES30.glActiveTexture(GLES30.GL_TEXTURE2);
CameraGLRenderer.checkGlError("glActiveTexture");
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, vTextureName);
CameraGLRenderer.checkGlError("glBindTexture");
//
//
// // Set the background clear color to black.
GLES30.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
CameraGLRenderer.checkGlError("glClearColor");
}
public void draw() {
Log.d(TAG, "Draw");
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
CameraGLRenderer.checkGlError("glClear"); ///ERROR !!!!
// Add program to OpenGL environment
GLES30.glUseProgram(mProgram);
CameraGLRenderer.checkGlError("glUseProgram");
// Load the vertex position
mVertices.position(0);
GLES30.glVertexAttribPointer(mPositionLoc, 3, GLES30.GL_FLOAT, false, 5*4, mVertices);
// Load the texture coordinate
mVertices.position(3);
GLES30.glVertexAttribPointer(mTexCoordLoc, 2, GLES30.GL_FLOAT, false, 5*4, mVertices);
// Enable a handle to the triangle vertices
GLES30.glEnableVertexAttribArray(mPositionLoc);
GLES30.glEnableVertexAttribArray(mTexCoordLoc);
CameraGLRenderer.checkGlError("glEnableVertexAttribArray");
CameraGLRenderer.checkGlError("glEnableVertexAttribArray");
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, yTextureNames[0]);
GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE,
1920, 1080, 0, GLES30.GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, yBuffer);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glActiveTexture(GLES30.GL_TEXTURE1+1);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, yTextureNames[0]);
GLES30.glUniform1i(yTexture, 1);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, uTextureNames[0]);
GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE,
960, 540, 0, GLES30.GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, uBuffer);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glActiveTexture(GLES30.GL_TEXTURE1+2);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, uTextureNames[0]);
GLES30.glUniform1i(uTexture, 2);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, vTextureNames[0]);
GLES30.glTexImage2D( GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE,
960, 540, 0, GLES30.GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, vBuffer);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glActiveTexture(GLES30.GL_TEXTURE1+3);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, vTextureNames[0]);
GLES30.glUniform1i(vTexture, 3);
// Draw the square
GLES30.glDrawElements(
GLES30.GL_TRIANGLES, mIndicesData.length,
GLES30.GL_UNSIGNED_SHORT, mVertices);
}
public void onPreviewFrame(byte[] data) {
System.arraycopy(data, 0, yData, 0, LENGTH);
yBuffer.put(yData);
yBuffer.position(0);
System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4);
uBuffer.put(uData);
uBuffer.position(0);
System.arraycopy(data, V_INDEX, vData, 0, LENGTH_4);
vBuffer.put(vData);
vBuffer.position(0);
}
}
The program goes through the draw function of the CameraImage class but the image is still black.
According to the fragmentShaderCode the image should be red but the image are still black.
The program doesn't seem to execute the shader.
Edit:
I modify the code according to message you send me. I also add glerror analyse.
I get an error on that line :
Log.d(TAG, "Draw");
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
CameraGLRenderer.checkGlError("glClear"); ///ERROR !!!!
This is the error I get:
08-21 07:12:03.644 6604-6622/com.example E/AndroidRuntime: FATAL EXCEPTION: GLThread 426
Process: com.example, PID: 6604
java.lang.RuntimeException: glClear: glError 1282
at com.example.CameraGLRenderer.checkGlError(CameraGLRenderer.java:90)
Edit2:
I mixe the CameraGLRenderer and the CameraImage into one Class MyRenderer I found on stackoverflow:
public class MyRenderer implements GLSurfaceView.Renderer {
public static final int recWidth = 1920;
public static final int recHeight = 1080;
private static final int U_INDEX = recWidth * recHeight;
private static final int V_INDEX = recWidth * recHeight * 5 / 4;
private static final int LENGTH = recWidth * recHeight;
private static final int LENGTH_4 = recWidth * recHeight / 4;
private int previewFrameWidth = 1920;
private int previewFrameHeight = 1080;
private int[] yTextureNames;
private int[] uTextureNames;
private int[] vTextureNames;
private FloatBuffer mVertices;
private ShortBuffer mIndices;
private int mProgramObject;
private int mPositionLoc;
private int mTexCoordLoc;
private int yTexture;
private int uTexture;
private int vTexture;
private final float[] mVerticesData = {-1.f, 1.f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-1.f, -1.f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
1.f, -1.f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
1.f, 1.f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
private final short[] mIndicesData = {0, 1, 2, 0, 2, 3};
private ByteBuffer yBuffer;
private ByteBuffer uBuffer;
private ByteBuffer vBuffer;
private IntBuffer frameBuffer;
private IntBuffer renderBuffer;
private IntBuffer parameterBufferWidth;
private IntBuffer parameterBufferHeigth;
byte[] ydata = new byte[LENGTH];
byte[] uData = new byte[LENGTH_4];
byte[] vData = new byte[LENGTH_4];
public MyRenderer() {
mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertices.put(mVerticesData).position(0);
mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2)
.order(ByteOrder.nativeOrder()).asShortBuffer();
mIndices.put(mIndicesData).position(0);
yBuffer = ByteBuffer.allocateDirect(LENGTH);//MyGraphUtils.makeByteBuffer(LENGTH);
uBuffer = ByteBuffer.allocateDirect(LENGTH_4);//MyGraphUtils.makeByteBuffer(LENGTH_4/* * 2*/);
vBuffer = ByteBuffer.allocateDirect(LENGTH_4);//MyGraphUtils.makeByteBuffer(LENGTH_4);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glActiveTexture(GLES20.GL_ACTIVE_TEXTURE);
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onSurfaceCreated(GL10 gl10, javax.microedition.khronos.egl.EGLConfig eglConfig) {
// public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.d("debug", "on surface created");
// Define a simple shader program for our point.
// final String vShaderStr = readTextFileFromRawResource(activity, R.raw.v_simple);
// final String fShaderStr = readTextFileFromRawResource(activity, R.raw.f_convert);
//Our vertex shader code; nothing special
String vShaderStr =
"attribute vec4 a_position; \n" +
"attribute vec2 a_texCoord; \n" +
"varying vec2 v_texCoord; \n" +
"void main(){ \n" +
" gl_Position = a_position; \n" +
" v_texCoord = a_texCoord; \n" +
"} \n";
//Our fragment shader code; takes Y,U,V values for each pixel and calculates R,G,B colors,
//Effectively making YUV to RGB conversion
String fShaderStr =
"#ifdef GL_ES \n" +
"precision highp float; \n" +
"#endif \n" +
"varying vec2 v_texCoord; \n" +
"uniform sampler2D y_texture; \n" +
"uniform sampler2D u_texture; \n" +
"uniform sampler2D v_texture; \n" +
//
"void main (void){ \n" +
" float r, g, b, y, u, v; \n" +
//We had put the Y values of each pixel to the R,G,B components by GL_LUMINANCE,
// //that's why we're pulling it from the R component, we could also use G or B
" y = texture2D(y_texture, v_texCoord).r; \n" +
//We had put the U and V values of each pixel to the A and R,G,B components of the
//texture respectively using GL_LUMINANCE_ALPHA. Since U,V bytes are interspread
//in the texture, this is probably the fastest way to use them in the shader
" u = texture2D(u_texture, v_texCoord).a - 0.5; \n" +
" v = texture2D(v_texture, v_texCoord).r - 0.5; \n" +
//The numbers are just YUV to RGB conversion constants
" r = y + 1.13983*v;\n" +
" g = y - 0.39465*u - 0.58060*v;\n" +
" b = y + 2.03211*u;\n" +
//We finally set the RGB color of our pixel
" gl_FragColor = vec4(r, g, b, 1.0);\n" +
"} \n";
frameBuffer = IntBuffer.allocate(1);
renderBuffer = IntBuffer.allocate(1);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
GLES20.glGenFramebuffers(1, frameBuffer);
GLES20.glGenRenderbuffers(1, renderBuffer);
GLES20.glActiveTexture(GLES20.GL_ACTIVE_TEXTURE);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer.get(0));
GLES20.glClear(0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBuffer.get(0));
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,
1920, 1080);
parameterBufferHeigth = IntBuffer.allocate(1);
parameterBufferWidth = IntBuffer.allocate(1);
GLES20.glGetRenderbufferParameteriv(GLES20.GL_RENDERBUFFER, GLES20.GL_RENDERBUFFER_WIDTH, parameterBufferWidth);
GLES20.glGetRenderbufferParameteriv(GLES20.GL_RENDERBUFFER, GLES20.GL_RENDERBUFFER_HEIGHT, parameterBufferHeigth);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER, renderBuffer.get(0));
if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE) {
Log.d("debug", "gl frame buffer status != frame buffer complete");
}
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glClear(0);
mProgramObject = loadProgram(vShaderStr, fShaderStr);
// Get the attribute locations
mPositionLoc = GLES20.glGetAttribLocation(mProgramObject, "a_position");
mTexCoordLoc = GLES20.glGetAttribLocation(mProgramObject, "a_texCoord");
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
yTexture = GLES20.glGetUniformLocation(mProgramObject, "y_texture");
yTextureNames = new int[1];
GLES20.glGenTextures(1, yTextureNames, 0);
int yTextureName = yTextureNames[0];
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
uTexture = GLES20.glGetUniformLocation(mProgramObject, "u_texture");
uTextureNames = new int[1];
GLES20.glGenTextures(1, uTextureNames, 0);
int uTextureName = uTextureNames[0];
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
vTexture = GLES20.glGetUniformLocation(mProgramObject, "v_texture");
vTextureNames = new int[1];
GLES20.glGenTextures(1, vTextureNames, 0);
int vTextureName = vTextureNames[0];
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
}
#Override
public final void onDrawFrame(GL10 gl) {
Log.d("debug", "on Draw frame");
// Clear the color buffer
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Use the program object
GLES20.glUseProgram(mProgramObject);
CameraGLRenderer.checkGlError("toto");
// Load the vertex position
mVertices.position(0);
GLES20.glVertexAttribPointer(mPositionLoc, 3, GLES20.GL_FLOAT, false, 5 * 4, mVertices);
// Load the texture coordinate
mVertices.position(3);
GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 5 * 4, mVertices);
CameraGLRenderer.checkGlError("toto");
GLES20.glEnableVertexAttribArray(mPositionLoc);
GLES20.glEnableVertexAttribArray(mTexCoordLoc);
CameraGLRenderer.checkGlError("toto");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureNames[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
1920, 1080, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureNames[0]);
GLES20.glUniform1i(yTexture, 0);
CameraGLRenderer.checkGlError("toto");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureNames[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
960, 540, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, uBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1 + 2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureNames[0]);
GLES20.glUniform1i(uTexture, 2);
CameraGLRenderer.checkGlError("toto");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, vTextureNames[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
960, 540, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, vBuffer);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1 + 1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, vTextureNames[0]);
GLES20.glUniform1i(vTexture, 1);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);
CameraGLRenderer.checkGlError("toto");
}
public void setPreviewFrameSize(int realWidth, int realHeight) {
previewFrameHeight = realHeight;
previewFrameWidth = realWidth;
}
// public static String readTextFileFromRawResource(final Context context, final int resourceId) {
// final InputStream inputStream = context.getResources().openRawResource(resourceId);
// final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
// final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//
// String nextLine;
// final StringBuilder body = new StringBuilder();
//
// try {
// while ((nextLine = bufferedReader.readLine()) != null) {
// body.append(nextLine);
// body.append('\n');
// }
// } catch (IOException e) {
// return null;
// }
//
// return body.toString();
// }
public static int loadShader(int type, String shaderSrc) {
int shader;
int[] compiled = new int[1];
// Create the shader object
shader = GLES20.glCreateShader(type);
if (shader == 0) {
return 0;
}
// Load the shader source
GLES20.glShaderSource(shader, shaderSrc);
// Compile the shader
GLES20.glCompileShader(shader);
// Check the compile status
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e("ESShader", GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
return 0;
}
return shader;
}
public static int loadProgram(String vertShaderSrc, String fragShaderSrc) {
int vertexShader;
int fragmentShader;
int programObject;
int[] linked = new int[1];
// Load the vertex/fragment shaders
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertShaderSrc);
if (vertexShader == 0) {
return 0;
}
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragShaderSrc);
if (fragmentShader == 0) {
GLES20.glDeleteShader(vertexShader);
return 0;
}
// Create the program object
programObject = GLES20.glCreateProgram();
if (programObject == 0) {
return 0;
}
GLES20.glAttachShader(programObject, vertexShader);
GLES20.glAttachShader(programObject, fragmentShader);
// Link the program
GLES20.glLinkProgram(programObject);
// Check the link status
GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0);
if (linked[0] == 0) {
Log.e("ESShader", "Error linking program:");
Log.e("ESShader", GLES20.glGetProgramInfoLog(programObject));
GLES20.glDeleteProgram(programObject);
return 0;
}
// Free up no longer needed shader resources
GLES20.glDeleteShader(vertexShader);
GLES20.glDeleteShader(fragmentShader);
return programObject;
}
public void onPreviewFrame(byte[] data) {
System.arraycopy(data, 0, ydata, 0, LENGTH);
yBuffer.put(ydata);
yBuffer.position(0);
System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4);
uBuffer.put(uData);
uBuffer.position(0);
System.arraycopy(data, V_INDEX, vData, 0, LENGTH_4);
vBuffer.put(vData);
vBuffer.position(0);
}
}
Now it draws one frame and then I get a glerror on the second draw :
glError 1280
I want to make customized watermark renderer on Android.
I am going to add watermark at bottom right corner above current camera preview screen.
Here is the source code what I made. this code does not work.
Please help me. Thank you.
Function call sequence is :
-setWatermarkTexture
-createBuffers
-configureOpenGL
-draw
public class WatermarkRenderer implements Renderer {
private int[] textureHandles = new int[1];
float vertices[] = {
-1, 0.5f,
-0.5f, -0.5f,
-1, 1,
-0.5f, 1,
};
float texCoords[] = {
0, 0,
1, 0,
0, 1,
1, 1,
};
private Bitmap watermark;
private int[] buffers = new int[2];
private float[] projectionMatrix = new float[16];
private FloatBuffer vertexBuffer;
private FloatBuffer textureBuffer;
#Override
public void configureOpenGL() {
GLES20.glGenTextures(textureHandles.length, textureHandles, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glGenBuffers(buffers.length, buffers, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 8, vertexBuffer, GLES20.GL_STATIC_DRAW );
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 8, textureBuffer, GLES20.GL_STATIC_DRAW );
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
}
#Override
public void createBuffers() {
vertexBuffer = FloatBuffer.allocate(8);
vertexBuffer.put(vertices);
vertexBuffer.position(0);
textureBuffer = FloatBuffer.allocate(8);
textureBuffer.put(texCoords);
textureBuffer.position(0);
}
#Override
public void draw() {
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
//GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
//GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA );
if (watermark != null) {
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, watermark, 0);
watermark.recycle();
watermark = null;
}
/*
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glEnableVertexAttribArray(AttributeLocations.POSITION);
GLES20.glVertexAttribPointer(AttributeLocations.POSITION, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glEnableVertexAttribArray(AttributeLocations.TEXTURE_COORDINATES );
GLES20.glVertexAttribPointer(AttributeLocations.TEXTURE_COORDINATES, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4 );
GLES20.glDisableVertexAttribArray(AttributeLocations.POSITION);
GLES20.glDisableVertexAttribArray(AttributeLocations.TEXTURE_COORDINATES);
*/
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
}
#Override
public void setProjectionMatrix(float[] projectionMatrix) {
this.projectionMatrix = projectionMatrix;
}
public void setWatermarkTexture(Bitmap bitmap) {
watermark = bitmap;
}
}
I solved my issue.
Here is the source code.
public class WatermarkRenderer implements Renderer {
private final float[] TEX_VERTICES = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
private final float[] POS_VERTICES = {
0.2f, -1.0f,
1.0f, -1.0f,
0.2f, -0.9f,
1.0f, -0.9f
};
private static final String VERTEX_SHADER =
"attribute vec4 a_position;\n" +
"attribute vec2 a_texcoord;\n" +
"varying vec2 v_texcoord;\n" +
"void main() {\n" +
" gl_Position = a_position;\n" +
" v_texcoord = a_texcoord;\n" +
"}\n";
private static final String FRAGMENT_SHADER =
"precision mediump float;\n" +
"uniform sampler2D tex_sampler;\n" +
"varying vec2 v_texcoord;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(tex_sampler, v_texcoord);\n" +
"}\n";
private final int FLOAT_SIZE_BYTES = 4;
private Bitmap watermark;
private int shaderProgram;
private int texSamplerHandle;
private int texCoordHandle;
private int posCoordHandle;
private FloatBuffer texVertices;
private FloatBuffer posVertices;
private int[] textureHandles = new int[1];
#Override
public void configureOpenGL() {
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, OpenGLUtils.loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER));
GLES20.glAttachShader(shaderProgram, OpenGLUtils.loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER));
GLES20.glLinkProgram(shaderProgram);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(shaderProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
String info = GLES20.glGetProgramInfoLog(shaderProgram);
GLES20.glDeleteProgram(shaderProgram);
shaderProgram = 0;
throw new RuntimeException("Could not link program: " + info);
}
texSamplerHandle = GLES20.glGetUniformLocation(shaderProgram, "tex_sampler");
texCoordHandle = GLES20.glGetAttribLocation(shaderProgram, "a_texcoord");
posCoordHandle = GLES20.glGetAttribLocation(shaderProgram, "a_position");
}
#Override
public void createBuffers() {
ByteBuffer byteBuffer;
byteBuffer = ByteBuffer.allocateDirect(TEX_VERTICES.length * FLOAT_SIZE_BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
texVertices = byteBuffer.asFloatBuffer();
texVertices.put(TEX_VERTICES);
texVertices.position(0);
byteBuffer = ByteBuffer.allocateDirect(POS_VERTICES.length * FLOAT_SIZE_BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
posVertices = byteBuffer.asFloatBuffer();
posVertices.put(POS_VERTICES);
posVertices.position(0);
}
#Override
public void draw() {
// Select the program.
GLES20.glUseProgram(shaderProgram);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA );
// Set the vertex attributes
GLES20.glVertexAttribPointer(texCoordHandle, 2, GLES20.GL_FLOAT, false, 0, texVertices);
GLES20.glEnableVertexAttribArray(texCoordHandle);
GLES20.glVertexAttribPointer(posCoordHandle, 2, GLES20.GL_FLOAT, false, 0, posVertices);
GLES20.glEnableVertexAttribArray(posCoordHandle);
// Set the input texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[0]);
GLES20.glUniform1i(texSamplerHandle, 0);
GLES20.glGenTextures(textureHandles.length, textureHandles, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, watermark, 0);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisableVertexAttribArray(texCoordHandle);
GLES20.glDisableVertexAttribArray(posCoordHandle);
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glUseProgram(0);
}
#Override
public void setProjectionMatrix(float[] projectionMatrix) {
}
public void setWatermarkTexture(Bitmap bitmap) {
watermark = bitmap;
}
}
I am Using OpenTok Android SDK 2.4+
(https://tokbox.com/developer/sdks/android/)
Currently in SDK it's Showing the Publisher(Camera Preview) in Square Area but I wants it in Round Shape (Publisher Camera view in Round shape).
Note: PublisherView using OpenGL GLSurfaceView to show Camera Preview.
I am using attached "CustomVideoRenderer.java" Class by Extending class "BaseVideoRenderer".
I am not familiar with the OpenGL so not able to understand what I should change in Code.
So Please help me to Get Out of it..
TO Display Publisher View in Round Shape.
public class CustomVideoRenderer extends BaseVideoRenderer {
private Context mContext;
private GLSurfaceView mView;
private MyRenderer mRenderer;
static class MyRenderer implements GLSurfaceView.Renderer {
int mTextureIds[] = new int[3];
float[] mScaleMatrix = new float[16];
private FloatBuffer mVertexBuffer;
private FloatBuffer mTextureBuffer;
private ShortBuffer mDrawListBuffer;
boolean mVideoFitEnabled = true;
boolean mVideoDisabled = false;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static final int TEXTURECOORDS_PER_VERTEX = 2;
static float mXYZCoords[] = {-1.0f, 1.0f, 0.0f, // top left
-1.0f, -1.0f, 0.0f, // bottom left
1.0f, -1.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f // top right
};
static float mUVCoords[] = {0, 0, // top left
0, 1, // bottom left
1, 1, // bottom right
1, 0}; // top right
private short mVertexIndex[] = {0, 1, 2, 0, 2, 3}; // order to draw
// vertices
private final String vertexShaderCode = "uniform mat4 uMVPMatrix;"
+ "attribute vec4 aPosition;\n"
+ "attribute vec2 aTextureCoord;\n"
+ "varying vec2 vTextureCoord;\n" + "void main() {\n"
+ " gl_Position = uMVPMatrix * aPosition;\n"
+ " vTextureCoord = aTextureCoord;\n" + "}\n";
private final String fragmentShaderCode = "precision mediump float;\n"
+ "uniform sampler2D Ytex;\n"
+ "uniform sampler2D Utex,Vtex;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main(void) {\n"
+ " float nx,ny,r,g,b,y,u,v;\n"
+ " mediump vec4 txl,ux,vx;"
+ " nx=vTextureCoord[0];\n"
+ " ny=vTextureCoord[1];\n"
+ " y=texture2D(Ytex,vec2(nx,ny)).r;\n"
+ " u=texture2D(Utex,vec2(nx,ny)).r;\n"
+ " v=texture2D(Vtex,vec2(nx,ny)).r;\n"
+ " y=1.0-1.1643*(y-0.0625);\n" // Invert effect
// + " y=1.1643*(y-0.0625);\n" // Normal renderer
+ " u=u-0.5;\n" + " v=v-0.5;\n" + " r=y+1.5958*v;\n"
+ " g=y-0.39173*u-0.81290*v;\n" + " b=y+2.017*u;\n"
+ " gl_FragColor=vec4(r,g,b,1.0);\n" + "}\n";
ReentrantLock mFrameLock = new ReentrantLock();
Frame mCurrentFrame;
private int mProgram;
private int mTextureWidth;
private int mTextureHeight;
private int mViewportWidth;
private int mViewportHeight;
public MyRenderer()
{
ByteBuffer bb = ByteBuffer.allocateDirect(mXYZCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
mVertexBuffer = bb.asFloatBuffer();
mVertexBuffer.put(mXYZCoords);
mVertexBuffer.position(0);
ByteBuffer tb = ByteBuffer.allocateDirect(mUVCoords.length * 4);
tb.order(ByteOrder.nativeOrder());
mTextureBuffer = tb.asFloatBuffer();
mTextureBuffer.put(mUVCoords);
mTextureBuffer.position(0);
ByteBuffer dlb = ByteBuffer.allocateDirect(mVertexIndex.length * 2);
dlb.order(ByteOrder.nativeOrder());
mDrawListBuffer = dlb.asShortBuffer();
mDrawListBuffer.put(mVertexIndex);
mDrawListBuffer.position(0);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
gl.glClearColor(0, 0, 0, 1);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES
// Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex
// shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment
// shader to
// program
GLES20.glLinkProgram(mProgram);
int positionHandle = GLES20.glGetAttribLocation(mProgram,
"aPosition");
int textureHandle = GLES20.glGetAttribLocation(mProgram,
"aTextureCoord");
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false, COORDS_PER_VERTEX * 4,
mVertexBuffer);
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(textureHandle,
TEXTURECOORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
TEXTURECOORDS_PER_VERTEX * 4, mTextureBuffer);
GLES20.glEnableVertexAttribArray(textureHandle);
GLES20.glUseProgram(mProgram);
int i = GLES20.glGetUniformLocation(mProgram, "Ytex");
GLES20.glUniform1i(i, 0); /* Bind Ytex to texture unit 0 */
i = GLES20.glGetUniformLocation(mProgram, "Utex");
GLES20.glUniform1i(i, 1); /* Bind Utex to texture unit 1 */
i = GLES20.glGetUniformLocation(mProgram, "Vtex");
GLES20.glUniform1i(i, 2); /* Bind Vtex to texture unit 2 */
mTextureWidth = 0;
mTextureHeight = 0;
}
static void initializeTexture(int name, int id, int width, int height) {
GLES20.glActiveTexture(name);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
width, height, 0, GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE, null);
}
void setupTextures(Frame frame) {
if (mTextureIds[0] != 0) {
GLES20.glDeleteTextures(3, mTextureIds, 0);
}
GLES20.glGenTextures(3, mTextureIds, 0);
int w = frame.getWidth();
int h = frame.getHeight();
int hw = (w + 1) >> 1;
int hh = (h + 1) >> 1;
initializeTexture(GLES20.GL_TEXTURE0, mTextureIds[0], w, h);
initializeTexture(GLES20.GL_TEXTURE1, mTextureIds[1], hw, hh);
initializeTexture(GLES20.GL_TEXTURE2, mTextureIds[2], hw, hh);
mTextureWidth = frame.getWidth();
mTextureHeight = frame.getHeight();
}
void updateTextures(Frame frame) {
int width = frame.getWidth();
int height = frame.getHeight();
int half_width = (width + 1) >> 1;
int half_height = (height + 1) >> 1;
int y_size = width * height;
int uv_size = half_width * half_height;
ByteBuffer bb = frame.getBuffer();
// If we are reusing this frame, make sure we reset position and
// limit
bb.clear();
if (bb.remaining() == y_size + uv_size * 2) {
bb.position(0);
GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[0]);
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width,
height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE,
bb);
bb.position(y_size);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[1]);
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
half_width, half_height, GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE, bb);
bb.position(y_size + uv_size);
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[2]);
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
half_width, half_height, GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE, bb);
} else {
mTextureWidth = 0;
mTextureHeight = 0;
}
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
mViewportWidth = width;
mViewportHeight = height;
}
#Override
public void onDrawFrame(GL10 gl) {
mFrameLock.lock();
if (mCurrentFrame != null && !mVideoDisabled) {
GLES20.glUseProgram(mProgram);
if (mTextureWidth != mCurrentFrame.getWidth()
|| mTextureHeight != mCurrentFrame.getHeight()) {
setupTextures(mCurrentFrame);
}
updateTextures(mCurrentFrame);
Matrix.setIdentityM(mScaleMatrix, 0);
float scaleX = 1.0f, scaleY = 1.0f;
float ratio = (float) mCurrentFrame.getWidth()
/ mCurrentFrame.getHeight();
float vratio = (float) mViewportWidth / mViewportHeight;
if (mVideoFitEnabled) {
if (ratio > vratio) {
scaleY = vratio / ratio;
} else {
scaleX = ratio / vratio;
}
} else {
if (ratio < vratio) {
scaleY = vratio / ratio;
} else {
scaleX = ratio / vratio;
}
}
Matrix.scaleM(mScaleMatrix, 0,
scaleX * (mCurrentFrame.isMirroredX() ? -1.0f : 1.0f),
scaleY, 1);
int mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram,
"uMVPMatrix");
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false,
mScaleMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mVertexIndex.length,
GLES20.GL_UNSIGNED_SHORT, mDrawListBuffer);
} else {
//black frame when video is disabled
gl.glClearColor(0, 0, 0, 1);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
mFrameLock.unlock();
}
public void displayFrame(Frame frame) {
mFrameLock.lock();
if (this.mCurrentFrame != null) {
this.mCurrentFrame.recycle();
}
this.mCurrentFrame = frame;
mFrameLock.unlock();
}
public static int loadShader(int type, String shaderCode) {
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public void disableVideo(boolean b) {
mFrameLock.lock();
mVideoDisabled = b;
if (mVideoDisabled) {
if (this.mCurrentFrame != null) {
this.mCurrentFrame.recycle();
}
this.mCurrentFrame = null;
}
mFrameLock.unlock();
}
public void enableVideoFit(boolean enableVideoFit) {
mVideoFitEnabled = enableVideoFit;
}
}
public CustomVideoRenderer(Context context) {
this.mContext = context;
mView = new GLSurfaceView(context);
mView.setEGLContextClientVersion(2);
mRenderer = new MyRenderer();
mView.setRenderer(mRenderer);
mView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
#Override
public void onFrame(Frame frame) {
mRenderer.displayFrame(frame);
mView.requestRender();
}
#Override
public void setStyle(String key, String value) {
if (BaseVideoRenderer.STYLE_VIDEO_SCALE.equals(key)) {
if (BaseVideoRenderer.STYLE_VIDEO_FIT.equals(value)) {
mRenderer.enableVideoFit(true);
} else if (BaseVideoRenderer.STYLE_VIDEO_FILL.equals(value)) {
mRenderer.enableVideoFit(false);
}
}
}
#Override
public void onVideoPropertiesChanged(boolean videoEnabled) {
mRenderer.disableVideo(!videoEnabled);
}
#Override
public View getView() {
return mView;
}
#Override
public void onPause() {
mView.onPause();
}
#Override
public void onResume() {
mView.onResume();
}
}
https://tokbox.com/developer/sdks/android/reference/com/opentok/android/Session.SessionOptions.html
You can have returned a TextureViews with TextureViews() and then the usual methods to have rounded corner seems to work.