I'm trying to texture an ArrayList of rectangle "bricks" for my game. I have code that works perfectly when there's only one rectangle to texture, but anytime I add more, the fragment shader only applies the texture to the last rectangle drawn, and the others are rendered invisible. I don't need to use different textures, just the exact same texture for each rectangle. What do I need to modify with my fragment shaders to make this happen?
Here's the code for my Graphics class:
private ArrayList<FloatBuffer> bricks;
private FloatBuffer textureBuffer;
private ShortBuffer drawListBuffer;
static final int COORDS_PER_VERTEX = 3;
private short drawOrder[] = {0, 1, 2, 0, 2, 3}; //Order to draw vertices
private float[] textureCoords =
{ 1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f };
private final int mProgram;
//New variables for textures
private int[] texBufferID = new int[1];
private int texCoordID;
private int texID;
//Use this guy to access and set the view transformation
private int mMVPMatrixHandle;
private final String vertexShaderCode =
//These are the coordinates used to pass texCoord over to the fragmentShader
"attribute vec2 s_vTexCoord;" +
"varying vec2 texCoord;" +
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
//The line that does the aforementioned pass
" texCoord = s_vTexCoord;" +
//the matrix has to modify glPosition
//Note: uMVPMatrix has to be first here. Cuz reasons
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"varying vec2 texCoord;" +
"precision mediump float;" +
"uniform sampler2D texture;" +
"void main() {" +
" gl_FragColor = texture2D(texture, texCoord);" + //How is texture defined?
"}";
public Graphics(Context context) {
//Load our texture coordinates into a buffer
ByteBuffer b = ByteBuffer.allocateDirect(textureCoords.length * 4);
b.order(ByteOrder.nativeOrder());
//create a floating point buffer from bb
textureBuffer = b.asFloatBuffer();
//Add our coordinates to the float buffer
textureBuffer.put(textureCoords);
//Set the buffer to read the first coordinate
textureBuffer.position(0);
//initialize buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); //2 bytes per short
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
//create empty OpenGL ES Program
mProgram = GLES20.glCreateProgram();
//Add the shaders
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
//Create OpenGL program executables
GLES20.glLinkProgram(mProgram);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
//Pass in our texture coordinates to the vertex shader
texCoordID = GLES20.glGetAttribLocation(mProgram, "s_vTexCoord");
GLES20.glEnableVertexAttribArray(texCoordID);
GLES20.glVertexAttribPointer(texCoordID, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
//Read in the bmp from file to bmp
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), R.drawable.brick, options);
//Read bmp into OpenGL as texture 0
GLES20.glGenTextures(1, texBufferID, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texBufferID[0]);
//This is basically OpenGL texture preferences
//GL_NEAREST means it grabs the color value of the nearest pixel for scaling. Fast and dirty.
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_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);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
bmp.recycle();
if (texBufferID[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
//Tell our vertex shader that texture 0 is the active texture
texID = GLES20.glGetUniformLocation(mProgram, "texture");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glUniform1i(texID, 0);
}
public void newBricks(ArrayList<float[]> brickList){
bricks = new ArrayList<>();
for (int i = 0; i < brickList.size(); i++) {
float[] brick = brickList.get(i);
// initialize a buffer to hold the vertices
ByteBuffer bb = ByteBuffer.allocateDirect(
//4 bytes per float
brick.length * 4);
//Tells bb to use the devices native byte order
bb.order(ByteOrder.nativeOrder());
//create a floating point buffer from bb
FloatBuffer vertexBuffer = bb.asFloatBuffer();
//Add our coordinates to the float buffer
vertexBuffer.put(brick);
//Set the buffer to read the first coordinate
vertexBuffer.position(0);
bricks.add(vertexBuffer);
}
}
public void remove(int brick){
bricks.remove(brick);
}
private int mPositionHandle;
private final int vertexCount = 12 / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; //4 bytes per vertex
//We now pass draw the calculated camera and projection view matrix
public void draw(float[] mvpMatrix) {
//Add program to the OpenGL ES environment
GLES20.glUseProgram(mProgram);
//Pass in our texture coordinates to the vertex shader
texCoordID = GLES20.glGetAttribLocation(mProgram, "s_vTexCoord");
GLES20.glEnableVertexAttribArray(texCoordID);
GLES20.glVertexAttribPointer(texCoordID, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
//get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
//enable a handle to the brick vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
//get handle to the transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
//pass the transformation matrix to the shader
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
for (int i = bricks.size() - 1; i >= 0; i--) {
//Prepare the brick coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, bricks.get(0));
//Draw the brick
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, vertexCount);
}
//Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
You wrote
bricks.get(0)
instead ofbricks.get(i)
infor
loop ofpublic void draw(float[] mvpMatrix)
function.And also you can remove this line
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
because it is from fixed function pipeline OpenGL, but you use Shaders from OpenGL ES 2.0