/* * Copyright (C) 2016 eschao <esc.chao@gmail.com> * * 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 com.eschao.android.widget.pageflip; import android.util.Log; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import static android.opengl.GLES20.GL_FLOAT; import static android.opengl.GLES20.glDrawArrays; import static android.opengl.GLES20.glEnableVertexAttribArray; import static android.opengl.GLES20.glVertexAttribPointer; /** * Vertexes is used to manage vertex and texture data for openGL drawing * * @author eschao */ class Vertexes { private static final String TAG = "Vertexes"; // how many vertexes in vertex float buffer will be drawn on screen int mVertexesSize; // how many float data is used for every vertex int mSizeOfPerVex; // vertex data array float[] mVertexes; // texture coordinates array float[] mTextureCoords; // float buffer for vertexes data and texture coordinates data FloatBuffer mVertexesBuf; FloatBuffer mTextureCoordsBuf; // next index when add vertex to float array int mNext; /** * Default constructor */ public Vertexes() { mNext = 0; mVertexesSize = 0; mSizeOfPerVex = 0; mVertexes = null; mVertexesBuf = null; mTextureCoords = null; mTextureCoordsBuf = null; } /** * Constructor with given vertex amount * * @param capacity vertex max amount * @param sizeOfPerVex how many float data is used for a vertex */ public Vertexes(int capacity, int sizeOfPerVex) { set(capacity, sizeOfPerVex, true); } /** * Constructor with given vertex max amount and texture * * @param capacity vertex amount * @param sizeOfPerVex how many float data is used for a vertex * @param hasTexture if need texture buffer for texture coordinates */ public Vertexes(int capacity, int sizeOfPerVex, boolean hasTexture) { set(capacity, sizeOfPerVex, hasTexture); } /** * Set max vertex amount and create buffer for vertex and texture * * @param capacity vertex amount * @param sizeOfPerVex how many float data is used for a vertex * @param hasTexture True if need texture buffer for texture coordinates * @return self */ public Vertexes set(int capacity, int sizeOfPerVex, boolean hasTexture) { if (sizeOfPerVex < 2) { Log.w(TAG, "sizeOfPerVex is invalid: " + sizeOfPerVex); throw new IllegalArgumentException("sizeOfPerVex:" + sizeOfPerVex + "is less than 2!"); } // reset all mNext = 0; mVertexes = null; mVertexesBuf = null; mTextureCoords = null; mTextureCoordsBuf = null; // create vertexes buffer mSizeOfPerVex = sizeOfPerVex; mVertexes = new float[capacity * sizeOfPerVex]; mVertexesBuf = ByteBuffer.allocateDirect(capacity * sizeOfPerVex * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); // if need, create texture buffer if (hasTexture) { mTextureCoords = new float[capacity << 1]; mTextureCoordsBuf = ByteBuffer.allocateDirect(capacity << 3) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); } return this; } /** * Release all resources * * @return self */ public Vertexes release() { mNext = 0; mVertexesSize = 0; mSizeOfPerVex = 0; mVertexes = null; mVertexesBuf = null; mTextureCoords = null; mTextureCoordsBuf = null; return this; } /** * Get max vertex amount * * @return max vertex amount */ public int capacity() { return mVertexes == null ? 0 : mVertexes.length / mSizeOfPerVex; } /** * Reset index of float array before adding vertex to buffer */ public void reset() { mNext = 0; } /** * Get float data with given index * * @param index float data position index * @return float data */ public float getFloatAt(int index) { if (index >= 0 && index < mNext) { return mVertexes[index]; } return 0; } /** * Set vertex coordinate(x, y, z) in given buffer position * * @param i where to start saving vertex data * @param x x value of vertex coordinate * @param y y value of vertex coordinate * @param z z value of vertex coordinate * @return self */ public Vertexes setVertex(int i, float x, float y, float z) { assert(i+2 < mVertexes.length); mVertexes[i] = x; mVertexes[i + 1] = y; mVertexes[i + 2] = z; return this; } /** * Set vertex coordinate(x, y, z, width) in given buffer position * * @param i where to start saving vertex data * @param x x value of vertex coordinate * @param y y value of vertex coordinate * @param z z value of vertex coordinate * @param w width value which is normally used to pass other value to shader * @return self */ public Vertexes setVertex(int i, float x, float y, float z, float w) { assert(i+3 < mVertexes.length); mVertexes[i] = x; mVertexes[i + 1] = y; mVertexes[i + 2] = z; mVertexes[i + 3] = w; return this; } /** * Set texture coordinate(x, y) in given buffer position * * @param i where to start saving texture coordinate * @param x x value of texture coordinate * @param y y value of texture coordinate * @return self */ public Vertexes setTextureCoord(int i, float x, float y) { assert(i+1 < mTextureCoords.length); mTextureCoords[i] = x; mTextureCoords[i + 1] = y; return this; } /** * Add vertex coordinate to buffer * * @param x x value of vertex coordinate * @param y y value of vertex coordinate * @param z z value of vertex coordinate * @return self */ public Vertexes addVertex(float x, float y, float z) { mVertexes[mNext++] = x; mVertexes[mNext++] = y; mVertexes[mNext++] = z; return this; } /** * Add vertex and texture coordinates * * @param x x value of vertex coordinate * @param y y value of vertex coordinate * @param z z value of vertex coordinate * @param coordX x value of texture coordinate * @param coordY y value of texture coordinate * @return self */ public Vertexes addVertex(float x, float y, float z, float coordX, float coordY) { int j = mNext / mSizeOfPerVex * 2; mVertexes[mNext++] = x; mVertexes[mNext++] = y; mVertexes[mNext++] = z; mTextureCoords[j++] = coordX; mTextureCoords[j] = coordY; return this; } /** * Add vertex coordinate to buffer * * @param x x value of vertex coordinate * @param y y value of vertex coordinate * @param z z value of vertex coordinate * @param w width value which is normally used to pass other value to shader * @return self */ public Vertexes addVertex(float x, float y, float z, float w) { mVertexes[mNext++] = x; mVertexes[mNext++] = y; mVertexes[mNext++] = z; mVertexes[mNext++] = w; return this; } /** * Add vertex and texture coordinates * * @param x x value of vertex coordinate * @param y y value of vertex coordinate * @param z z value of vertex coordinate * @param w width value which is normally used to pass other value to shader * @param coordX x value of texture coordinate * @param coordY y value of texture coordinate * @return self */ public Vertexes addVertex(float x, float y, float z, float w, float coordX, float coordY) { int j = mNext / mSizeOfPerVex * 2; mVertexes[mNext++] = x; mVertexes[mNext++] = y; mVertexes[mNext++] = z; mVertexes[mNext++] = w; mTextureCoords[j++] = coordX; mTextureCoords[j] = coordY; return this; } /** * Add GLPoint to float buffer * * @param point GLPoint object * @return self */ public Vertexes addVertex(GLPoint point) { int j = mNext / mSizeOfPerVex * 2; mVertexes[mNext++] = point.x; mVertexes[mNext++] = point.y; mVertexes[mNext++] = point.z; mTextureCoords[j++] = point.texX; mTextureCoords[j] = point.texY; return this; } /** * Put data from float array to float buffer * * @param offset data start offset in float array * @param length data length to be put */ public void toFloatBuffer(int offset, int length) { mVertexesBuf.put(mVertexes, offset, length).position(0); mVertexesSize = length / mSizeOfPerVex; // has texture? put again if (mTextureCoords != null) { final int o = offset / mSizeOfPerVex * 2; final int l = mVertexesSize * 2; mTextureCoordsBuf.put(mTextureCoords, o, l).position(0); } } /** * Put all data from float array to float buffer * <p> * The offset is 0 and the length is determined by mNext which is increased * after calling {@link #addVertex} * </p> */ public void toFloatBuffer() { mVertexesBuf.put(mVertexes, 0, mNext).position(0); mVertexesSize = mNext / mSizeOfPerVex; if (mTextureCoords != null) { mTextureCoordsBuf.put(mTextureCoords, 0, mVertexesSize << 1) .position(0); } } /** * Draw vertexes * * @param type openGL drawing type: TRIANGLE, STRIP, FAN * @param hVertexPos vertex position var in shader program * @param hTextureCoord texture var in shader program */ public void drawWith(int type, int hVertexPos, int hTextureCoord) { // pass vertex data glVertexAttribPointer(hVertexPos, mSizeOfPerVex, GL_FLOAT, false, 0, mVertexesBuf); glEnableVertexAttribArray(hVertexPos); // pass texture data glVertexAttribPointer(hTextureCoord, 2, GL_FLOAT, false, 0, mTextureCoordsBuf); glEnableVertexAttribArray(hTextureCoord); // draw triangles glDrawArrays(type, 0, mVertexesSize); } /** * Draw vertexes with given offset and length * * @param type openGL drawing type: TRIANGLE, STRIP, FAN * @param hVertexPos vertex var in shader program * @param hTextureCoord texture var in shader program * @param offset vertex start offset in buffer * @param length vertex length to be drawn */ public void drawWith(int type, int hVertexPos, int hTextureCoord, int offset, int length) { glVertexAttribPointer(hVertexPos, mSizeOfPerVex, GL_FLOAT, false, 0, mVertexesBuf); glEnableVertexAttribArray(hVertexPos); glVertexAttribPointer(hTextureCoord, 2, GL_FLOAT, false, 0, mTextureCoordsBuf); glEnableVertexAttribArray(hTextureCoord); glDrawArrays(type, offset, length); } }