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      */
Sphere(int nSlices, float x, float y, float z, float r, int numIndexBuffers)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 
getVertices()131     public FloatBuffer getVertices() {
132         return mVertices;
133     }
134 
getVeticesStride()135     public int getVeticesStride() {
136         return 5*FLOAT_SIZE;
137     }
138 
getIndices()139     public ShortBuffer[] getIndices() {
140         return mIndices;
141     }
142 
getNumIndices()143     public int[] getNumIndices() {
144         return mNumIndices;
145     }
146 
getTotalIndices()147     public int getTotalIndices() {
148         return mTotalIndices;
149     }
150 
151 
max(int[] array)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