Skip to content

Instantly share code, notes, and snippets.

@framundo
Last active April 12, 2016 21:54
Show Gist options
  • Save framundo/c5a8f3c7c49810df41ce0281ccfc9150 to your computer and use it in GitHub Desktop.
Save framundo/c5a8f3c7c49810df41ce0281ccfc9150 to your computer and use it in GitHub Desktop.
Android OpenGL 2.0

Basic Android OpenGL 2.0 usage

...
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
...
public class BasicGLRenderer implements GLSurfaceView.Renderer {
private final GLCameraOptions mGLCameraOptions;
private int mBackgroundColor;
private float[] mViewMatrix = new float[16];
private float[] mMVPMatrix = new float[16];
private float[] mProjectionMatrix = new float[16];
public BasicGLRenderer(GLCameraOptions glCameraOptions) {
mGLCameraOptions = glCameraOptions;
mBackgroundColor = Color.BLACK;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(GLColor.r(mBackgroundColor),
GLColor.g(mBackgroundColor),
GLColor.b(mBackgroundColor),
GLColor.a(mBackgroundColor));
// Enable depth testing
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.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, mGLCameraOptions.near, mGLCameraOptions.far);
}
@Override
public void onDrawFrame(GL10 gl) {
// Redraw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0,
mGLCameraOptions.eyeX,
mGLCameraOptions.eyeY,
mGLCameraOptions.eyeZ,
mGLCameraOptions.centerX,
mGLCameraOptions.centerY,
mGLCameraOptions.centerZ,
mGLCameraOptions.upX,
mGLCameraOptions.upY,
mGLCameraOptions.upZ);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
public void setBackgroundColor(int color) {
mBackgroundColor = color;
}
public void addModel(Model3D model3D) {
mModels.add(model3D);
}
}
public class BasicGLRenderer implements GLSurfaceView.Renderer {
...
private List<Model3D> mModels = new LinkedList<>();
@Override
public void onDrawFrame(GL10 gl) {
...
for(Model3D model : mModels) {
model.draw(mMVPMatrix);
}
}
public void addModel(Model3D model3D) {
mModels.add(model3D);
}
}
public class EasyGLView extends GLSurfaceView {
public EasyGLView(Context context) {
super(context);
init();
}
public EasyGLView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setEGLConfigChooser(8, 8, 8, 8, 16, 0);
setEGLContextClientVersion(2);
GLHelper.setContext(getContext().getApplicationContext());
}
}
public class ExampleFragment extends Fragment {
private EasyGLView mEasyGLView;
private BasicGLRenderer mBasicRenderer;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_example, container, false);
mEasyGLView = (EasyGLView) viewGroup.findViewById(R.id.easygl);
setupWorld();
return viewGroup;
}
private void setupWorld() {
GLCameraOptions glCameraOptions = new GLCameraOptions()
.setEye(0, 0, -3.0f)
.setUp(0, 1.0f, 0)
.setDepthRange(0.5f, 100.0f);
mBasicRenderer = new BasicGLRenderer(glCameraOptions);
mBasicRenderer.setBackgroundColor(Color.BLUE);
mEasyGLView.setRenderer(mBasicRenderer);
}
}
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ar.com.wolox.easygl.view.EasyGLView
android:id="@+id/easygl"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
public class GLCameraOptions {
public float eyeX;
public float eyeY;
public float eyeZ;
public float centerX;
public float centerY;
public float centerZ;
public float upX;
public float upY;
public float upZ;
public float near;
public float far;
public GLCameraOptions setEye(float x, float y, float z) {
eyeX = x;
eyeY = y;
eyeZ = z;
return this;
}
public GLCameraOptions setCenter(float x, float y, float z) {
centerX = x;
centerY = y;
centerZ = z;
return this;
}
public GLCameraOptions setUp(float x, float y, float z) {
upX = x;
upY = y;
upZ = z;
return this;
}
public GLCameraOptions setDepthRange(float near, float far) {
this.near = near;
this.far = far;
return this;
}
}
public class GLHelper {
private static final String TAG = "GLHelper";
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);
}
}
}
public abstract class Model3D {
private Integer mProgram;
private int mColorHandle;
private float[] mColor;
private String mVertexShader;
private String mFragmentShader;
private void setupShaders() {
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram,
GLHelper.loadShader(GLES20.GL_VERTEX_SHADER, mVertexShader));
GLES20.glAttachShader(mProgram,
GLHelper.loadShader(GLES20.GL_FRAGMENT_SHADER, mFragmentShader));
GLES20.glLinkProgram(mProgram);
}
public void draw(float[] mvpMatrix) {
if(mProgram == null) {
if(mVertexShader == null || mFragmentShader == null) {
return;
};
setupShaders();
}
GLES20.glUseProgram(mProgram);
GLHelper.checkGlError("glUseProgram");
int positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
GLHelper.checkGlError("glGetAttribLocation");
GLES20.glEnableVertexAttribArray(positionHandle);
GLHelper.checkGlError("glEnableVertexAttribArray");
GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, getVertexBuffer());
GLHelper.checkGlError("glVertexAttribPointer");
if(mColor != null) {
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
GLHelper.checkGlError("glGetUniformLocation");
GLES20.glUniform4fv(mColorHandle, 1, mColor, 0);
GLHelper.checkGlError("glUniform4fv");
}
int matrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
GLHelper.checkGlError("glGetUniformLocation");
GLES20.glUniformMatrix4fv(matrixHandle, 1, false, mvpMatrix, 0);
GLHelper.checkGlError("glUniformMatrix4fv");
GLES20.glDrawElements(GLES20.GL_TRIANGLES, getIndexBuffer().capacity(), GLES20.GL_UNSIGNED_SHORT, getIndexBuffer());
GLHelper.checkGlError("glDrawElements");
GLES20.glDisableVertexAttribArray(positionHandle);
GLHelper.checkGlError("glDisableVertexAttribArray");
}
protected abstract FloatBuffer getVertexBuffer();
protected abstract ShortBuffer getIndexBuffer();
public void setColor(int color) {
mColor = new float[] {GLColor.r(color), GLColor.g(color), GLColor.b(color), GLColor.a(color)};
if(mVertexShader == null || mFragmentShader == null) {
setShaders(Shaders.COLOR_VERTEX_SHADER, Shaders.COLOR_FRAGMENT_SHADER);
}
}
private void setShaders(String vertexShader, String fragmentShader) {
mVertexShader = vertexShader;
mFragmentShader = fragmentShader;
mProgram = null;
}
}
public class Shaders {
public static final String COLOR_VERTEX_SHADER =
"uniform mat4 uMVPMatrix;\n" +
"attribute vec4 vPosition;\n" +
"void main() {\n" +
" gl_Position = uMVPMatrix * vPosition;\n" +
" gl_PointSize = 10.0;\n" +
"}";
public static final String COLOR_FRAGMENT_SHADER =
"precision mediump float;\n" +
"uniform vec4 vColor;\n" +
"void main() {\n" +
" gl_FragColor = vColor;\n" +
"}";
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
public class Triangle extends Model3D {
private FloatBuffer vertexBuffer;
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 1.0f, 0.0f, // top
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f // bottom right
};
static final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private ShortBuffer indexBuffer;
public Triangle() {
super();
init();
}
private void init() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.asFloatBuffer();
// add the coordinates to the FloatBuffer
vertexBuffer.put(triangleCoords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
indexBuffer = ShortBuffer.allocate(vertexCount);
indexBuffer.put((short)0);
indexBuffer.put((short)1);
indexBuffer.put((short)2);
indexBuffer.rewind();
}
@Override
protected FloatBuffer getVertexBuffer() {
return vertexBuffer;
}
@Override
protected ShortBuffer getIndexBuffer() {
return indexBuffer;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment