1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.openglperf.cts; 18 19 import java.lang.Math; 20 import java.nio.ByteBuffer; 21 import java.nio.ByteOrder; 22 import java.nio.FloatBuffer; 23 import java.nio.ShortBuffer; 24 25 /* 26 * Class for generating a sphere model for given input params 27 * The generated class will have vertices and indices 28 * Vertices data is composed of vertex coordinates in x, y, z followed by 29 * texture coordinates s, t for each vertex 30 * Indices store vertex indices for the whole sphere. 31 * Formula for generating sphere is originally coming from source code of 32 * OpenGL ES2.0 Programming guide 33 * which is available from http://code.google.com/p/opengles-book-samples/, 34 * but some changes were made to make texture look right. 35 */ 36 public class Sphere { 37 public static final int FLOAT_SIZE = 4; 38 public static final int SHORT_SIZE = 2; 39 40 private FloatBuffer mVertices; 41 private ShortBuffer[] mIndices; 42 private int[] mNumIndices; 43 private int mTotalIndices; 44 45 /* 46 * @param nSlices how many slice in horizontal direction. 47 * The same slice for vertical direction is applied. 48 * nSlices should be > 1 and should be <= 180 49 * @param x,y,z the origin of the sphere 50 * @param r the radius of the sphere 51 */ 52 public Sphere(int nSlices, float x, float y, float z, float r, int numIndexBuffers) { 53 54 int iMax = nSlices + 1; 55 int nVertices = iMax * iMax; 56 if (nVertices > Short.MAX_VALUE) { 57 // this cannot be handled in one vertices / indices pair 58 throw new RuntimeException("nSlices " + nSlices + " too big for vertex"); 59 } 60 mTotalIndices = nSlices * nSlices * 6; 61 float angleStepI = ((float) Math.PI / nSlices); 62 float angleStepJ = ((2.0f * (float) Math.PI) / nSlices); 63 64 // 3 vertex coords + 2 texture coords 65 mVertices = ByteBuffer.allocateDirect(nVertices * 5 * FLOAT_SIZE) 66 .order(ByteOrder.nativeOrder()).asFloatBuffer(); 67 mIndices = new ShortBuffer[numIndexBuffers]; 68 mNumIndices = new int[numIndexBuffers]; 69 // first evenly distribute to n-1 buffers, then put remaining ones to the last one. 70 int noIndicesPerBuffer = (mTotalIndices / numIndexBuffers / 6) * 6; 71 for (int i = 0; i < numIndexBuffers - 1; i++) { 72 mNumIndices[i] = noIndicesPerBuffer; 73 } 74 mNumIndices[numIndexBuffers - 1] = mTotalIndices - noIndicesPerBuffer * 75 (numIndexBuffers - 1); 76 77 for (int i = 0; i < numIndexBuffers; i++) { 78 mIndices[i] = ByteBuffer.allocateDirect(mNumIndices[i] * SHORT_SIZE) 79 .order(ByteOrder.nativeOrder()).asShortBuffer(); 80 } 81 // calling put for each float took too much CPU time, so put by line instead 82 float[] vLineBuffer = new float[iMax * 5]; 83 for (int i = 0; i < iMax; i++) { 84 for (int j = 0; j < iMax; j++) { 85 int vertexBase = j * 5; 86 float sini = (float) Math.sin(angleStepI * i); 87 float sinj = (float) Math.sin(angleStepJ * j); 88 float cosi = (float) Math.cos(angleStepI * i); 89 float cosj = (float) Math.cos(angleStepJ * j); 90 // vertex x,y,z 91 vLineBuffer[vertexBase + 0] = x + r * sini * sinj; 92 vLineBuffer[vertexBase + 1] = y + r * sini * cosj; 93 vLineBuffer[vertexBase + 2] = z + r * cosi; 94 // texture s,t 95 vLineBuffer[vertexBase + 3] = (float) j / (float) nSlices; 96 vLineBuffer[vertexBase + 4] = (1.0f - i) / (float)nSlices; 97 } 98 mVertices.put(vLineBuffer, 0, vLineBuffer.length); 99 } 100 101 short[] indexBuffer = new short[max(mNumIndices)]; 102 int index = 0; 103 int bufferNum = 0; 104 for (int i = 0; i < nSlices; i++) { 105 for (int j = 0; j < nSlices; j++) { 106 int i1 = i + 1; 107 int j1 = j + 1; 108 if (index >= mNumIndices[bufferNum]) { 109 // buffer ready for moving to target 110 mIndices[bufferNum].put(indexBuffer, 0, mNumIndices[bufferNum]); 111 // move to the next one 112 index = 0; 113 bufferNum++; 114 } 115 indexBuffer[index++] = (short) (i * iMax + j); 116 indexBuffer[index++] = (short) (i1 * iMax + j); 117 indexBuffer[index++] = (short) (i1 * iMax + j1); 118 indexBuffer[index++] = (short) (i * iMax + j); 119 indexBuffer[index++] = (short) (i1 * iMax + j1); 120 indexBuffer[index++] = (short) (i * iMax + j1); 121 } 122 } 123 mIndices[bufferNum].put(indexBuffer, 0, mNumIndices[bufferNum]); 124 125 mVertices.position(0); 126 for (int i = 0; i < numIndexBuffers; i++) { 127 mIndices[i].position(0); 128 } 129 } 130 131 public FloatBuffer getVertices() { 132 return mVertices; 133 } 134 135 public int getVeticesStride() { 136 return 5*FLOAT_SIZE; 137 } 138 139 public ShortBuffer[] getIndices() { 140 return mIndices; 141 } 142 143 public int[] getNumIndices() { 144 return mNumIndices; 145 } 146 147 public int getTotalIndices() { 148 return mTotalIndices; 149 } 150 151 152 private int max(int[] array) { 153 int max = array[0]; 154 for (int i = 1; i < array.length; i++) { 155 if (array[i] > max) max = array[i]; 156 } 157 return max; 158 } 159 } 160