/*
UVSphere.java
Copyright (c) 2015 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.theta.opengl.model;
import android.opengl.GLES20;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
/**
* UV sphere model class.
*
* @author NTT DOCOMO, INC.
*/
public class UVSphere {
private final int COORDS_PER_VERTEX = 3;
private final int TEXTURE_COORDS_PER_VERTEX = 2;
private int mStrips;
private int mStripePointsNum;
private ArrayList<FloatBuffer> mVertices;
private ArrayList<FloatBuffer> mTextureCoords;
private final int vertexStride = COORDS_PER_VERTEX * 4;
private final int textureStride = TEXTURE_COORDS_PER_VERTEX * 4;
private final float mRadius;
/**
* Constructor
* Sphere is displayed according to the number of partitions.
* The longitude is created from the number of partitions which is half the number of
* latitude lines 1 and the number of polygons which is double the number of
* partitions set in the radius specified as the origin coordinates.
*
* @param radius Radius
* @param divide Number of partitions (must be an even number)
*/
public UVSphere(float radius, int divide) {
mVertices = new ArrayList<FloatBuffer>();
mTextureCoords = new ArrayList<FloatBuffer>();
mRadius = radius;
if (radius <= 0 || divide <= 0 || 0 != (divide % 2)) {
throw new IllegalArgumentException();
}
mStrips = divide / 2;
mStripePointsNum = (divide + 1) * 2;
makeSphereVertices(radius, divide);
}
public float getRadius() {
return mRadius;
}
/**
* Sphere drawing method
*
* @param mPositionHandle Handler value tied to gl_Position in vertex shader
* @param mUVHandle Handler value tied to the UV coordinates provided to the fragment shader via the varyig variable
*/
public void draw(int mPositionHandle, int mUVHandle) {
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glEnableVertexAttribArray(mUVHandle);
for (int i = 0; i < mStrips; i++) {
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, mVertices.get(i));
GLES20.glVertexAttribPointer(mUVHandle, TEXTURE_COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, textureStride, mTextureCoords.get(i));
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, mStripePointsNum);
}
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mUVHandle);
}
private void makeSphereVertices(float radius, int divide) {
float altitude = 0.0f;
float altitudeDelta = 0.0f;
float azimuth = 0.0f;
float ex = 0.0f;
float ey = 0.0f;
float ez = 0.0f;
for (int i = 0; i < divide / 2; ++i) {
altitude = (float) (Math.PI / 2.0 - i * (Math.PI * 2) / divide);
altitudeDelta = (float) (Math.PI / 2.0 - (i + 1) * (Math.PI * 2) / divide);
float[] vertices = new float[divide * 6 + 6];
float[] texCoords = new float[divide * 4 + 4];
for (int j = 0; j <= divide; ++j) {
azimuth = (float) (Math.PI - (j * (Math.PI * 2) / divide));
// first point
ex = (float) (Math.cos(altitudeDelta) * Math.cos(azimuth));
ey = (float) Math.sin(altitudeDelta);
ez = (float) (Math.cos(altitudeDelta) * Math.sin(azimuth));
vertices[6 * j + 0] = radius * ex;
vertices[6 * j + 1] = radius * ey;
vertices[6 * j + 2] = radius * ez;
texCoords[4 * j + 0] = 1.0f - (j / (float) divide);
texCoords[4 * j + 1] = 2 * (i + 1) / (float) divide;
// second point
ex = (float) (Math.cos(altitude) * Math.cos(azimuth));
ey = (float) Math.sin(altitude);
ez = (float) (Math.cos(altitude) * Math.sin(azimuth));
vertices[6 * j + 3] = radius * ex;
vertices[6 * j + 4] = radius * ey;
vertices[6 * j + 5] = radius * ez;
texCoords[4 * j + 2] = 1.0f - (j / (float) divide);
texCoords[4 * j + 3] = 2 * i / (float) divide;
}
mVertices.add(makeFloatBufferFromArray(vertices));
mTextureCoords.add(makeFloatBufferFromArray(texCoords));
}
return;
}
private FloatBuffer makeFloatBufferFromArray(float[] array) {
FloatBuffer fb = ByteBuffer.allocateDirect(array.length * Float.SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
fb.put(array);
fb.position(0);
return fb;
}
}