org.scijava.java3d.utils.geometry.GeomBuffer Maven / Gradle / Ivy
Show all versions of j3dutils Show documentation
/*
* Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
* INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or
* maintenance of any nuclear facility.
*
*/
package org.scijava.java3d.utils.geometry;
import org.scijava.java3d.Geometry;
import org.scijava.java3d.GeometryArray;
import org.scijava.java3d.QuadArray;
import org.scijava.java3d.TriangleArray;
import org.scijava.java3d.TriangleFanArray;
import org.scijava.java3d.TriangleStripArray;
import org.scijava.vecmath.Point3f;
import org.scijava.vecmath.TexCoord2f;
import org.scijava.vecmath.Vector3f;
/**
* GeomBuffer allows OpenGL-like input of geometry data. It outputs
* Java 3D geometry array objects. This utility is to simplify porting
* of OpenGL programs to Java 3D.
*
* Here is a sample code that use this utility to create some quads.
*
*
* GeomBuffer gbuf = new GeomBuffer(100);
* gbuf.begin(GeomBuffer.QUADS);
*
* for (int i = 0; i < 5; i++){
* gbuf.normal3d(0.0, 1.0, 0.0);
* gbuf.vertex3d(1.0, 1.0, 0.0);
*
* gbuf.normal3d(0.0, 1.0, 0.0);
* gbuf.vertex3d(0.0, 1.0, 0.0);
*
* gbuf.normal3d(0.0, 1.0, 0.0);
* gbuf.vertex3d(0.0, 0.0, 0.0);
*
* gbuf.normal3d(0.0, 1.0, 0.0);
* gbuf.vertex3d(1.0, 0.0, 0.0);
* }
* gbuf.end();
* Shape3D shape = new Shape3D(gbuf.getGeom(GeomBuffer.GENERATE_NORMALS));
*
* Notice, that you only need to specify some upperbound on the number of
* points you'll use at the beginning (100 in this case).
*
* Currently, you are limited to one primitive type per geom buffer. Future
* versions will add support for mixed primitive types.
*
**/
class GeomBuffer extends Object{
//Supported Primitives
static final int QUAD_STRIP = 0x01;
static final int TRIANGLES = 0x02;
static final int QUADS = 0x04;
static final int TRIANGLE_FAN = 0x10;
static final int TRIANGLE_STRIP = 0x20;
private int flags;
Point3f[] pts = null;
Vector3f[] normals = null;
TexCoord2f[] tcoords = null;
int currVertCnt;
int currPrimCnt;
int[] currPrimType = null,
currPrimStartVertex = null,
currPrimEndVertex = null;
GeometryArray geometry;
int numVerts = 0;
int numTris = 0;
int numTexUnit = 1;
int texCoordSetMap[] = null;
static final int debug = 0;
/** Creates a geometry buffer of given number of vertices
* @param numVerts total number of vertices to allocate by this buffer.
* This is an upper bound estimate.
*/
GeomBuffer(int numVerts, int numTexUnit)
{
this.numTexUnit = numTexUnit;
pts = new Point3f[numVerts];
normals = new Vector3f[numVerts];
tcoords = new TexCoord2f[numVerts];
// max primitives is numV/3
currPrimType = new int[numVerts/3];
currPrimStartVertex = new int[numVerts/3];
currPrimEndVertex = new int[numVerts/3];
currVertCnt = 0;
currPrimCnt = 0;
texCoordSetMap = new int[numTexUnit];
for (int i = 0; i < numTexUnit; i++)
texCoordSetMap[i] = 0;
}
GeomBuffer(int numVerts)
{
this(numVerts, 1);
}
/*
* Returns a Java 3D geometry array from the geometry buffer. You need to
* call begin, vertex3d, end, etc. before calling this, of course.
*
* @param format vertex format.
*/
GeometryArray getGeom(int format)
{
GeometryArray obj = null;
flags = format;
numTris = 0;
//Switch based on first primitive.
switch (currPrimType[0]){
case TRIANGLES:
obj = processTriangles();
break;
case QUADS:
obj = processQuads();
break;
case QUAD_STRIP:
case TRIANGLE_STRIP:
obj = processQuadStrips();
break;
case TRIANGLE_FAN:
obj = processTriangleFan();
break;
}
if ((obj != null) && ((flags & Primitive.ENABLE_GEOMETRY_PICKING) != 0)) {
obj.setCapability(Geometry.ALLOW_INTERSECT);
obj.setCapability(GeometryArray.ALLOW_FORMAT_READ);
obj.setCapability(GeometryArray.ALLOW_COUNT_READ);
obj.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
}
return obj;
}
/**
* Begins a new primitive given the primitive type.
*
* @param prim the primitive type (listed above).
*
**/
void begin(int prim)
{
if (debug >= 1) System.out.println("quad");
currPrimType[currPrimCnt] = prim;
currPrimStartVertex[currPrimCnt] = currVertCnt;
}
/**
* End of primitive.
*
*
**/
void end()
{
if (debug >= 1) System.out.println("end");
currPrimEndVertex[currPrimCnt] = currVertCnt;
currPrimCnt++;
}
void vertex3d(double x, double y, double z)
{
if (debug >= 2) System.out.println("v " + x + " " +
y + " " +
z);
pts[currVertCnt] = new Point3f((float)x, (float)y, (float)z);
currVertCnt++;
}
void normal3d(double x, double y, double z)
{
if (debug >= 2) System.out.println("n " + x + " " +
y + " " + z);
double sum = x*x+y*y+z*z;
if (Math.abs(sum - 1.0) > 0.001){
if (debug >= 2) System.out.println("normalizing");
double root = Math.sqrt(sum);
if (root > 0.000001) {
x /= root;
y /= root;
z /= root;
} else {
y = z = 0.0; x = 1.0;
}
}
normals[currVertCnt] = new Vector3f((float)x, (float)y, (float)z);
}
void texCoord2d(double s, double t)
{
if (debug >= 2) System.out.println("t " +
s + " " +
t);
tcoords[currVertCnt] = new TexCoord2f((float)s, (float)t);
}
// Return a reference to the texture coordinates of this geom buffer.
TexCoord2f[] getTexCoords() {
return tcoords;
}
/**
* Returns the Java 3D geometry gotten from calling getGeom.
*
**/
GeometryArray getComputedGeometry()
{
return geometry;
}
int getNumTris()
{
return numTris;
}
int getNumVerts()
{
return numVerts;
}
private GeometryArray processQuadStrips()
{
GeometryArray obj = null;
int i;
int totalVerts = 0;
// Calculate how many vertices needed to hold all of the individual quads
int stripCounts[] = new int[currPrimCnt];
for (i = 0; i < currPrimCnt; i++){
stripCounts[i] = currPrimEndVertex[i] - currPrimStartVertex[i];
totalVerts += stripCounts[i];
}
if (debug >= 1) System.out.println("totalVerts " + totalVerts);
int tsaFlags = TriangleStripArray.COORDINATES;
if ((flags & Primitive.GENERATE_NORMALS) != 0)
tsaFlags |= TriangleStripArray.NORMALS;
if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
tsaFlags |= TriangleStripArray.TEXTURE_COORDINATE_2;
// Create GeometryArray to pass back
obj = new TriangleStripArray(totalVerts, tsaFlags,
1, texCoordSetMap, stripCounts);
// Allocate space to store new vertex info
Point3f[] newpts = new Point3f[totalVerts];
Vector3f[] newnormals = new Vector3f[totalVerts];
TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
int currVert = 0;
// Repeat for each Quad Strip
for (i = 0; i < currPrimCnt; i++){
// Output order for these quad arrays same as java 3d triangle strips
for (int j = currPrimStartVertex[i] ; j < currPrimEndVertex[i] ; j++){
outVertex(newpts, newnormals, newtcoords, currVert++,
pts, normals, tcoords, j);
}
}
numVerts = currVert;
numTris += totalVerts - currPrimCnt * 2;
obj.setCoordinates(0, newpts);
if ((flags & Primitive.GENERATE_NORMALS) != 0)
obj.setNormals(0, newnormals);
if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
obj.setTextureCoordinates(0, 0, newtcoords);
geometry = obj;
return obj;
}
private GeometryArray processQuads()
{
GeometryArray obj = null;
int i;
int totalVerts = 0;
for (i = 0; i < currPrimCnt; i++){
totalVerts += currPrimEndVertex[i] - currPrimStartVertex[i];
}
if (debug >= 1) System.out.println("totalVerts " + totalVerts);
if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
obj = new QuadArray(totalVerts,
QuadArray.COORDINATES |
QuadArray.NORMALS |
QuadArray.TEXTURE_COORDINATE_2,
1, texCoordSetMap);
}
else
if (((flags & Primitive.GENERATE_NORMALS) == 0) &&
((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
obj = new QuadArray(totalVerts,
QuadArray.COORDINATES |
QuadArray.TEXTURE_COORDINATE_2,
1, texCoordSetMap);
}
else
if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
((flags & Primitive.GENERATE_TEXTURE_COORDS) == 0)){
obj = new QuadArray(totalVerts,
QuadArray.COORDINATES |
QuadArray.NORMALS);
}
else {
obj = new QuadArray(totalVerts,
QuadArray.COORDINATES);
}
Point3f[] newpts = new Point3f[totalVerts];
Vector3f[] newnormals = new Vector3f[totalVerts];
TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
int currVert = 0;
if (debug > 1) System.out.println("total prims " + currPrimCnt);
for (i = 0; i < currPrimCnt; i++){
if (debug > 1) System.out.println("start " + currPrimStartVertex[i] +
" end " + currPrimEndVertex[i]);
for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i] - 3;j+=4){
outVertex(newpts, newnormals, newtcoords, currVert++,
pts, normals, tcoords, j);
outVertex(newpts, newnormals, newtcoords, currVert++,
pts, normals, tcoords, j + 1);
outVertex(newpts, newnormals, newtcoords, currVert++,
pts, normals, tcoords, j + 2);
outVertex(newpts, newnormals, newtcoords, currVert++,
pts, normals, tcoords, j + 3);
numTris += 2;
}
}
numVerts = currVert;
obj.setCoordinates(0, newpts);
if ((flags & Primitive.GENERATE_NORMALS) != 0)
obj.setNormals(0, newnormals);
if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
obj.setTextureCoordinates(0, 0, newtcoords);
geometry = obj;
return obj;
}
private GeometryArray processTriangles()
{
GeometryArray obj = null;
int i;
int totalVerts = 0;
for (i = 0; i < currPrimCnt; i++){
totalVerts += currPrimEndVertex[i] - currPrimStartVertex[i];
}
if (debug >= 1) System.out.println("totalVerts " + totalVerts);
if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
obj = new TriangleArray(totalVerts,
TriangleArray.COORDINATES |
TriangleArray.NORMALS |
TriangleArray.TEXTURE_COORDINATE_2,
1, texCoordSetMap);
}
else
if (((flags & Primitive.GENERATE_NORMALS) == 0) &&
((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
obj = new TriangleArray(totalVerts,
TriangleArray.COORDINATES |
TriangleArray.TEXTURE_COORDINATE_2,
1, texCoordSetMap);
}
else
if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
((flags & Primitive.GENERATE_TEXTURE_COORDS) == 0)){
obj = new TriangleArray(totalVerts,
TriangleArray.COORDINATES |
TriangleArray.NORMALS);
}
else {
obj = new TriangleArray(totalVerts,
TriangleArray.COORDINATES);
}
Point3f[] newpts = new Point3f[totalVerts];
Vector3f[] newnormals = new Vector3f[totalVerts];
TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
int currVert = 0;
for (i = 0; i < currPrimCnt; i++){
for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i] - 2;j+=3){
outVertex(newpts, newnormals, newtcoords, currVert++,
pts, normals, tcoords, j);
outVertex(newpts, newnormals, newtcoords, currVert++,
pts, normals, tcoords, j + 1);
outVertex(newpts, newnormals, newtcoords, currVert++,
pts, normals, tcoords, j + 2);
numTris += 1;
}
}
numVerts = currVert;
obj.setCoordinates(0, newpts);
if ((flags & Primitive.GENERATE_NORMALS) != 0)
obj.setNormals(0, newnormals);
if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
obj.setTextureCoordinates(0, 0, newtcoords);
geometry = obj;
return obj;
}
private GeometryArray processTriangleFan() {
if (debug > 0) System.out.println("processTriangleFan");
GeometryArray obj = null;
int i;
int totalVerts = 0;
int stripCounts[] = new int[currPrimCnt];
// figure out how many vertices we need to hold the individual fans
for (i = 0; i < currPrimCnt; i++) {
stripCounts[i] = currPrimEndVertex[i] - currPrimStartVertex[i];
totalVerts += stripCounts[i];
}
// figure out what flags we need
int tfFlags = TriangleFanArray.COORDINATES;
if ((flags & Primitive.GENERATE_NORMALS) != 0) {
tfFlags |= TriangleFanArray.NORMALS;
}
if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) {
tfFlags |= TriangleFanArray.TEXTURE_COORDINATE_2;
}
// create the TriangleFanArray
obj = new TriangleFanArray(totalVerts, tfFlags, 1, texCoordSetMap,
stripCounts);
// allocate space for vertex info
Point3f[] newpts = new Point3f[totalVerts];
Vector3f[] newnormals = new Vector3f[totalVerts];
TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
int currVert = 0;
// repeat for each fan
for (i = 0; i < currPrimCnt; i++) {
for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i]; j++) {
outVertex(newpts, newnormals, newtcoords, currVert++, pts,
normals, tcoords, j);
}
}
for (i = 0; i < newpts.length; i++) {
if (debug > 1) System.out.println("i = " + i + " " + newpts[i]);
}
numVerts = currVert;
numTris = totalVerts - currPrimCnt * 2;
// set the coordinates on the GeometryArray
obj.setCoordinates(0, newpts);
// set the normals and tex coords if necessary
if ((flags & Primitive.GENERATE_NORMALS) != 0) {
obj.setNormals(0, newnormals);
}
if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) {
obj.setTextureCoordinates(0, 0, newtcoords);
}
geometry = obj;
return obj;
}
void outVertex(Point3f[] dpts, Vector3f[] dnormals, TexCoord2f[] dtcoords,
int dloc,
Point3f[] spts, Vector3f[] snormals, TexCoord2f[] stcoords,
int sloc)
{
if (debug >= 1) System.out.println("v " + spts[sloc].x + " " +
spts[sloc].y + " " +
spts[sloc].z);
// PSP: Do we really need new points here?
dpts[dloc] = new Point3f(spts[sloc]);
if ((flags & Primitive.GENERATE_NORMALS) != 0){
dnormals[dloc] = new Vector3f(snormals[sloc]);
}
if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0){
if (debug >= 2) System.out.println("final out tcoord");
dtcoords[dloc] = new TexCoord2f(stcoords[sloc]);
}
}
}