package org.geogebra.common.geogebra3D.euclidian3D.openGL;
import org.geogebra.common.geogebra3D.euclidian3D.openGL.ManagerShaders.TypeElement;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.Matrix.Coords3;
import org.geogebra.common.util.debug.Log;
public class PlotterSurfaceElements extends PlotterSurface {
final private static boolean DEBUG = false;
final private static void debug(String s) {
if (DEBUG) {
Log.debug(s);
}
}
private int latitudeMin;
private int latitude;
private int latitudeMax;
private int latitudeMaxTop;
private int latitudeMaxBottom;
private interface DrawEllipticSurface {
public void drawNCr(Coords normal);
public void drawNCrm(Coords normal);
/**
* compute radius and z for given latitude
*
* @param v
* current latitude
* @param latitudeLength
* latitude length
* @param rz
* radius and z return
*/
public void computeRadiusAndZ(int v, int latitudeLength, double[] rz);
/**
*
* @return true if we draw poles
*/
public boolean drawPoles();
/**
*
* @param latitudeLength
* latitude length
* @param longitudeLength
* TODO
* @return next jump for latitude length
*/
public int initNextJump(int latitudeLength, int longitudeLength);
/**
*
* @param nextJump
* current value
* @param latitudeLength
* latitude length
* @return updated value for next jump
*/
public int updateNextJump(int nextJump, int latitudeLength);
/**
*
* @return true if we draw equator
*/
public boolean drawEquator();
/**
*
* @param vi
* latitude index
* @return true if we draw top part at vi (normals and vertices)
*/
public boolean drawTop(int vi);
/**
*
* @param vi
* latitude index
* @return true if we draw bottom part at vi (normals and vertices)
*/
public boolean drawBottom(int vi);
/**
*
* @return north pole
*/
public Coords getNorthPole();
}
private class DrawSphere implements DrawEllipticSurface {
private PlotterSurface surface;
private Coords center;
private double radius;
protected DrawSphere() {
}
public void set(PlotterSurface surface, Coords center, double radius) {
this.surface = surface;
this.center = center;
this.radius = radius;
}
@Override
public void drawNCr(Coords normal) {
surface.drawNCr(normal, center, radius);
}
@Override
public void drawNCrm(Coords normal) {
surface.drawNCrm(normal, center, radius);
}
@Override
public void computeRadiusAndZ(int v, int latitudeLength, double[] rz) {
PlotterSurface.cosSin(v, latitudeLength, rz);
}
@Override
public boolean drawPoles() {
return true;
}
@Override
public Coords getNorthPole() {
return Coords.VZ;
}
@Override
public int initNextJump(int latitudeLength, int longitudeLength) {
return (int) (latitudeLength / Math.PI);
}
@Override
public int updateNextJump(int nextJump, int latitudeLength) {
return nextJump / 2;
}
@Override
public boolean drawEquator() {
return true;
}
@Override
public boolean drawTop(int vi) {
return vi < latitudeMaxTop;
}
@Override
public boolean drawBottom(int vi) {
return vi < latitudeMaxBottom;
}
}
private class DrawEllipsoid implements DrawEllipticSurface {
private PlotterSurface surface;
private Coords center;
private Coords ev0, ev1, ev2;
private double r0, r1, r2;
private Coords c = Coords.createInhomCoorsInD3();
private Coords n = new Coords(4);
private Coords tmpCoords = new Coords(4);
protected DrawEllipsoid() {
}
public void set(PlotterSurface surface, Coords center, Coords ev0,
Coords ev1, Coords ev2, double r0, double r1, double r2) {
this.surface = surface;
this.center = center;
this.ev0 = ev0;
this.ev1 = ev1;
this.ev2 = ev2;
this.r0 = r0;
this.r1 = r1;
this.r2 = r2;
}
@Override
public void drawNCr(Coords normal) {
c.setValues(center, 3);
tmpCoords.setMul(ev0, r0 * normal.getX());
c.addInside(tmpCoords);
tmpCoords.setMul(ev1, r1 * normal.getY());
c.addInside(tmpCoords);
tmpCoords.setMul(ev2, r2 * normal.getZ());
c.addInside(tmpCoords);
n.setMul(ev0, r1 * r2 * normal.getX());
tmpCoords.setMul(ev1, r0 * r2 * normal.getY());
n.addInside(tmpCoords);
tmpCoords.setMul(ev2, r0 * r1 * normal.getZ());
n.addInside(tmpCoords);
n.normalize();
surface.drawNV(n, c);
}
@Override
public void drawNCrm(Coords normal) {
c.setValues(center, 3);
tmpCoords.setMul(ev0, r0 * normal.getX());
c.addInside(tmpCoords);
tmpCoords.setMul(ev1, r1 * normal.getY());
c.addInside(tmpCoords);
tmpCoords.setMul(ev2, -r2 * normal.getZ());
c.addInside(tmpCoords);
n.setMul(ev0, r1 * r2 * normal.getX());
tmpCoords.setMul(ev1, r0 * r2 * normal.getY());
n.addInside(tmpCoords);
tmpCoords.setMul(ev2, -r0 * r1 * normal.getZ());
n.addInside(tmpCoords);
n.normalize();
surface.drawNV(n, c);
}
@Override
public void computeRadiusAndZ(int v, int latitudeLength, double[] rz) {
PlotterSurface.cosSin(v, latitudeLength, rz);
}
@Override
public boolean drawPoles() {
return true;
}
@Override
public Coords getNorthPole() {
return Coords.VZ;
}
@Override
public int initNextJump(int latitudeLength, int longitudeLength) {
return (int) (latitudeLength / Math.PI);
}
@Override
public int updateNextJump(int nextJump, int latitudeLength) {
return nextJump / 2;
}
@Override
public boolean drawEquator() {
return true;
}
@Override
public boolean drawTop(int vi) {
return vi < latitudeMaxTop;
}
@Override
public boolean drawBottom(int vi) {
return vi < latitudeMaxBottom;
}
}
private class DrawHyperboloidOneSheet implements DrawEllipticSurface {
protected PlotterSurface surface;
protected Coords center;
protected Coords ev0, ev1, ev2;
protected double r0, r1, r2;
protected double min;
protected double max;
protected double jump;
private int longitudeJumps;
protected boolean fading;
protected Coords c = Coords.createInhomCoorsInD3();
protected Coords n = new Coords(4);
protected Coords tmpCoords = new Coords(4);
protected DrawHyperboloidOneSheet() {
}
public void set(PlotterSurface surface, Coords center, Coords ev0,
Coords ev1, Coords ev2, double r0, double r1, double r2,
boolean fading) {
this.surface = surface;
this.center = center;
this.ev0 = ev0;
this.ev1 = ev1;
this.ev2 = ev2;
this.r0 = r0;
this.r1 = r1;
this.r2 = r2;
this.fading = fading;
}
protected double maxFadingStartTop, maxFadingEndTop, middleFading,
maxFadingStartBottom, maxFadingEndBottom;
public void setMinMax(double min, double max) {
if (min < 0) {
if (max > 0) {
this.min = 0;
this.max = Math.max(-min, max);
} else {
this.min = -max;
this.max = -min;
}
} else {
this.min = min;
this.max = max;
}
if (fading) {
double shMin = Math.sinh(min);
double shMax = Math.sinh(max);
middleFading = (shMax + shMin) / 2;
maxFadingStartTop = shMax * 0.9 + shMin * 0.1;
maxFadingEndTop = shMax;
maxFadingStartBottom = shMax * 0.1 + shMin * 0.9;
maxFadingEndBottom = shMin;
}
// Log.debug(maxFading + "," + max);
// use asymptotic behavior of cosh() for (un)refine radius
jump = Math.log(2) / max;
}
@Override
public void drawNCr(Coords normal) {
double z = normal.getZ();
c.setValues(center, 3);
tmpCoords.setMul(ev0, -r0 * normal.getX());
c.addInside(tmpCoords);
tmpCoords.setMul(ev1, r1 * normal.getY());
c.addInside(tmpCoords);
tmpCoords.setMul(ev2, r2 * z);
c.addInside(tmpCoords);
n.setMul(ev0, -r1 * r2 * normal.getX());
tmpCoords.setMul(ev1, r0 * r2 * normal.getY());
n.addInside(tmpCoords);
tmpCoords.setMul(ev2, -r0 * r1 * z);
n.addInside(tmpCoords);
n.normalize();
if (fading) {
if (z > middleFading) {
manager.texture(0, (z - maxFadingStartTop)
/ (maxFadingEndTop - maxFadingStartTop));
} else {
manager.texture(0, (z - maxFadingStartBottom)
/ (maxFadingEndBottom - maxFadingStartBottom));
}
}
surface.drawNV(n, c);
}
@Override
public void drawNCrm(Coords normal) {
double z = -normal.getZ();
c.setValues(center, 3);
tmpCoords.setMul(ev0, -r0 * normal.getX());
c.addInside(tmpCoords);
tmpCoords.setMul(ev1, r1 * normal.getY());
c.addInside(tmpCoords);
tmpCoords.setMul(ev2, r2 * z);
c.addInside(tmpCoords);
n.setMul(ev0, -r1 * r2 * normal.getX());
tmpCoords.setMul(ev1, r0 * r2 * normal.getY());
n.addInside(tmpCoords);
tmpCoords.setMul(ev2, -r0 * r1 * z);
n.addInside(tmpCoords);
n.normalize();
if (fading) {
if (z < middleFading) {
manager.texture(0, (z - maxFadingStartBottom)
/ (maxFadingEndBottom - maxFadingStartBottom));
} else {
manager.texture(0, (z - maxFadingStartTop)
/ (maxFadingEndTop - maxFadingStartTop));
}
}
surface.drawNV(n, c);
}
@Override
public void computeRadiusAndZ(int vi, int latitudeLength, double[] rz) {
double v = computeV(vi, latitudeLength);
rz[0] = Math.cosh(v);
rz[1] = Math.sinh(v);
}
private double computeV(int vi, int latitudeLength) {
return min + ((double) (latitudeLength - vi - 1)
/ (latitudeLength - 2)) * (max - min);
}
@Override
public boolean drawPoles() {
return false;
}
@Override
public Coords getNorthPole() {
return null; // no pole here
}
@Override
public int initNextJump(int latitudeLength, int longitudeLength) {
// if (jump > 1) {
// return 0;
// }
// int ret = (int) (jump * latitudeLength);
// if (ret < 2) { // avoid jump after first step
// return 0;
// }
// ret = latitudeLength - ret;
// // asymptotic (un)refine works when x > 2
// if (ret * max < 2 * latitudeLength) {
// return 0;
// }
// longitudeJumps = longitudeLength;
// Log.debug(longitudeLength + "," + latitudeLength + "," + ret);
// return ret;
return 0;
}
@Override
public int updateNextJump(int nextJump, int latitudeLength) {
if (longitudeJumps <= 8) { // avoid not enough longitudes
return 0;
}
longitudeJumps /= 2;
int ret = ((int) (nextJump - jump * latitudeLength));
if (ret < 0) {
return 0;
}
// asymptotic (un)refine works when x > 2
if (ret * max < 2 * latitudeLength) {
return 0;
}
return ret;
}
@Override
public boolean drawEquator() {
return false;
}
@Override
public boolean drawTop(int vi) {
return vi >= latitudeMaxTop;
}
@Override
public boolean drawBottom(int vi) {
return vi >= latitudeMaxBottom;
}
}
private class DrawHyperboloidTwoSheets extends DrawHyperboloidOneSheet {
protected DrawHyperboloidTwoSheets() {
}
@Override
public void setMinMax(double min, double max) {
if (min < 0) {
if (max > 0) {
this.min = 0;
this.max = Math.max(-min, max);
} else {
this.min = -max;
this.max = -min;
}
} else {
this.min = min;
this.max = max;
}
if (fading) {
double chMin;
if (Kernel.isZero(min)) {
chMin = 0;
} else {
chMin = Math.cosh(min);
if (min < 0) {
chMin = -chMin;
}
}
double chMax;
if (Kernel.isZero(max)) {
chMax = 0;
} else {
chMax = Math.cosh(max);
if (max < 0) {
chMax = -chMax;
}
}
middleFading = (chMax + chMin) / 2;
maxFadingStartTop = chMax * 0.9 + chMin * 0.1;
maxFadingEndTop = chMax;
maxFadingStartBottom = chMax * 0.1 + chMin * 0.9;
maxFadingEndBottom = chMin;
}
// use asymptotic behavior of cosh() for (un)refine radius
jump = Math.log(2) / max;
}
@Override
public void computeRadiusAndZ(int vi, int latitudeLength, double[] rz) {
double v = computeV(vi, latitudeLength);
rz[0] = Math.sinh(v);
rz[1] = Math.cosh(v);
}
private double computeV(int vi, int latitudeLength) {
return min + ((double) (latitudeLength - vi) / (latitudeLength - 2))
* (max - min);
}
@Override
public boolean drawPoles() {
return true;
}
@Override
public Coords getNorthPole() {
return Coords.VZ;
}
}
private class DrawParaboloid extends DrawHyperboloidOneSheet {
protected DrawParaboloid() {
}
@Override
public void setMinMax(double min, double max) {
this.min = min;
this.max = max;
if (fading) {
if (Kernel.isZero(min)) {
middleFading = 0;
maxFadingEndTop = max * max;
maxFadingStartTop = maxFadingEndTop * 0.9;
maxFadingStartBottom = 0;
maxFadingEndBottom = 0;
} else {
double min2 = min * min;
double max2 = max * max;
middleFading = (min2 + max2) / 2;
maxFadingStartTop = max2 * 0.9 + min2 * 0.1;
maxFadingEndTop = max2;
maxFadingStartBottom = max2 * 0.1 + min2 * 0.9;
maxFadingEndBottom = min2;
}
}
// use asymptotic behavior of cosh() for (un)refine radius
jump = Math.log(2) / max;
}
@Override
public void drawNCr(Coords normal) {
double z = normal.getZ();
c.setValues(center, 3);
tmpCoords.setMul(ev0, -r0 * normal.getX());
c.addInside(tmpCoords);
tmpCoords.setMul(ev1, r1 * normal.getY());
c.addInside(tmpCoords);
tmpCoords.setMul(ev2, r2 * z);
c.addInside(tmpCoords);
n.setMul(ev0, -2 * r1 * r2 * normal.getX());
tmpCoords.setMul(ev1, 2 * r0 * r2 * normal.getY());
n.addInside(tmpCoords);
tmpCoords.setMul(ev2, -r0 * r1);
n.addInside(tmpCoords);
n.normalize();
if (fading) {
if (z > middleFading) {
manager.texture(0, (z - maxFadingStartTop)
/ (maxFadingEndTop - maxFadingStartTop));
} else {
manager.texture(0, (z - maxFadingStartBottom)
/ (maxFadingEndBottom - maxFadingStartBottom));
}
}
surface.drawNV(n, c);
}
@Override
public void computeRadiusAndZ(int vi, int latitudeLength, double[] rz) {
double v = computeV(vi, latitudeLength);
rz[0] = v;
rz[1] = v * v;
}
private double computeV(int vi, int latitudeLength) {
return min + ((double) (latitudeLength - vi) / (latitudeLength - 2))
* (max - min);
}
@Override
public boolean drawPoles() {
return min == 0;
}
@Override
public Coords getNorthPole() {
return Coords.O;
}
@Override
public boolean drawTop(int vi) {
return vi >= latitudeMaxTop;
}
@Override
public boolean drawBottom(int vi) {
return false;
}
}
public PlotterSurfaceElements(Manager manager) {
super(manager);
}
@Override
public void drawSphere(Coords center, double radius, int longitude,
double longitudeStart, int longitudeLength, double frustumRadius) {
startGeometry();
// set texture to (0,0)
manager.setDummyTexture();
setLatitudeMinMaxForEllipsoid(center, radius, longitude, frustumRadius);
if (drawSphere == null) {
drawSphere = new DrawSphere();
}
drawSphere.set(this, center, radius);
drawNV(drawSphere, longitude, longitudeStart, longitudeLength);
setIndices(longitude, longitudeLength, drawSphere);
}
private void startGeometry() {
manager.startGeometry(Manager.Type.TRIANGLES);
// manager.getRenderer().setLineWidth(1);
// manager.startGeometry(Manager.Type.LINE_STRIP);
}
private void setLatitudeMinMaxForEllipsoid(Coords center, double radius,
int longitude, double frustumRadius) {
latitude = longitude / 4;
// check which parts are visible (latitudes)
Coords o = manager.getView3D().getCenter();
double z = center.getZ();
double zMin = o.getZ() - frustumRadius;
double zMax = o.getZ() + frustumRadius;
latitudeMaxTop = latitude;
if (Kernel.isGreater(z + radius, zMax)) {
double angle = Math.asin((zMax - z) / radius);
latitudeMaxTop = (int) (latitude * 2 * angle / Math.PI) + 2;
}
latitudeMaxBottom = latitude;
if (Kernel.isGreater(zMin, z - radius)) {
double angle = Math.asin((z - zMin) / radius);
latitudeMaxBottom = (int) (latitude * 2 * angle / Math.PI) + 2;
}
// debug(latitudeMaxBottom+","+latitudeMaxTop);
latitudeMax = Math.max(latitudeMaxTop, latitudeMaxBottom);
if (latitudeMax > latitude) {
latitudeMax = latitude;
}
latitudeMin = 0; // start on equator
if (latitudeMaxTop < 0) { // start below equator
latitudeMin = -latitudeMaxTop;
} else if (latitudeMaxBottom < 0) { // start above equator
latitudeMin = -latitudeMaxBottom;
}
// prevent too close values
if (latitudeMin + 1 >= latitudeMax) {
if (latitudeMax >= 2) {
latitudeMin = latitudeMax - 2;
} else {
latitudeMax = latitudeMin + 2;
}
}
// Log.debug(latitudeMin + "," + latitudeMax + "," + latitudeMaxBottom
// + "," + latitudeMaxTop + "," + latitude);
}
private void setLatitudeMinMaxForHyperboloid(double min, double max,
DrawHyperboloidOneSheet dhos) {
if (min < 0) {
if (max > 0) {
if (-min > max) {// more bottom than top
latitudeMaxTop = (int) (latitude * (1 - max / (-min)));
if (latitudeMaxTop == 1) {
latitudeMaxTop = 2; // ensure at least a strip is drawn
}
latitudeMaxBottom = 0;
} else { // more top than bottom
latitudeMaxTop = 0;
latitudeMaxBottom = (int) (latitude * (1 - (-min) / max));
if (latitudeMaxBottom == 1) {
latitudeMaxBottom = 2; // ensure at least a strip is
// drawn
}
}
latitudeMax = latitude;
latitudeMin = 0;
dhos.setMinMax(min, max);
} else {
// only bottom
latitudeMaxTop = latitude;
latitudeMaxBottom = 0;
latitudeMax = latitude;
latitudeMin = 0;
dhos.setMinMax(min, max);
}
} else {
// only top
latitudeMaxTop = 0;
latitudeMaxBottom = latitude;
latitudeMax = latitude;
latitudeMin = 0;
dhos.setMinMax(min, max);
}
// Log.debug("min=" + min + ", max=" + max + "," + latitudeMin + ","
// + latitudeMax + "," + latitudeMaxBottom + "," + latitudeMaxTop
// + "," + latitude);
}
private void setLatitudeMinMaxForParaboloid(double min, double max,
DrawParaboloid dp) {
// only top
latitudeMaxTop = 0;
latitudeMaxBottom = latitude;
latitudeMax = latitude;
latitudeMin = 0;
dp.setMinMax(min, max);
}
private Coords n;
private DrawSphere drawSphere;
private void drawNV(DrawEllipticSurface dse, int longitude,
double longitudeStart, int longitudeLength) {
// start drawing
if (n == null) {
n = new Coords(4);
}
// values for radius and z at each latitude
double[] rz = new double[2];
debug("longitude = " + longitude + " , longitudeLength = "
+ longitudeLength);
short lastLength, currentLength;
boolean drawTop, drawBottom;
int vi, nextJump, next;
short shift;
// ///////////////
// draw vertices
// first latitude
if (dse.drawEquator()) {
dse.computeRadiusAndZ(latitudeMin, latitude, rz);
for (int ui = 0; ui < longitudeLength; ui++) {
sphericalCoords(ui, longitude, longitudeStart, rz, n);
dse.drawNCr(n);
}
}
arrayIndex = 0;
lastLength = (short) longitudeLength;
currentLength = (short) longitudeLength;
// both = 1 if only drawing up or down, both = 2 if drawing both
drawTop = true;
drawBottom = true;
vi = latitudeMin + 1;
nextJump = dse.initNextJump(latitude, longitude);
debug("latitude : " + latitude + " , latitude-nextJump : "
+ (latitude - nextJump));
next = 0;
shift = 1;
while (next < latitudeMax) {
next = Math.min(latitudeMax, latitude - nextJump);
debug("latitude : " + latitude + " , latitudeMin : " + latitudeMin
+ " , next : " + next + " , latitudeMax : " + latitudeMax);
while (next < latitudeMin + 2) {
nextJump = dse.updateNextJump(nextJump, latitude);
next = Math.min(latitudeMax, latitude - nextJump);
debug(">> next : " + next);
}
// until next jump
while (vi < next) {
drawTop = dse.drawTop(vi);
drawBottom = dse.drawBottom(vi);
dse.computeRadiusAndZ(vi, latitude, rz);
for (int ui = 0; ui < longitudeLength; ui += shift) {
sphericalCoords(ui, longitude, longitudeStart, rz, n);
if (drawTop) {// top vertices
dse.drawNCr(n);
}
if (drawBottom) {// bottom vertices
dse.drawNCrm(n);
}
}
debug("vi : " + vi);
lastLength = currentLength;
if (drawTop) {// top triangles
if (longitudeLength == longitude) {
arrayIndex += 6 * lastLength;
} else {
arrayIndex += 6 * (lastLength - 1);
}
}
if (drawBottom) {// bottom triangles
if (longitudeLength == longitude) {
arrayIndex += 6 * lastLength;
} else {
arrayIndex += 6 * (lastLength - 1);
}
}
vi++;
}
// jump
if (next < latitudeMax) {
shift *= 2;
dse.computeRadiusAndZ(vi, latitude, rz);
for (int ui = 0; ui < longitudeLength; ui += shift) {
sphericalCoords(ui, longitude, longitudeStart, rz, n);
if (drawTop) {// top vertices
dse.drawNCr(n);
}
if (drawBottom) {// bottom vertices
dse.drawNCrm(n);
}
}
lastLength = currentLength;
currentLength /= 2;
if (drawTop) {// top triangles
if (longitudeLength == longitude) {
arrayIndex += 9 * currentLength;
} else {
arrayIndex += 9 * (currentLength - 1);
}
}
if (drawBottom) {// bottom triangles
if (longitudeLength == longitude) {
arrayIndex += 9 * currentLength;
} else {
arrayIndex += 9 * (currentLength - 1);
}
}
vi++;
nextJump = dse.updateNextJump(nextJump, latitude);
}
}
lastLength = currentLength;
if (dse.drawPoles()) {
// north pole
if (latitudeMax == latitude) {
if (drawTop) {
dse.drawNCr(dse.getNorthPole());
if (longitudeLength == longitude) {
arrayIndex += 3 * lastLength;
} else {
arrayIndex += 3 * (lastLength - 1);
}
}
// south pole
if (drawBottom) {
dse.drawNCrm(dse.getNorthPole());
if (longitudeLength == longitude) {
arrayIndex += 3 * lastLength;
} else {
arrayIndex += 3 * (lastLength - 1);
}
}
}
}
debug("==== arrayIndex (1) = " + arrayIndex);
}
private void setIndices(int longitude, int longitudeLength,
DrawEllipticSurface dse) {
// ///////////////
// set indices
arrayI = manager.getCurrentGeometryIndices(arrayIndex);
arrayIndex = 0;
short lastStartIndex = 0;
short lastLength = (short) longitudeLength;
short currentStartIndex = lastStartIndex;
short currentLength = (short) longitudeLength;
// both = 1 if only drawing up or down, both = 2 if drawing both
boolean drawTop = true;
boolean drawBottom = true;
boolean lastDrawTop = true;
boolean lastDrawBottom = true;
short lastBoth = 1;
short both = 2;
int vi = latitudeMin + 1;
if (dse.drawEquator()) {
both = 1; // we use the same vertices
} else {
vi++; // we start after equator
if (latitudeMaxTop > 0) {
drawTop = false;
both = 1;
} else if (latitudeMaxBottom > 0) {
drawBottom = false;
both = 1;
}
}
int nextJump = dse.initNextJump(latitude, longitude);
debug("latitude : " + latitude + " , latitude-nextJump : "
+ (latitude - nextJump));
int next = 0;
while (next < latitudeMax) {
next = Math.min(latitudeMax, latitude - nextJump);
debug("latitude : " + latitude + " , latitudeMin : " + latitudeMin
+ " , next : " + next + " , latitudeMax : " + latitudeMax);
while (next < latitudeMin + 2) {
nextJump = dse.updateNextJump(nextJump, latitude);
next = Math.min(latitudeMax, latitude - nextJump);
debug(">> next : " + next);
}
// until next jump
while (vi < next) {
lastDrawTop = drawTop;
lastDrawBottom = drawBottom;
drawTop = dse.drawTop(vi);
drawBottom = dse.drawBottom(vi);
lastBoth = both;
both = 0;
if (drawTop) {// top vertices
both++;
}
if (drawBottom) {// bottom vertices
both++;
}
debug("vi : " + vi + " -- both : " + both);
lastStartIndex = currentStartIndex;
lastLength = currentLength;
currentStartIndex += lastLength * lastBoth;
if (lastDrawTop && drawTop) {// top triangles
short currentIndex = currentStartIndex;
short lastIndex;
for (lastIndex = lastStartIndex; lastIndex < currentStartIndex
- lastBoth; lastIndex += lastBoth) {
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put((short) (currentIndex + both));
arrayIndex++;
currentIndex += both;
}
if (longitudeLength == longitude) {
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put(lastStartIndex);
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put(lastStartIndex);
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
}
}
// shift to draw also bottom
if (lastBoth == 2) {
lastStartIndex += 1;
}
if (both == 2) {
currentStartIndex += 1;
}
if (lastDrawBottom && drawBottom) {// bottom triangles
short currentIndex = currentStartIndex;
short lastIndex;
for (lastIndex = lastStartIndex; lastIndex < currentStartIndex
- both; lastIndex += lastBoth) {
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put((short) (currentIndex + both));
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
currentIndex += both;
}
if (longitudeLength == longitude) {
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put(lastStartIndex);
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
arrayI.put(lastStartIndex);
arrayIndex++;
}
}
// shift back
if (lastBoth == 2) {
lastStartIndex -= 1;
}
if (both == 2) {
currentStartIndex -= 1;
}
vi++;
}
// jump
if (next < latitudeMax) {
lastBoth = both;
lastStartIndex = currentStartIndex;
lastLength = currentLength;
currentStartIndex += lastLength * lastBoth;
currentLength /= 2;
if (lastDrawTop && drawTop) {// top triangles
short currentIndex = currentStartIndex;
short lastIndex;
for (lastIndex = lastStartIndex; lastIndex < currentStartIndex
- 2 * lastBoth; lastIndex += 2 * lastBoth) {
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put((short) (lastIndex + 2 * lastBoth));
arrayIndex++;
arrayI.put((short) (currentIndex + both));
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put((short) (currentIndex + both));
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
currentIndex += both;
}
if (longitudeLength == longitude) {
// close the parallel
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(lastStartIndex);
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
}
// shift for maybe draw bottom
lastStartIndex += 1;
currentStartIndex += 1;
}
if (lastDrawBottom && drawBottom) {// bottom triangles
short currentIndex = currentStartIndex;
short lastIndex;
for (lastIndex = lastStartIndex; lastIndex < currentStartIndex
- 2 * lastBoth; lastIndex += 2 * lastBoth) {
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put((short) (currentIndex + both));
arrayIndex++;
arrayI.put((short) (lastIndex + 2 * lastBoth));
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put((short) (currentIndex + both));
arrayIndex++;
currentIndex += both;
}
if (longitudeLength == longitude) {
// close the parallel
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
arrayI.put(lastStartIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(currentIndex);
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
}
}
if (drawTop) {
// shift back
lastStartIndex -= 1;
currentStartIndex -= 1;
}
vi++;
nextJump = dse.updateNextJump(nextJump, latitude);
}
}
lastBoth = both;
lastStartIndex = currentStartIndex;
lastLength = currentLength;
currentStartIndex += lastLength * lastBoth;
if (dse.drawPoles()) {
// north pole
if (latitudeMax == latitude) {
if (drawTop) {
short lastIndex;
for (lastIndex = lastStartIndex; lastIndex < currentStartIndex
- lastBoth; lastIndex += lastBoth) {
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
}
if (longitudeLength == longitude) {
// close the parallel
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put(lastStartIndex);
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
}
// shift for maybe south pole
lastStartIndex += 1;
currentStartIndex += 1;
}
// south pole
if (drawBottom) {
short lastIndex;
for (lastIndex = lastStartIndex; lastIndex < currentStartIndex
- lastBoth; lastIndex += lastBoth) {
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
arrayI.put((short) (lastIndex + lastBoth));
arrayIndex++;
}
if (longitudeLength == longitude) {
// close the parallel
arrayI.put(lastIndex);
arrayIndex++;
arrayI.put(currentStartIndex);
arrayIndex++;
arrayI.put(lastStartIndex);
arrayIndex++;
}
}
}
}
debug("==== arrayIndex (2) = " + arrayIndex);
arrayI.rewind();
manager.endGeometry(arrayIndex, TypeElement.SURFACE);
}
private DrawEllipsoid drawEllipsoid;
@Override
public void drawEllipsoid(Coords center, Coords ev0, Coords ev1, Coords ev2,
double r0, double r1, double r2, int longitude) {
startGeometry();
// set texture to (0,0)
manager.setDummyTexture();
double r = Math.max(r0, Math.max(r1, r2));
setLatitudeMinMaxForEllipsoid(center, r, longitude,
manager.getView3D().getFrustumRadius());
if (drawEllipsoid == null) {
drawEllipsoid = new DrawEllipsoid();
}
drawEllipsoid.set(this, center, ev0, ev1, ev2, r0, r1, r2);
drawNV(drawEllipsoid, longitude, 0, longitude);
setIndices(longitude, longitude, drawEllipsoid);
}
private DrawHyperboloidOneSheet drawHyperboloidOneSheet;
@Override
public void drawHyperboloidOneSheet(Coords center, Coords ev0, Coords ev1,
Coords ev2, double r0, double r1, double r2, int longitude,
double min, double max, boolean fading) {
startGeometry();
if (!fading) {
manager.setDummyTexture();
}
if (drawHyperboloidOneSheet == null) {
drawHyperboloidOneSheet = new DrawHyperboloidOneSheet();
}
drawHyperboloidOneSheet.set(this, center, ev0, ev1, ev2, r0, r1, r2,
fading);
latitude = 32; // 32 seems to be ok in any case
setLatitudeMinMaxForHyperboloid(min, max, drawHyperboloidOneSheet);
drawNV(drawHyperboloidOneSheet, longitude, 0, longitude);
setIndices(longitude, longitude, drawHyperboloidOneSheet);
}
private DrawHyperboloidTwoSheets drawHyperboloidTwoSheets;
@Override
public void drawHyperboloidTwoSheets(Coords center, Coords ev0, Coords ev1,
Coords ev2, double r0, double r1, double r2, int longitude,
double min, double max, boolean fading) {
startGeometry();
if (!fading) {
manager.setDummyTexture();
}
if (drawHyperboloidTwoSheets == null) {
drawHyperboloidTwoSheets = new DrawHyperboloidTwoSheets();
}
drawHyperboloidTwoSheets.set(this, center, ev0, ev1, ev2, r0, r1, r2,
fading);
latitude = 16; // 16 seems to be ok in any case
setLatitudeMinMaxForHyperboloid(min, max, drawHyperboloidTwoSheets);
drawNV(drawHyperboloidTwoSheets, longitude, 0, longitude);
setIndices(longitude, longitude, drawHyperboloidTwoSheets);
}
private DrawParaboloid drawParaboloid;
@Override
public void drawParaboloid(Coords center, Coords ev0, Coords ev1,
Coords ev2, double r0, double r1, int longitude, double min,
double max, boolean fading) {
startGeometry();
if (!fading) {
manager.setDummyTexture();
}
if (drawParaboloid == null) {
drawParaboloid = new DrawParaboloid();
}
drawParaboloid.set(this, center, ev0, ev1, ev2, r0, r1, 1, fading);
latitude = 32; // 32 seems to be ok in any case
setLatitudeMinMaxForParaboloid(min, max, drawParaboloid);
drawNV(drawParaboloid, longitude, 0, longitude);
setIndices(longitude, longitude, drawParaboloid);
}
private double maxFadingStartTop, maxFadingEndTop, middleFading,
maxFadingStartBottom, maxFadingEndBottom;
@Override
public void drawParabolicCylinder(Coords center, Coords ev0, Coords ev1,
Coords ev2, double r, double min, double max, double lineMin,
double lineMax, boolean fading) {
center1.setAdd(center, tmpCoords.setMul(ev1, lineMin));
center2.setAdd(center, tmpCoords.setMul(ev1, lineMax));
if (n == null) {
n = new Coords(4);
}
double lineFading = 0;
if (fading) {
if (Kernel.isZero(min)) {
maxFadingEndTop = max * max;
maxFadingStartTop = maxFadingEndTop * 0.9;
middleFading = -1;
maxFadingStartBottom = 0;
maxFadingEndBottom = 0;
} else {
double min2 = min * min;
double max2 = max * max;
middleFading = (min2 + max2) / 2;
maxFadingStartTop = max2 * 0.9 + min2 * 0.1;
maxFadingEndTop = max2;
maxFadingStartBottom = max2 * 0.1 + min2 * 0.9;
maxFadingEndBottom = min2;
}
lineFading = -8; // TODO preferences
}
latitude = 16;
// set geometry
startGeometry();
if (min == 0) {
n.setMul(ev0, -1);
if (fading) {
manager.texture(1, 0);
}
drawNV(n, center1);
if (fading) { // we need an intermediate vertex for texture
manager.texture(lineFading, 0);
drawNV(n, center);
}
if (fading) {
manager.texture(1, 0);
}
drawNV(n, center2);
}
for (int vi = 1; vi <= latitude; vi++) {
double v = min + ((max - min) * vi) / latitude;
double z = v * v;
double zFading = 0;
if (fading) {
if (z > middleFading) {
zFading = (z - maxFadingStartTop)
/ (maxFadingEndTop - maxFadingStartTop);
} else {
zFading = (z - maxFadingStartBottom)
/ (maxFadingEndBottom - maxFadingStartBottom);
}
}
tmpCoords2.setMul(ev2, r * v);
tmpCoords3.setMul(ev0, z);
// v > 0
tmpCoords.setMul(ev0, -r);
n.setMul(ev2, 2 * v);
n.setAdd(tmpCoords, n);
n.normalize();
m.setAdd(center1, tmpCoords2);
m.setAdd(m, tmpCoords3);
if (fading) {
manager.texture(1, zFading);
}
drawNV(n, m);
if (fading) {
m.setAdd(center, tmpCoords2);
m.setAdd(m, tmpCoords3);
manager.texture(lineFading, zFading);
drawNV(n, m);
}
m.setAdd(center2, tmpCoords2);
m.setAdd(m, tmpCoords3);
if (fading) {
manager.texture(1, zFading);
}
drawNV(n, m);
// v < 0
n.setMul(ev2, -2 * v);
n.setAdd(tmpCoords, n);
n.normalize();
m.setSub(center1, tmpCoords2);
m.setAdd(m, tmpCoords3);
if (fading) {
manager.texture(1, zFading);
}
drawNV(n, m);
if (fading) {
m.setSub(center, tmpCoords2);
m.setAdd(m, tmpCoords3);
manager.texture(lineFading, zFading);
drawNV(n, m);
}
m.setSub(center2, tmpCoords2);
m.setAdd(m, tmpCoords3);
if (fading) {
manager.texture(1, zFading);
}
drawNV(n, m);
}
// set indices
if (min == 0) {
arrayIndex = latitude * 12;
} else {
arrayIndex = (latitude - 1) * 12;
}
if (fading) {
arrayIndex *= 2;
}
arrayI = manager.getCurrentGeometryIndices(arrayIndex);
short index = 0;
if (fading) {
if (min == 0) {
arrayI.put(index);
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 5));
arrayI.put(index);
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 8));
arrayI.put((short) (index + 7));
index += 3;
}
for (int vi = 1; vi < latitude; vi++) {
arrayI.put(index);
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 8));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 9));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 10));
arrayI.put((short) (index + 9));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 5));
arrayI.put((short) (index + 10));
arrayI.put((short) (index + 5));
arrayI.put((short) (index + 11));
arrayI.put((short) (index + 10));
index += 6;
}
} else {
if (min == 0) {
arrayI.put(index);
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 3));
arrayI.put(index);
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 5));
arrayI.put((short) (index + 4));
index += 2;
}
for (int vi = 1; vi < latitude; vi++) {
arrayI.put(index);
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 5));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 6));
index += 4;
}
}
arrayI.rewind();
manager.endGeometry(arrayIndex, TypeElement.SURFACE);
}
@Override
public void drawHyperbolicCylinder(Coords center, Coords ev0, Coords ev1,
Coords ev2, double r1, double r2, double min0, double max,
double lineMin, double lineMax, boolean fading) {
double min;
if (min0 < 0) {
min = 0;
} else {
min = min0;
}
center1.setAdd(center, tmpCoords.setMul(ev2, lineMin));
center2.setAdd(center, tmpCoords.setMul(ev2, lineMax));
if (n == null) {
n = new Coords(4);
}
double lineFading = 0;
if (fading) {
if (min > 0) {
double shMin = Math.sinh(min0);
double shMax = Math.sinh(max);
middleFading = (shMax + shMin) / 2;
maxFadingStartTop = shMax * 0.9 + shMin * 0.1;
maxFadingEndTop = shMax;
maxFadingStartBottom = shMax * 0.1 + shMin * 0.9;
maxFadingEndBottom = shMin;
} else {
double shMax = Math.sinh(max);
middleFading = -1;
maxFadingStartTop = shMax * 0.9;
maxFadingEndTop = shMax;
maxFadingStartBottom = -1;
maxFadingEndBottom = -1;
}
lineFading = -8; // TODO preferences
}
latitude = 16;
// set geometry
startGeometry();
if (!fading) {
manager.setDummyTexture();
}
if (min <= 0) {
n.setMul(ev0, -1);
tmpCoords2.setMul(ev0, r1);
if (fading) {
manager.texture(1, 0);
}
m.setAdd(center1, tmpCoords2);
drawNV(n, m);
if (fading) { // we need an intermediate vertex for texture
manager.texture(lineFading, 0);
m.setAdd(center, tmpCoords2);
drawNV(n, m);
}
if (fading) {
manager.texture(1, 0);
}
m.setAdd(center2, tmpCoords2);
drawNV(n, m);
}
for (int vi = 1; vi <= latitude; vi++) {
double v = min + ((max - min) * vi) / latitude;
double c = Math.cosh(v);
double s = Math.sinh(v);
double sFading = 0;
if (fading) {
if (s > middleFading) {
sFading = (s - maxFadingStartTop)
/ (maxFadingEndTop - maxFadingStartTop);
} else {
sFading = (s - maxFadingStartBottom)
/ (maxFadingEndBottom - maxFadingStartBottom);
}
}
tmpCoords2.setMul(ev0, r1 * c);
tmpCoords3.setMul(ev1, r2 * s);
// > 0
tmpCoords.setMul(ev0, -r2 * c);
n.setMul(ev1, r1 * s);
n.setAdd(tmpCoords, n);
n.normalize();
m.setAdd(center1, tmpCoords2);
m.setAdd(m, tmpCoords3);
if (fading) {
manager.texture(1, sFading);
}
drawNV(n, m);
if (fading) {
m.setAdd(center, tmpCoords2);
m.setAdd(m, tmpCoords3);
manager.texture(lineFading, sFading);
drawNV(n, m);
}
m.setAdd(center2, tmpCoords2);
m.setAdd(m, tmpCoords3);
if (fading) {
manager.texture(1, sFading);
}
drawNV(n, m);
// < 0
n.setMul(ev1, -r1 * s);
n.setAdd(tmpCoords, n);
n.normalize();
m.setAdd(center1, tmpCoords2);
m.setSub(m, tmpCoords3);
if (fading) {
manager.texture(1, sFading);
}
drawNV(n, m);
if (fading) {
m.setAdd(center, tmpCoords2);
m.setSub(m, tmpCoords3);
manager.texture(lineFading, sFading);
drawNV(n, m);
}
m.setAdd(center2, tmpCoords2);
m.setSub(m, tmpCoords3);
if (fading) {
manager.texture(1, sFading);
}
drawNV(n, m);
}
// set indices
if (min <= 0) {
arrayIndex = latitude * 12;
} else {
arrayIndex = (latitude - 1) * 12;
}
if (fading) {
arrayIndex *= 2;
}
arrayI = manager.getCurrentGeometryIndices(arrayIndex);
short index = 0;
if (fading) {
if (min <= 0) {
arrayI.put(index);
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 5));
arrayI.put((short) (index + 4));
arrayI.put(index);
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 8));
index += 3;
}
for (int vi = 1; vi < latitude; vi++) {
arrayI.put(index);
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 8));
arrayI.put((short) (index + 7));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 9));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 9));
arrayI.put((short) (index + 10));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 10));
arrayI.put((short) (index + 5));
arrayI.put((short) (index + 5));
arrayI.put((short) (index + 10));
arrayI.put((short) (index + 11));
index += 6;
}
} else {
if (min <= 0) {
arrayI.put(index);
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 2));
arrayI.put(index);
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 5));
index += 2;
}
for (int vi = 1; vi < latitude; vi++) {
arrayI.put(index);
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 1));
arrayI.put((short) (index + 5));
arrayI.put((short) (index + 4));
arrayI.put((short) (index + 2));
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 3));
arrayI.put((short) (index + 6));
arrayI.put((short) (index + 7));
index += 4;
}
}
arrayI.rewind();
manager.endGeometry(arrayIndex, TypeElement.SURFACE);
}
@Override
public void drawHyperbolicParaboloid(Coords center, Coords ev0, Coords ev1,
Coords ev2, double r0, double r1, double min0, double max0,
double min1, double max1, boolean fading) {
latitude = 64;
startGeometry();
if (!fading) {
manager.setDummyTexture();
}
if (n == null) {
n = new Coords(4);
}
for (int ui = 0; ui <= latitude; ui++) {
double u = min0 + ui * (max0 - min0) / latitude;
tmpCoords.setMul(ev0, u);
tmpCoords.setAdd(center, tmpCoords);
tmpCoords3.setMul(ev0, 2 * r0 * u);
double uFading = 0;
if (fading) {
if (ui < latitude / 2) {
uFading = 1 - ui * 20.0 / latitude;
} else {
uFading = 1 - (latitude - ui) * 20.0 / latitude;
}
}
for (int vi = 0; vi <= latitude; vi++) {
double v = min1 + vi * (max1 - min1) / latitude;
tmpCoords2.setMul(ev1, v);
m.setAdd(tmpCoords, tmpCoords2);
tmpCoords2.setMul(ev2, r0 * u * u + r1 * v * v);
m.setAdd(m, tmpCoords2);
n.setMul(ev1, 2 * r0 * u);
n.setAdd(n, tmpCoords3);
n.setAdd(n, Coords.VZm);
n.normalize();
if (fading) {
double vFading;
if (vi < latitude / 2) {
vFading = 1 - vi * 20.0 / latitude;
} else {
vFading = 1 - (latitude - vi) * 20.0 / latitude;
}
manager.texture(uFading, vFading);
}
drawNV(n, m);
}
}
// set indices
arrayIndex = latitude * latitude * 6;
arrayI = manager.getCurrentGeometryIndices(arrayIndex);
short uIndex = 0;
for (int ui = 0; ui < latitude; ui++) {
for (int vi = 0; vi < latitude; vi++) {
arrayI.put((short) (uIndex + vi));
arrayI.put((short) (uIndex + vi + 1));
arrayI.put((short) (uIndex + latitude + 1 + vi));
arrayI.put((short) (uIndex + latitude + 1 + vi));
arrayI.put((short) (uIndex + vi + 1));
arrayI.put((short) (uIndex + latitude + 1 + vi + 1));
}
uIndex += latitude + 1;
}
arrayI.rewind();
manager.endGeometry(arrayIndex, TypeElement.SURFACE);
}
private int arrayIndex = 0;
private GLBufferIndices arrayI;
@Override
public void startTriangles(int size) {
manager.startGeometry(Manager.Type.TRIANGLES);
manager.setDummyTexture();
arrayIndex = 0;
arrayI = manager.getCurrentGeometryIndices(size);
}
@Override
public void vertexDirect(Coords3 p) {
manager.vertexToScale(p.getXf(), p.getYf(), p.getZf());
}
@Override
public void normalDirect(Coords3 n) {
manager.normal(n.getXf(), n.getYf(), n.getZf());
}
@Override
public void endGeometryDirect() {
arrayI.rewind();
manager.endGeometry(arrayIndex, TypeElement.SURFACE);
}
/**
* @param id
* vertex normal id
*/
public void drawIndex(int id) {
arrayI.put((short) id);
arrayIndex++;
}
}