Multiple objects with same texture

332 views Asked by At

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);
}
1

There are 1 answers

1
haksist On BEST ANSWER

You wrote bricks.get(0) instead of bricks.get(i) in for loop of public 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