/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jo.util.jgl.obj.tri;
import java.util.ArrayList;
import java.util.List;
import jo.util.jgl.JGLColorValues;
import jo.vecmath.Color3f;
import jo.vecmath.Point2f;
import jo.vecmath.Point3f;
import jo.vecmath.logic.Matrix4fLogic;
import jo.vecmath.logic.Point2fLogic;
import jo.vecmath.logic.Point3fLogic;
/**
* A vertex shaded cube.
*/
public class JGLObjHEALPixSphere extends JGLObj {
protected int mVertCount;
protected int mTriCount;
protected int mEdgeSize;
protected boolean mInterior;
/**
* the distance from the center point each point falls on
*/
public float mRadius;
private static final Point3f NORTH_POLE = new Point3f(0, 0, 1);
private static final Point3f NORTH_TROPIC1 = Point3fLogic.rotateNew(Point3fLogic.rotateNew(NORTH_POLE, (float) Math.PI / 4, 0, 0), 0, 0, (float) Math.PI / 4);
private static final Point3f NORTH_TROPIC2 = Point3fLogic.rotateNew(NORTH_TROPIC1, 0, 0, (float) Math.PI / 2);
private static final Point3f NORTH_TROPIC3 = Point3fLogic.rotateNew(NORTH_TROPIC2, 0, 0, (float) Math.PI / 2);
private static final Point3f NORTH_TROPIC4 = Point3fLogic.rotateNew(NORTH_TROPIC3, 0, 0, (float) Math.PI / 2);
private static final Point3f EQUATOR1 = Point3fLogic.rotateNew(NORTH_POLE, (float) Math.PI / 2, 0, 0);
private static final Point3f EQUATOR2 = Point3fLogic.rotateNew(EQUATOR1, 0, 0, (float) Math.PI / 2);
private static final Point3f EQUATOR3 = Point3fLogic.rotateNew(EQUATOR2, 0, 0, (float) Math.PI / 2);
private static final Point3f EQUATOR4 = Point3fLogic.rotateNew(EQUATOR3, 0, 0, (float) Math.PI / 2);
private static final Point3f SOUTH_TROPIC1 = Point3fLogic.rotateNew(Point3fLogic.rotateNew(NORTH_POLE, (float) Math.PI * 3 / 4, 0, 0), 0, 0, (float) Math.PI / 4);
private static final Point3f SOUTH_TROPIC2 = Point3fLogic.rotateNew(SOUTH_TROPIC1, 0, 0, (float) Math.PI / 2);
private static final Point3f SOUTH_TROPIC3 = Point3fLogic.rotateNew(SOUTH_TROPIC2, 0, 0, (float) Math.PI / 2);
private static final Point3f SOUTH_TROPIC4 = Point3fLogic.rotateNew(SOUTH_TROPIC3, 0, 0, (float) Math.PI / 2);
private static final Point3f SOUTH_POLE = new Point3f(0, 0, -1);
private static final float UV_X_0 = 0.0f;
private static final float UV_X_1 = 0.25f;
private static final float UV_X_2 = 0.5f;
private static final float UV_X_3 = 0.75f;
private static final float UV_X_4 = 1.0f;
private static final float UV_Y_0 = 1.0f;
private static final float UV_Y_1 = 2.0f / 3.0f;
private static final float UV_Y_2 = 1.0f / 3.0f;
private static final float UV_Y_3 = 0.0f;
private static final Point2f[][] UV_GRID = {
{new Point2f(UV_X_0, UV_Y_0), new Point2f(UV_X_1, UV_Y_0), new Point2f(UV_X_2, UV_Y_0), new Point2f(UV_X_3, UV_Y_0), new Point2f(UV_X_4, UV_Y_0),},
{new Point2f(UV_X_0, UV_Y_1), new Point2f(UV_X_1, UV_Y_1), new Point2f(UV_X_2, UV_Y_1), new Point2f(UV_X_3, UV_Y_1), new Point2f(UV_X_4, UV_Y_1),},
{new Point2f(UV_X_0, UV_Y_2), new Point2f(UV_X_1, UV_Y_2), new Point2f(UV_X_2, UV_Y_2), new Point2f(UV_X_3, UV_Y_2), new Point2f(UV_X_4, UV_Y_2),},
{new Point2f(UV_X_0, UV_Y_3), new Point2f(UV_X_1, UV_Y_3), new Point2f(UV_X_2, UV_Y_3), new Point2f(UV_X_3, UV_Y_3), new Point2f(UV_X_4, UV_Y_3),},};
private static final Point3f[][] V_FACES = {
{NORTH_POLE, NORTH_TROPIC1, EQUATOR1, NORTH_TROPIC4,}, // 0
{NORTH_POLE, NORTH_TROPIC2, EQUATOR2, NORTH_TROPIC1,}, // 3
{NORTH_POLE, NORTH_TROPIC3, EQUATOR3, NORTH_TROPIC2,}, // 2
{NORTH_POLE, NORTH_TROPIC4, EQUATOR4, NORTH_TROPIC3,}, // 1
{NORTH_TROPIC1, EQUATOR2, SOUTH_TROPIC1, EQUATOR1,}, // 7
{NORTH_TROPIC2, EQUATOR3, SOUTH_TROPIC2, EQUATOR2,}, // 6
{NORTH_TROPIC3, EQUATOR4, SOUTH_TROPIC3, EQUATOR3,}, // 5
{NORTH_TROPIC4, EQUATOR1, SOUTH_TROPIC4, EQUATOR4,}, // 4
{EQUATOR2, SOUTH_TROPIC2, SOUTH_POLE, SOUTH_TROPIC1,}, // 10
{EQUATOR3, SOUTH_TROPIC3, SOUTH_POLE, SOUTH_TROPIC2,}, // 9
{EQUATOR4, SOUTH_TROPIC4, SOUTH_POLE, SOUTH_TROPIC3,}, // 8
{EQUATOR1, SOUTH_TROPIC1, SOUTH_POLE, SOUTH_TROPIC4,}, // 11
};
private static final Point2f[][] UV_FACES = {
{UV_GRID[0][3], UV_GRID[0][4], UV_GRID[1][4], UV_GRID[1][3],}, // 0
{UV_GRID[0][0], UV_GRID[0][1], UV_GRID[1][1], UV_GRID[1][0],}, // 3
{UV_GRID[0][1], UV_GRID[0][2], UV_GRID[1][2], UV_GRID[1][1],}, // 2
{UV_GRID[0][2], UV_GRID[0][3], UV_GRID[1][3], UV_GRID[1][2],}, // 1
{UV_GRID[1][3], UV_GRID[1][4], UV_GRID[2][4], UV_GRID[2][3],}, // 4
{UV_GRID[1][0], UV_GRID[1][1], UV_GRID[2][1], UV_GRID[2][0],}, // 7
{UV_GRID[1][1], UV_GRID[1][2], UV_GRID[2][2], UV_GRID[2][1],}, // 6
{UV_GRID[1][2], UV_GRID[1][3], UV_GRID[2][3], UV_GRID[2][2],}, // 5
{UV_GRID[2][3], UV_GRID[2][4], UV_GRID[3][4], UV_GRID[3][3],}, // 8
{UV_GRID[2][0], UV_GRID[2][1], UV_GRID[3][1], UV_GRID[3][0],}, // 11
{UV_GRID[2][1], UV_GRID[2][2], UV_GRID[3][2], UV_GRID[3][1],}, // 10
{UV_GRID[2][2], UV_GRID[2][3], UV_GRID[3][3], UV_GRID[3][2],}, // 9
};
public JGLObjHEALPixSphere(Point3f size, Point3f center) {
this(2);
Matrix4fLogic.translate(getTransform(), center);
Matrix4fLogic.scale(getTransform(), size);
}
public JGLObjHEALPixSphere(int depth) {
init(depth);
}
private void init(int zSamples) {
mEdgeSize = zSamples;
// allocate vertices
mVertCount = mEdgeSize * mEdgeSize * 12 * 4;
List<Point3f> posBuf = new ArrayList<>();
List<Point3f> normBuf = new ArrayList<>();
List<Point2f> texBuf = new ArrayList<>();
List<Short> idxBuf = new ArrayList<>();
// generate geometry
for (int face = 0; face < 12; face++) {
//System.out.println("Square "+face);
makeSquare(posBuf, normBuf, texBuf,
V_FACES[face][0], V_FACES[face][1], V_FACES[face][2], V_FACES[face][3],
UV_FACES[face][0], UV_FACES[face][1], UV_FACES[face][2], UV_FACES[face][3]
);
}
setIndexData(idxBuf);
setVertices(posBuf);
setNormals(normBuf);
setTextures(texBuf);
setIndices(idxBuf);
List<Color3f> colorBuf = new ArrayList<>();
int vertsPerFace = posBuf.size() / 12;
for (int face = 0; face < 12; face++) {
for (int v = 0; v < vertsPerFace; v++) {
colorBuf.add(JGLColorValues.POINT_COLORS[face]);
}
}
setColors(colorBuf);
//setColors(JGLUtils.rndColors(mVertices, new Point3f(.5f, .5f, .5f), new Point3f(.5f, .5f, .5f)));
// System.out.println("Verts: "+posBuf.size()+" (bytes="+mVertexBuffer.limit()+")");
// System.out.println("Triangles: "+(idxBuf.size()/3));
// for (int i = 0; i < idxBuf.size(); i += 3)
// {
// int i1 = idxBuf.get(i);
// int i2 = idxBuf.get(i+1);
// int i3 = idxBuf.get(i+2);
// System.out.print(" "+i1+"-"+i2+"-"+i3);
// Point3f p1 = posBuf.get(i1);
// Point3f p2 = posBuf.get(i2);
// Point3f p3 = posBuf.get(i3);
// System.out.println(" -> "+p1+"-"+p2+"-"+p3);
// }
}
private static final float E = .0001f;
private void makeSquare(List<Point3f> posBuf, List<Point3f> normBuf, List<Point2f> texBuf,
Point3f top, Point3f right, Point3f bottom, Point3f left,
Point2f uvTop, Point2f uvRight, Point2f uvBottom, Point2f uvLeft) {
//System.out.println("UV: "+uvTop+", "+uvRight+", "+uvBottom+", "+uvLeft);
uvTop = new Point2f(uvTop.x + E, uvTop.y + E);
uvRight = new Point2f(uvRight.x - E, uvRight.y + E);
uvBottom = new Point2f(uvBottom.x - E, uvBottom.y - E);
uvLeft = new Point2f(uvLeft.x + E, uvLeft.y - E);
float pc = 1.0f / mEdgeSize;
for (int j = 0; j < mEdgeSize; j++) {
Point3f rowTopLeft = Point3fLogic.interpolate(top, left, j * pc);
Point3f rowBotLeft = Point3fLogic.interpolate(top, left, (j + 1) * pc);
Point3f rowTopRight = Point3fLogic.interpolate(right, bottom, j * pc);
Point3f rowBotRight = Point3fLogic.interpolate(right, bottom, (j + 1) * pc);
Point2f rowUVTopLeft = Point2fLogic.interpolate(uvTop, uvLeft, j * pc);
Point2f rowUVBotLeft = Point2fLogic.interpolate(uvTop, uvLeft, (j + 1) * pc);
Point2f rowUVTopRight = Point2fLogic.interpolate(uvRight, uvBottom, j * pc);
Point2f rowUVBotRight = Point2fLogic.interpolate(uvRight, uvBottom, (j + 1) * pc);
for (int i = 0; i < mEdgeSize; i++) {
// top
makeVertex(posBuf, normBuf, texBuf,
rowTopLeft, rowTopRight, rowUVTopLeft, rowUVTopRight,
i * pc);
// left
makeVertex(posBuf, normBuf, texBuf,
rowBotLeft, rowBotRight, rowUVBotLeft, rowUVBotRight,
i * pc);
// bottom
makeVertex(posBuf, normBuf, texBuf,
rowBotLeft, rowBotRight, rowUVBotLeft, rowUVBotRight,
(i + 1) * pc);
// right
makeVertex(posBuf, normBuf, texBuf,
rowTopLeft, rowTopRight, rowUVTopLeft, rowUVTopRight,
(i + 1) * pc);
}
}
}
private void makeVertex(List<Point3f> posBuf, List<Point3f> normBuf, List<Point2f> texBuf,
Point3f rowTopLeft, Point3f rowTopRight,
Point2f rowUVTopLeft, Point2f rowUVTopRight,
float pc) {
Point3f pixTopV = Point3fLogic.interpolate(rowTopLeft, rowTopRight, pc);
Point3fLogic.normalize(pixTopV);
Point2f pixTopUV = Point2fLogic.interpolate(rowUVTopLeft, rowUVTopRight, pc);
normBuf.add(pixTopV);
pixTopV.scale(mRadius);
posBuf.add(pixTopV);
texBuf.add(pixTopUV);
//System.out.println("pos="+pixTopV.x+","+pixTopV.y+","+pixTopV.z+"; uv="+pixTopUV.x+","+pixTopUV.y);
}
/**
* sets the indices for rendering the sphere.
*/
private void setIndexData(List<Short> idxBuf) {
// allocate connectivity
mTriCount = mEdgeSize * mEdgeSize * 12 * 2;
// generate connectivity
for (int i = 0; i < mTriCount; i += 2) {
int base = (i / 2) * 4;
idxBuf.add((short) (base + 0));
idxBuf.add((short) (base + 1));
idxBuf.add((short) (base + 2));
idxBuf.add((short) (base + 2));
idxBuf.add((short) (base + 3));
idxBuf.add((short) (base + 0));
}
}
}