I want to load more than one textures in OpenGL and use them.
This is TextureLoader,i think it correctly loads texture on idx position.
public int[] texture = new int[10];
public int loadTexture(Context context, int resource,int idx){
GLES20.glGenTextures(idx, texture, 0);
BitmapFactory.Options bo = new BitmapFactory.Options();
Bitmap tex = BitmapFactory.decodeResource(context.getResources(), resource, bo);
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.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, tex, 0);
tex.recycle();
if(texture[idx] == 0){
// Displays error
}
return texture[idx];
}
This is my render and I have no idea how to select loaded texture.
int mPositionHandle =
GLES20.glGetAttribLocation(riGraphicTools.sp_Image, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, 3,
GLES20.GL_FLOAT, false,
0, vertexBuffer);
int mTexCoordLoc = GLES20.glGetAttribLocation(riGraphicTools.sp_Image,
"a_texCoord" );
GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
// Prepare the texturecoordinates
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT,
false,
0, uvBuffer);
int mtrxhandle = GLES20.glGetUniformLocation(riGraphicTools.sp_Image,
"uMVPMatrix");
GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0);
int mSamplerLoc = GLES20.glGetUniformLocation (riGraphicTools.sp_Image,
"s_texture" );
GLES20.glUniform1i ( mSamplerLoc, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
It looks like you have most of what you need, assuming that you filled the buffers with the necessary data. There's one call in your code where the arguments are not what you must have intended:
GLES20.glGenTextures(idx, texture, 0);
With the Java bindings in Android, the first argument is the number of ids you want to generate, the second an array of ids, the 3rd the start index in the array where the generated ids are stored. So to generate one id, and store it as texture[idx], the correct arguments are:
GLES20.glGenTextures(1, texture, idx);
Then, for the core part of your question, the call you are looking for is glBindTexture(). This call defines which specific texture most texture-related OpenGL operations use. You will need this call in multiple places.
In your loadTexture() method, both GLES20.glTexParameteri() and GLUtils.texImage2D() operate on the currently bound texture. So before those calls, you need to add this call to bind your new texture:
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[idx]);
You need the same call before the draw operation. So somewhere in your render method, before you call GLES20.glDrawElements(), use a glBindTexture() call that looks just like the one above, with the idx value of the texture you want to use. This is where you really choose which of the textures you loaded is applied during rendering.
There are mechanisms that allow you to bind multiple textures at the same time. This is mainly useful if your shader needs to sample from multiple textures. You most likely won't need this yet. But once you get to that point, you will want to read up on "texture units", and look up the glActiveTexture() call.
Related
I am writing an app utilizing CameraX to capture the camera feed, OpenCV to modify the frames and the OpenGL to render them on a GLSurfaceView.
My current approach was to render the original frames from CameraX, construct a pixel buffer, an OpenCV Mat, use glReadPixels to copy the pixel buffer (ByteBuffer) into the Mat, then process it, write the pixel buffer from Mat back to the pixel buffer and then render it onto the texture with glTexSubImage2D.
The problem is, CameraX enables me to access the frame data via GL_TEXTURE_EXTERNAL_OES, which - as per OpenGL's documentation - does not allow for glTexSubImage2D to modify the texture and my current approach, using the code below, does not work and continously throws W/OpenGLRenderer: [SurfaceTexture-1-25873-0] bindTextureImage: clearing GL error: 0x500, which is expected as says the documentation. Is there an alternative way to copy the buffer into GL_TEXTURE_EXTERNAL_OES after OpenCV processing? Another thing I can think of is to copy the texture into GL_TEXTURE_2D and then use glTexSubImage2D, although I have no idea how to do that. Maybe someone knows another approach that would allow me to achieve the goal?
My code:
public void onDrawFrame(GL10 gl) {
GLES20.glClear( GLES20.GL_COLOR_BUFFER_BIT );
if(this.resolutionSet) {
surfaceTexture.updateTexImage();
GLES20.glUseProgram(hProgram);
int ph = GLES20.glGetAttribLocation(hProgram, "vPosition");
int tch = GLES20.glGetAttribLocation(hProgram, "vTexCoord");
int th = GLES20.glGetUniformLocation(hProgram, "sTexture");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, hTex[0]);
GLES20.glUniform1i(th, 0);
GLES20.glVertexAttribPointer(ph, 2, GLES20.GL_FLOAT, false, 4 * 2, pVertex);
GLES20.glVertexAttribPointer(tch, 2, GLES20.GL_FLOAT, false, 4 * 2, pTexCoord);
GLES20.glEnableVertexAttribArray(ph);
GLES20.glEnableVertexAttribArray(tch);
GLES20.glReadPixels(0, 0, this.img.cols(), this.img.rows(), GL_RGBA, GL_UNSIGNED_BYTE, this.imgBuff);
img.put(0, 0, this.imgBuff.array());
Log.d(LOG_TAG, img.toString());
Imgproc.cvtColor(img, img, Imgproc.COLOR_RGBA2BGRA);
Imgproc.cvtColor(img, img, Imgproc.COLOR_BGRA2GRAY);
this.imgBuff.clear();
img.get(0, 0, this.imgBuff.array());
GLES20.glTexImage2D(GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
GLES20.glTexSubImage2D(GL_TEXTURE_EXTERNAL_OES, 0, 0, 0, img.width(), img.height(), GL_RGBA, GL_UNSIGNED_BYTE, this.imgBuff);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
GLES20.glFlush();
}
and the code initializing texture:
hTex = new int[1];
GLES20.glGenTextures ( 1, hTex, 0 );
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, hTex[0]);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
Given you are replacing the entire image and uploading "normal" RGBA data from the application, why does this need to be a GL_TEXTURE_EXTERNAL_OES type at all? Just use a normal GL_TEXTURE_2D.
I am using following method to create OpenGL ES texture on android.
private int createTexture(int width, int height, int i) {
int[] mTextureHandles = new int[1];
GLES20.glGenTextures(1, mTextureHandles, 0);
int textureID = mTextureHandles[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
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_REPEAT);
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);
return textureID;
}
Then uploading a bitmap to this texture and simply rendering it using GLSurfaceView's Renderer.
Most of the times it is working as expected,
But randomly the texture is displayed like this. (here GL_TEXTURE_WRAP_S mode is GLES20.GL_CLAMP_TO_EDGE
After changing wrap mode.
If GL_TEXTURE_WRAP_S = GLES20.GL_REPEAT then (again randomly) texture is displayed like this(notice the color change).
I have already tried using power of 2 texture.
Code for vertex buffer
private FloatBuffer createVertexBuffer(RectF glCoords) {
// RectF glCoords contains gl vertices.
// current Rect read from Logcat.
// left = -0.5833333, top = 0.5, right = 0.5833334, bottom = -0.5
float[] vertices = new float[]{glCoords.left, glCoords.top, 0, 1, // V1 - top left
glCoords.left, glCoords.bottom, 0, 1, // V2 - bottom left
glCoords.right, glCoords.bottom, 0, 1, // V3 - bottom right
glCoords.right, glCoords.top, 0, 1 // V4 - top right
};
FloatBuffer vBuffer = ByteBuffer.allocateDirect(vertices.length * bytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
vBuffer.put(vertices);
vBuffer.position(0);
return vBuffer;
}
IndicesBuffer is not used as I am using Triangle-Fan to render triangles.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
It would be really helpful if someone can point out as to what could be causing this
Your geometry seems to be a 4-vertex rectangle (quad), but the code wants to draw a fan with 6 vertices - GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
Those extra 2 vertices aren't initialized, not specified in the vertex array. OpenGL will read beyond the defined part of the array. The results would be random, and I'd even expect crashes.
Replace 6 with 4 in glDrawArrays() call, this should fix the problem.
I want use OpenGL ES to draw a frame animation, so I use glTexSubImage2D to update the texture.
This function initializes the texture:
private void initTexture()
{
textures=new int[1];
GLES20.glGenTextures(1,textures,0);
//Bitmap bitmap= BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/xiaobizi/xiaobizi_0001.png");
Bitmap bitmap= BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/aa.png");
ratio=(float)bitmap.getHeight()/(float)bitmap.getWidth();
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);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
this function to save&remove Bitmap:
mTextureMap.remove(mPathList.get(messageTag));
mTextureMap.put(mPathList.get(saveCount),BitmapFactory.decodeFile(mPathList.get(saveCount)));
private void drawMagic()
{
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE,GLES20.GL_ONE_MINUS_SRC_ALPHA);
GLES20.glUseProgram(programMagic);
int mPositionHandleFace = GLES20.glGetAttribLocation(programMagic, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandleFace);
GLES20.glVertexAttribPointer(mPositionHandleFace, 2, GLES20.GL_FLOAT, false, 0, 0);
int mTexCoordLocFace = GLES20.glGetAttribLocation(programMagic, "a_texCoord" );
// Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray ( mTexCoordLocFace );
// Prepare the texturecoordinates
GLES20.glVertexAttribPointer(mTexCoordLocFace, 2, GLES20.GL_FLOAT, false, 0, 0);
// Get handle to shape's transformation matrix
int mTransHandle = GLES20.glGetUniformLocation(programMagic, "transMatrix");
int mScaleHandle=GLES20.glGetUniformLocation(programMagic,"scaleMatrix");
int mRotateXHandle=GLES20.glGetUniformLocation(programMagic,"rotateXMatrix");
int mRotateZHandle=GLES20.glGetUniformLocation(programMagic,"rotateZMatrix");
int mRotateYHandle=GLES20.glGetUniformLocation(programMagic,"rotateYMatrix");
//control matrix
GLES20.glUniformMatrix4fv(mTransHandle,1,false,transMatrix,0);
GLES20.glUniformMatrix4fv(mScaleHandle,1,false,scaleMatrix,0);
GLES20.glUniformMatrix4fv(mRotateXHandle,1,false,rotateXMatrix,0);
GLES20.glUniformMatrix4fv(mRotateZHandle,1,false,rotateZMatrix,0);
GLES20.glUniformMatrix4fv(mRotateYHandle,1,false,rotateYMatrix,0);
int mtrxhandleFace = GLES20.glGetUniformLocation(programMagic, "uMVPMatrix");
// Apply the projection and view transformation
//GLES20.glUniformMatrix4fv(mtrxhandleFace, 1, false, mGLTextureTransformMatrix, 0);
GLES20.glUniformMatrix4fv(mtrxhandleFace, 1, false, mSecondTransFormMatrix, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[0]);
if(i>=mTotalCount)
{
i=i-mTotalCount;
}
// update texture
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D,0,0,0,mTextureMap.get(mPathList.get(i)));
int mSamplerLocFace = GLES20.glGetUniformLocation (programMagic, "s_texture" );
// Set the sampler texture unit to 0, where we have saved the texture.
GLES20.glUniform1i ( mSamplerLocFace, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandleFace);
GLES20.glDisableVertexAttribArray(mTexCoordLocFace);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
mDecodeHandler.sendEmptyMessage(i);
i++;
}
this is my drawFrame function.
In initTexture function if the bitmap belongs to the Frame Animation, texSubImage2D works,the texture always updating, but if i pass a bitmap that does't belongs to the Frame Animation , the function texSubImage2D does't work. In that case, the texture always was the bitmap that i passed in function initTexture didn't update.
If i called the function when opengl was dawing, the texture was black,but its shapes can be displayed properly, just the background was black.
I am searching for a long time on net. But no use. Please help or try to give some ideas how to fix this.thank u.
This is the code I'm using to render a Bitmap in Wikitude SDK class ArchitectView
// clear Screen and Depth Buffer, we have set the clear color as black.
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// get handle to vertex shader's vPosition member
int mPositionHandle = GLES20.glGetAttribLocation(riGraphicTools.sp_Image, "vPosition");
// Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, 3,
GLES20.GL_FLOAT, false,
0, vertexBuffer);
// Get handle to texture coordinates location
int mTexCoordLoc = GLES20.glGetAttribLocation(riGraphicTools.sp_Image, "a_texCoord" );
// Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
// Prepare the texturecoordinates
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT,
false,
0, uvBuffer);
// Get handle to shape's transformation matrix
int mtrxhandle = GLES20.glGetUniformLocation(riGraphicTools.sp_Image, "uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0);
// Get handle to textures locations
int mSamplerLoc = GLES20.glGetUniformLocation (riGraphicTools.sp_Image, "s_texture" );
// Set the sampler texture unit to 0, where we have saved the texture.
GLES20.glUniform1i ( mSamplerLoc, 0);
// Draw the triangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
And this is how image being setup:
public void SetupImage(Bitmap bmp)
{
// Create our UV coordinates.
uvs = new float[] {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
// The texture buffer
ByteBuffer bb = ByteBuffer.allocateDirect(uvs.length * 4);
bb.order(ByteOrder.nativeOrder());
uvBuffer = bb.asFloatBuffer();
uvBuffer.put(uvs);
uvBuffer.position(0);
// Generate Textures, if more needed, alter these numbers.
int[] texturenames = new int[1];
GLES20.glGenTextures(1, texturenames, 0);
// Bind texture to texturename
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[0]);
// Set filtering
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);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
// We are done using the bitmap so we should recycle it.
bmp.recycle();
}
The problem is I can't render texture inside ArchitectView, but rendering it without any issues on default android's GLSurfaceView.
You're not supposed to write any OpenGL code inside the ArchitectView. If you need some custom drawing, please write a plugin for the Wikitude SDK and use the startRender/endRender method to draw your OpenGL content (Only these two methods guarantee a valid OpenGL context bound).
So I'm able to display 1 texture at a time but I have a problem with displaying more textures. The render function is called for every texture separately (tex_nr), not sure if that's a good approach. Here's the rendering code:
private void Render(float[] m, int tex_nr) {
// Set our shaderprogram to image shader
GLES20.glUseProgram(riGraphicTools.sp_Image);
// clear Screen and Depth Buffer, we have set the clear color as black.
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// get handle to vertex shader's vPosition member
int mPositionHandle = GLES20.glGetAttribLocation(riGraphicTools.sp_SolidColor, "vPosition");
// Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, 3,
GLES20.GL_FLOAT, false,
0, vertexBuffer);
// Get handle to texture coordinates location
int mTexCoordLoc = GLES20.glGetAttribLocation(riGraphicTools.sp_Image,
"a_texCoord" );
// Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
// Prepare the texturecoordinates
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT,
false,
0, uvBuffer);
// Get handle to shape's transformation matrix
int mtrxhandle = GLES20.glGetUniformLocation(riGraphicTools.sp_Image,
"uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0);
// Get handle to textures locations
int mSamplerLoc = GLES20.glGetUniformLocation (riGraphicTools.sp_Image,
"s_texture" );
// Set the sampler texture unit to where we have saved the texture.
GLES20.glUniform1i ( mSamplerLoc, tex_nr);
// Draw the triangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
}
And here the loading textures code:
texturenames = new int[GameObject.spritePaths.size()];
GLES20.glGenTextures(GameObject.spritePaths.size(), texturenames, 0);
for(int i = 0; i < GameObject.spritePaths.size(); i++)
{
// Retrieve our image from resources.
int id = mContext.getResources().getIdentifier(GameObject.spritePaths.get(i), null, mContext.getPackageName());
// Temporary create a bitmap
Bitmap bmp = BitmapFactory.decodeResource(mContext.getResources(), id);
// Bind texture to texturename
GLES20.glActiveTexture(GLES20.GL_TEXTURE0+i);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[i]);
// Set filtering
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);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
// We are done using the bitmap so we should recycle it.
bmp.recycle();
}
As a result of this code, only the last loaded texture is displayed and I have no idea why the former ones do not show up. I would be very grateful for any clues!
edit:
Actually, I have just found out that I can display all of the textures that I loaded but only 1 at a time. So I guess that the problem isn't connected with loading? It looks as if each consecutive Render call(my function) prevented the drawing in the previous call...
You have a call to glClear() in your Render() method:
// clear Screen and Depth Buffer, we have set the clear color as black.
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
This does pretty much what the name suggests, and what's also captured in your comment: It clears all rendering that has been done so far. So if you call the Render() method multiple times, only the rendering from the last call will be visible.
If you want to invoke Render() multiple times for the same frame, you will need to take it out of Render(), and call it only once at the start of rendering the frame.
There's another thing in your code that looks slightly suspicious:
int mPositionHandle = GLES20.glGetAttribLocation(riGraphicTools.sp_SolidColor, "vPosition");
....
int mTexCoordLoc = GLES20.glGetAttribLocation(riGraphicTools.sp_Image, "a_texCoord");
Unless sp_SolidColor and sp_Image have the same value, you're querying attribute locations from two different shader programs. Since sp_Image is the program you are using, you should pass it in as the first parameter for both these calls.