package com.arretadogames.pilot.render.opengl; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import javax.microedition.khronos.opengles.GL10; import android.graphics.Color; import android.opengl.GLES11; public class GLCircle { private static final int DEFAULT_NUM_SEGMENTS = 60; // Minimum: 3 (Triangle) private FloatBuffer vertexBuffer; private ShortBuffer indexBuffer; private int numSegments; public GLCircle(float radius) { this(radius, DEFAULT_NUM_SEGMENTS); } public GLCircle() { this(1, DEFAULT_NUM_SEGMENTS); } public GLCircle(float radius, int segments) { numSegments = segments; // Creating Vertices short indices[] = new short[(numSegments * 3)]; int indicesIndex = 0; float vertices[] = new float[(numSegments + 1) * 3]; int verticesIndex = 0; // Center of the Circle vertices[verticesIndex++] = 0; // x vertices[verticesIndex++] = 0; // y vertices[verticesIndex++] = 0; // z for (int i = 0 ; i < numSegments ; i++) { double theta = 2 * Math.PI * i / numSegments; vertices[verticesIndex++] = (float) (radius * Math.cos(theta)); vertices[verticesIndex++] = (float) (radius * Math.sin(theta)); vertices[verticesIndex++] = 0; // z } // Triangulating for (int i = 2 ; i < segments + 1 ; i++) { // Adding a +1 because 0 vertex is the center indices[indicesIndex++] = 0; // Center indices[indicesIndex++] = (short) i; // Current Segment Vertex indices[indicesIndex++] = (short) (i - 1); // Previous Segment Vertex } // Last Triangle indices[indicesIndex++] = 0; // Center indices[indicesIndex++] = 1; // First indices[indicesIndex++] = (short) (Math.floor(verticesIndex / 3.0) - 1); // Last Circle Segment // Creating Buffers ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); vbb.order(ByteOrder.nativeOrder()); vertexBuffer = vbb.asFloatBuffer(); vertexBuffer.put(vertices); createIndicesBuffer(indices); indexBuffer.position(0); vertexBuffer.position(0); } // default draw public void drawCircle(GLCanvas gl, float x, float y, int color, int lineWidth, boolean filled) { drawCircle(gl, x, y, color, filled, lineWidth, 0, numSegments); } // percent: 0 to 100 public void drawCircle(GLCanvas gl, float x, float y, int color, boolean filled, int lineWidth, int percent) { drawCircle(gl, x, y, color, filled, lineWidth, 0, percent * numSegments / 100); } // fromsegment - starting segment to draw // tosegment - last segment to draw public void drawCircle(GLCanvas gl, float x, float y, int color, boolean filled, int lineWidth, int fromSegment, int toSegment) { if (fromSegment > toSegment || fromSegment < 0 || toSegment > numSegments) throw new IllegalArgumentException("Error in segment parameter while drawing circle"); indexBuffer.position(fromSegment * 3); vertexBuffer.position(0); gl.saveState(); gl.translate(x, y); gl.rotate(-90); // Hack to start from top GLES11.glColor4f(Color.red(color) / 255f, Color.green(color) / 255f, Color.blue(color) / 255f, Color.alpha(color) / 255f); if (filled) { // Draw GLES11.glEnableClientState(GL10.GL_VERTEX_ARRAY); GLES11.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); // Sets Vertex Buffer GLES11.glDrawElements(GL10.GL_TRIANGLES, (toSegment - fromSegment) * 3, GL10.GL_UNSIGNED_SHORT, indexBuffer); // Sets Index Buffer GLES11.glEnableClientState(GL10.GL_VERTEX_ARRAY); } else { vertexBuffer.position(fromSegment * 3 + 3); // Jump Center GLLine.drawLineStrip(vertexBuffer, (toSegment - fromSegment), lineWidth, color, (toSegment == numSegments && fromSegment == 0)); } // Reset Color GLES11.glColor4f(1, 1, 1, 1); gl.restoreState(); } private void createIndicesBuffer(short[] indices) { ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2); ibb.order(ByteOrder.nativeOrder()); indexBuffer = ibb.asShortBuffer(); indexBuffer.put(indices); indexBuffer.position(0); } }