/*
* JAME 6.2.1
* http://jame.sourceforge.net
*
* Copyright 2001, 2016 Andrea Medeghini
*
* This file is based on code from idx3dIII
* Copyright 1999, 2000 Peter Walser
* http://www.idx3d.ch/idx3d/idx3d.html
*
* This file is part of JAME.
*
* JAME is an application for creating fractals and other graphics artifacts.
*
* JAME is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JAME is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JAME. If not, see <http://www.gnu.org/licenses/>.
*
*/
package net.sf.jame.core.media.g3d;
public final class SolidFactory {
private SolidFactory() {
}
public static Part FIELD(final String name, final int xresolution, final int yresolution, final float xsize, final float ysize, final boolean single) {
final float[][] data = new float[xresolution][yresolution];
for (int i = 0; i < xresolution; i++) {
for (int j = 0; j < yresolution; j++) {
data[i][j] = 0;
}
}
return SolidFactory.HEIGHTFIELD(name, data, xsize, ysize, single);
}
public static Part HEIGHTFIELD(final String name, final Texture heightmap, final float height, final int xresolution, final int yresolution, final float xsize, final float ysize, final boolean single) {
final float[][] data = new float[xresolution][yresolution];
final float vx = (float) heightmap.width / (float) xresolution;
final float vy = (float) heightmap.height / (float) yresolution;
for (int j = 0; j < yresolution; j++) {
for (int i = 0; i < xresolution; i++) {
data[i][j] = ((Color.getAverage(heightmap.pixels[((int) (vy * j) * heightmap.width) + (int) (vx * i)]) - 127) / 127f) * height;
}
}
return SolidFactory.HEIGHTFIELD(name, data, xsize, ysize, single);
}
public static Part HEIGHTFIELD(final String name, final float[][] data, final float xsize, final float ysize, final boolean single) {
final Part part = new Part(name);
Vertex vertex = null;
int q1;
int q2;
int q3;
int q4;
float x;
float y;
float u;
float v;
final int xresolution = data.length;
final int yresolution = data[0].length;
final float xscale = 1f / (xresolution - 1);
final float yscale = 1f / (yresolution - 1);
for (int i = 0; i < xresolution; i++) {
u = (float) i / (float) (xresolution - 1);
x = ((xscale * i) - 0.5f) * xsize;
for (int j = 0; j < yresolution; j++) {
v = (float) j / (float) (yresolution - 1);
y = (0.5f - (yscale * j)) * ysize;
vertex = new Vertex(x, y, data[i][j]);
vertex.u = u;
vertex.v = v;
part.addVertex(vertex);
}
}
for (int i = 0; i < (xresolution - 1); i++) {
for (int j = 0; j < (yresolution - 1); j++) {
q1 = j + (yresolution * i);
q2 = q1 + 1;
q3 = q1 + yresolution;
q4 = q2 + yresolution;
part.addTriangle(single, q1, q2, q3);
part.addTriangle(single, q2, q4, q3);
}
}
return part;
}
public static Part CUBE(final String name, final int resolution, final float size, final boolean single) {
return SolidFactory.BOX(name, resolution, resolution, resolution, size, size, size, single);
}
/*
* public static Part BOX(String name,float xsize,float ysize,float zsize,boolean single) { Part part = new Part(name); float x = (float)Math.abs(xsize / 2f); float y = (float)Math.abs(ysize / 2f); float z = (float)Math.abs(zsize / 2f); int[] xflag = new int[6]; int[] yflag = new int[6]; int[] zflag = new int[6]; xflag[0] = 10; yflag[0] = 3; zflag[0] = 0; xflag[1] = 10; yflag[1] = 15; zflag[1] = 3; xflag[2] = 15; yflag[2] = 3; zflag[2] = 10; xflag[3] = 10; yflag[3] = 0; zflag[3] = 12; xflag[4] = 0; yflag[4] = 3; zflag[4] = 5; xflag[5] = 5; yflag[5] = 3; zflag[5] = 15; float xx; float yy; float zz; for (int side = 0; side < 6; side++) { for (int i = 0; i < 4; i++) { xx = ((xflag[side] & (1 << i)) > 0) ? +x : -x; yy = ((yflag[side] & (1 << i)) > 0) ? +y : -y; zz = ((zflag[side] & (1 << i)) > 0) ? +z : -z; part.addVertex(xx,yy,zz,i & 1,(i & 2) >> 1); } int j = side << 2; part.addTriangle(single,j,j + 2,j + 3); part.addTriangle(single,j,j + 3,j + 1); } return part; }
*/
public static Part BOX(final String name, final int xresolution, final int yresolution, final int zresolution, final float xsize, final float ysize, final float zsize, final boolean single) {
final Part part = new Part(name);
Vertex vertex = null;
int q1;
int q2;
int q3;
int q4;
float x;
float y;
float z;
float u;
float v;
final float xscale = 1f / (xresolution - 1);
final float yscale = 1f / (yresolution - 1);
final float zscale = 1f / (zresolution - 1);
int offset = 0;
z = -0.5f * zsize;
for (int i = 0; i < xresolution; i++) {
u = (float) i / (float) (xresolution - 1);
x = ((xscale * i) - 0.5f) * xsize;
for (int j = 0; j < yresolution; j++) {
v = (float) j / (float) (yresolution - 1);
y = (0.5f - (yscale * j)) * ysize;
vertex = new Vertex(x, y, z);
vertex.u = u;
vertex.v = v;
part.addVertex(vertex);
}
}
for (int i = 0; i < (xresolution - 1); i++) {
for (int j = 0; j < (yresolution - 1); j++) {
q1 = offset + j + (yresolution * i);
q2 = q1 + 1;
q3 = q1 + yresolution;
q4 = q2 + yresolution;
part.addTriangle(single, q1, q2, q3);
part.addTriangle(single, q3, q2, q4);
}
}
offset += (xresolution * yresolution);
z = -z;
for (int i = 0; i < xresolution; i++) {
u = (float) i / (float) (xresolution - 1);
x = (0.5f - (xscale * i)) * xsize;
for (int j = 0; j < yresolution; j++) {
v = (float) j / (float) (yresolution - 1);
y = (0.5f - (yscale * j)) * ysize;
vertex = new Vertex(x, y, z);
vertex.u = u;
vertex.v = v;
part.addVertex(vertex);
}
}
for (int i = 0; i < (xresolution - 1); i++) {
for (int j = 0; j < (yresolution - 1); j++) {
q1 = offset + j + (yresolution * i);
q2 = q1 + 1;
q3 = q1 + yresolution;
q4 = q2 + yresolution;
part.addTriangle(single, q1, q2, q3);
part.addTriangle(single, q3, q2, q4);
}
}
offset += (xresolution * yresolution);
x = -0.5f * xsize;
for (int i = 0; i < zresolution; i++) {
u = (float) (zresolution - 1 - i) / (float) (zresolution - 1);
z = ((zscale * i) - 0.5f) * zsize;
for (int j = 0; j < yresolution; j++) {
v = (float) (yresolution - 1 - j) / (float) (yresolution - 1);
y = ((yscale * j) - 0.5f) * ysize;
vertex = new Vertex(x, y, z);
vertex.u = u;
vertex.v = v;
part.addVertex(vertex);
}
}
for (int i = 0; i < (zresolution - 1); i++) {
for (int j = 0; j < (yresolution - 1); j++) {
q1 = offset + j + (yresolution * i);
q2 = q1 + 1;
q3 = q1 + yresolution;
q4 = q2 + yresolution;
part.addTriangle(single, q1, q2, q3);
part.addTriangle(single, q3, q2, q4);
}
}
offset += (zresolution * yresolution);
x = -x;
for (int i = 0; i < zresolution; i++) {
u = (float) i / (float) (zresolution - 1);
z = ((zscale * i) - 0.5f) * zsize;
for (int j = 0; j < yresolution; j++) {
v = (float) j / (float) (yresolution - 1);
y = (0.5f - (yscale * j)) * ysize;
vertex = new Vertex(x, y, z);
vertex.u = u;
vertex.v = v;
part.addVertex(vertex);
}
}
for (int i = 0; i < (zresolution - 1); i++) {
for (int j = 0; j < (yresolution - 1); j++) {
q1 = offset + j + (yresolution * i);
q2 = q1 + 1;
q3 = q1 + yresolution;
q4 = q2 + yresolution;
part.addTriangle(single, q1, q2, q3);
part.addTriangle(single, q3, q2, q4);
}
}
offset += (zresolution * yresolution);
y = -0.5f * ysize;
for (int i = 0; i < zresolution; i++) {
u = (float) i / (float) (zresolution - 1);
z = ((zscale * i) - 0.5f) * zsize;
for (int j = 0; j < xresolution; j++) {
v = (float) j / (float) (xresolution - 1);
x = (0.5f - (xscale * j)) * xsize;
vertex = new Vertex(x, y, z);
vertex.u = u;
vertex.v = v;
part.addVertex(vertex);
}
}
for (int i = 0; i < (zresolution - 1); i++) {
for (int j = 0; j < (xresolution - 1); j++) {
q1 = offset + j + (xresolution * i);
q2 = q1 + 1;
q3 = q1 + xresolution;
q4 = q2 + xresolution;
part.addTriangle(single, q1, q2, q3);
part.addTriangle(single, q3, q2, q4);
}
}
offset += (zresolution * xresolution);
y = -y;
for (int i = 0; i < zresolution; i++) {
u = (float) i / (float) (zresolution - 1);
z = (0.5f - (zscale * i)) * zsize;
for (int j = 0; j < xresolution; j++) {
v = (float) j / (float) (xresolution - 1);
x = (0.5f - (xscale * j)) * xsize;
vertex = new Vertex(x, y, z);
vertex.u = u;
vertex.v = v;
part.addVertex(vertex);
}
}
for (int i = 0; i < (zresolution - 1); i++) {
for (int j = 0; j < (xresolution - 1); j++) {
q1 = offset + j + (+xresolution * i);
q2 = q1 + 1;
q3 = q1 + xresolution;
q4 = q2 + xresolution;
part.addTriangle(single, q1, q2, q3);
part.addTriangle(single, q3, q2, q4);
}
}
return part;
}
public static Part CONE(final String name, final float height, final float radius, final int sides, final boolean single) {
final Vector[] path = new Vector[3];
final float h = height / 2f;
path[0] = new Vector(0, +h, 0);
path[1] = new Vector(radius, -h, 0);
path[2] = new Vector(0, -h, 0);
return SolidFactory.ROTATIONOBJECT(name, path, sides, single);
}
public static Part CYLINDER(final String name, final float height, final float radius, final int sides, final boolean single) {
final Vector[] path = new Vector[4];
final float h = height / 2f;
path[0] = new Vector(0, +h, 0);
path[1] = new Vector(radius, +h, 0);
path[2] = new Vector(radius, -h, 0);
path[3] = new Vector(0, -h, 0);
return SolidFactory.ROTATIONOBJECT(name, path, sides, single);
}
public static Part SPHERE(final String name, final float radius, final int sides, final boolean single) {
final Vector[] path = new Vector[sides + 1];
float x;
float y;
final float step = -3.14159265f / sides;
float angle = (0.5f * 3.14159265f) + step;
path[0] = new Vector(0, +radius, 0);
for (int i = 1; i < sides; i++) {
x = Math.cos(angle) * radius;
y = Math.sin(angle) * radius;
path[i] = new Vector(x, y, 0);
angle += step;
}
path[sides] = new Vector(0, -radius, 0);
return SolidFactory.ROTATIONOBJECT(name, path, sides, single);
}
public static Part ROTATIONOBJECT(final String name, final Vector[] path, final int sides, final boolean single) {
final Part part = new Part(name);
Vertex vertex = null;
int q1;
int q2;
int q3;
int q4;
float x;
float z;
float u;
float v;
final int steps = sides + 1;
final int nodes = path.length;
final float step = -(2f * 3.14159265f) / sides;
float alpha = 0;
for (int j = 0; j < steps; j++) {
u = (float) j / (float) (steps - 1);
for (int i = 0; i < nodes; i++) {
v = (float) i / (float) (nodes - 1);
x = ((path[i].x * Math.cos(alpha)) + (path[i].z * Math.sin(alpha)));
z = ((path[i].z * Math.cos(alpha)) - (path[i].x * Math.sin(alpha)));
vertex = new Vertex(x, path[i].y, z);
vertex.u = u;
vertex.v = v;
part.addVertex(vertex);
}
alpha += step;
}
for (int j = 0; j < (steps - 1); j++) {
for (int i = 0; i < (nodes - 1); i++) {
q1 = i + (nodes * j);
q2 = q1 + 1;
q3 = q1 + nodes;
q4 = q2 + nodes;
part.addTriangle(single, q1, q2, q3);
part.addTriangle(single, q3, q2, q4);
}
}
for (int i = 0; i < (nodes - 1); i++) {
q1 = i + (nodes * (steps - 1));
q2 = q1 + 1;
q3 = i;
q4 = q3 + 1;
part.addTriangle(single, q1, q2, q3);
part.addTriangle(single, q3, q2, q4);
}
return part;
}
public static Part TORUS(final String name, final float radius, final float size, final int segments, final int sides, final boolean single) {
final Vector[] circle = new Vector[segments + 1];
final float step = (2f * 3.14159265f) / segments;
float angle = 0;
for (int i = 0; i < (segments + 1); i++) {
circle[i] = new Vector(radius * Math.cos(angle), radius * Math.sin(angle), 0f);
angle += step;
}
return SolidFactory.TUBE(name, circle, size, sides, true, single);
}
public static Part TUBE(final String name, final Vector[] path, final float radius, final int sides, final boolean closed, final boolean single) {
final Vector[] circle = new Vector[sides + 1];
final float step = (2f * 3.14159265f) / sides;
float angle = 0;
for (int i = 0; i < (sides + 1); i++) {
circle[i] = new Vector(radius * Math.cos(angle), radius * Math.sin(angle), 0f);
angle += step;
}
return SolidFactory.EXTRUSIONOBJECT(name, path, circle, closed, single);
}
public static Part EXTRUSIONOBJECT(final String name, final Vector[] path, final Vector[] shape, final boolean closed, final boolean single) {
final Part part = new Part(name);
Vector forward;
Vector up;
Vector right;
Matrix frenetmatrix;
Vertex vertex;
int q1;
int q2;
int q3;
int q4;
float u;
float v;
final int segments = path.length;
final int sides = shape.length;
for (int i = 0; i < segments; i++) {
if (i != (segments - 1)) {
forward = Vector.sub(path[i + 1], path[i]);
}
else {
if (!closed) {
forward = Vector.sub(path[i], path[i - 1]);
}
else {
forward = Vector.sub(path[1], path[0]);
}
}
forward.normalize();
up = new Vector(0f, 0f, 1f);
right = Vector.normal(forward, up);
up = Vector.normal(forward, right);
frenetmatrix = new Matrix(right, up, forward);
frenetmatrix.shift(path[i].x, path[i].y, path[i].z);
v = (float) i / (float) (segments - 1);
for (int k = 0; k < sides; k++) {
u = (float) k / (float) (sides - 1);
vertex = new Vertex(shape[k].transform(frenetmatrix));
vertex.u = u;
vertex.v = v;
part.addVertex(vertex);
}
}
for (int i = 0; i < (segments - 1); i++) {
for (int k = 0; k < (sides - 1); k++) {
q1 = (i * sides) + k;
q2 = q1 + 1;
q3 = q1 + sides;
q4 = q2 + sides;
part.addTriangle(single, q1, q3, q2);
part.addTriangle(single, q2, q3, q4);
}
q1 = ((i + 1) * sides) - 1;
q2 = (q1 + 1) - sides;
q3 = q1 + sides;
q4 = q2 + sides;
part.addTriangle(single, q1, q3, q2);
part.addTriangle(single, q2, q3, q4);
}
return part;
}
}