/**
* Copyright (c) 2003-2009, Xith3D Project Group all rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions 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 the 'Xith3D Project Group' nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.xith3d.scenegraph.primitives;
import org.openmali.FastMath;
import org.openmali.vecmath2.Colorf;
import org.openmali.vecmath2.Point3f;
import org.openmali.vecmath2.TexCoord2f;
import org.openmali.vecmath2.Vector3f;
import org.xith3d.loaders.texture.TextureLoader;
import org.xith3d.scenegraph.Appearance;
import org.xith3d.scenegraph.Geometry;
import org.xith3d.scenegraph.Shape3D;
import org.xith3d.scenegraph.Texture;
import org.xith3d.scenegraph.TriangleArray;
/**
* An open cone pointing in the +z direction.
* Has unit height and radius.
*
* @see <a href="http://www.javagaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=xith3d;action=display;num=1081555878">Original Announcement</a>
*
* @author Daniel Herring
* @author Marvin Froehlich (aka Qudus)
*/
public class Cone extends Shape3D
{
private static GeometryType geomConstructTypeHint = GeometryType.TRIANGLE_ARRAY;
/**
* Sets the hint for this ShapeType's Geometry to be constructed of a certain type.
*
* @param hint
*/
public static void setGeometryConstructionTypeHint( GeometryType hint )
{
switch ( hint )
{
case TRIANGLE_ARRAY:
geomConstructTypeHint = hint;
break;
default:
throw new UnsupportedOperationException( "Currently " + Sphere.class.getSimpleName() + " does not support " + hint );
}
}
/**
* @return the hint for this ShapeType's Geometry to be constructed of a certain type.
*/
public static GeometryType getGeometryConstructionTypeHint()
{
return ( geomConstructTypeHint );
}
/*
public static GeometryConstruct createGeometryConstructITSA(int slices, int features)
{
if (slices < 3)
{
throw new IllegalArgumentException( "slices < 3" ) );
}
Point3f[] vertices = null;
Vector3f[] normals = null;
TexCoord2f[] texCoords = null;
Color3f[] colors = null;
int[] indices = null;
int[] stripLengths = null;
vertices = new Point3f[ slices + 2 ];
if ((features & GeometryArray.NORMALS) > 0)
normals = new Vector3f[ vertices.length ];
if ((features & GeometryArray.TEXTURE_COORDINATE_2) > 0)
texCoords = new TexCoord2f[ vertices.length ];
int numIndices = (int)FastMath.floor( (float)slices / 3f ) * 5;
if ((slices % 3) == 1)
numIndices += 3;
else if ((slices % 3) == 2)
numIndices += 4;
indices = new int[ numIndices ];
if (slices % 3 == 0)
stripLengths = new int[ slices / 3 ];
else
stripLengths = new int[ slices / 3 + 1 ];
for (int i = 0; i < stripLengths.length; i++)
{
if (i == stripLengths.length - 1)
{
if (slices % 3 == 0)
stripLengths[ i ] = 5;
else if (slices % 3 == 1)
stripLengths[ i ] = 3;
else
stripLengths[ i ] = 4;
}
else
{
stripLengths[ i ] = 5;
}
}
vertices[ 0 ] = new Point3f( 0.0f, 1.0f, 0.0f );
if (normals != null)
normals[ 0 ] = new Vector3f( 0.0f, 1.0f, 0.0f );
if (texCoords != null)
texCoords[ 0 ] = new TexCoord2f( 0.5f, 0.5f );
int v = 1;
int i = 0;
for (int s = 0; s < slices + 1; s += 3)
{
for (int t = 0; (t < 3) && (s + t < slices + 1); t++)
{
final float a = (float)(s + t) * FastMath.TWO_PI / (float)slices;
vertices[ v + t ] = new Point3f( FastMath.cos( a ), 0.0f, -FastMath.sin( a ) );
if (normals != null)
normals[ v + t ] = new Vector3f( 0.0f, 1.0f, 0.0f );
if (texCoords != null)
texCoords[ v + t ] = new TexCoord2f( 0.5f, 0.5f );
}
indices[ i++ ] = v;
indices[ i++ ] = v + 1;
indices[ i++ ] = 0;
if (i < indices.length)
indices[ i++ ] = v + 2;
if (i < indices.length)
indices[ i++ ] = v + 3;
v += 3;
}
if ((features & GeometryArray.COLOR_3) > 0)
colors = GeomFactory.generateColors3( vertices );
return ( new GeometryConstruct( GeometryType.INDEXED_TRIANGLE_STRIP_ARRAY, vertices, normals, texCoords, colors, indices, stripLengths ) );
}
*/
private static final Vector3f compNormal( Point3f vertex, Point3f tip, float height )
{
if ( height == 0.0f )
{
return ( new Vector3f( 0f, 1f, 0f ) );
}
Vector3f tmp1 = Vector3f.fromPool();
Vector3f tmp2 = Vector3f.fromPool();
tmp1.sub( vertex, tip );
tmp2.sub( vertex, Point3f.ZERO );
Vector3f normal = new Vector3f();
normal.cross( tmp2, tmp1 );
normal.cross( tmp1, normal );
normal.normalize();
Vector3f.toPool( tmp2 );
Vector3f.toPool( tmp1 );
return ( normal );
}
private static final float PI_FOURTH = FastMath.PI / 4f;
private static final float O1 = PI_FOURTH;
private static final float O2 = PI_FOURTH * 2f;
private static final float O3 = PI_FOURTH * 3f;
private static final float O4 = PI_FOURTH * 4f;
private static final float O5 = PI_FOURTH * 5f;
private static final float O6 = PI_FOURTH * 6f;
private static final float O7 = PI_FOURTH * 7f;
private static final float O8 = PI_FOURTH * 8f;
private static final TexCoord2f getTexCoord( float angle )
{
float s = 0f;
float t = 0f;
if ( angle <= O1 )
{
s = 1.0f;
t = FastMath.sin( angle * 2f );
t *= 0.5f;
t += 0.5f;
}
else if ( angle <= O2 )
{
t = 1.0f;
s = FastMath.sin( ( O2 - angle ) * 2f );
s *= 0.5f;
s += 0.5f;
}
else if ( angle <= O3 )
{
t = 1.0f;
s = FastMath.sin( ( angle - O2 ) * 2f );
s *= -0.5f;
s += 0.5f;
}
else if ( angle <= O4 )
{
s = 0.0f;
t = FastMath.sin( ( O4 - angle ) * 2f );
t *= 0.5f;
t += 0.5f;
}
else if ( angle <= O5 )
{
s = 0.0f;
t = FastMath.sin( ( angle - O4 ) * 2f );
t *= -0.5f;
t += 0.5f;
}
else if ( angle <= O6 )
{
t = 0.0f;
s = FastMath.sin( ( O6 - angle ) * 2f );
s *= -0.5f;
s += 0.5f;
}
else if ( angle <= O7 )
{
t = 0.0f;
s = FastMath.sin( ( angle - O6 ) * 2f );
s *= 0.5f;
s += 0.5f;
}
else// if ( angle <= O8 )
{
s = 1.0f;
t = FastMath.sin( ( O8 - angle ) * 2f );
t *= -0.5f;
t += 0.5f;
}
return ( new TexCoord2f( s, t ) );
}
/**
* Generate the GeometryConstruct for a TriangleArray to build
* a Cone pointing in the +y direction (with unit radius and length).
*
* @param radius the cone's base-radius
* @param height the cone's height
* @param slices Number of vertical stripes down the cone
* @param features Generate the data for GeometryArray.NORMALS | GeometryArray.TEXTURE_COORDINATES_2 ...
* @param colorAlpha
* @param texCoordsSize
*/
public static GeometryConstruct createGeometryConstructTA( float radius, float height, int slices, int features, boolean colorAlpha, int texCoordsSize )
{
if ( slices < 3 )
{
throw new IllegalArgumentException( "slices < 3" );
}
Point3f[] vertices = new Point3f[ 3 * slices ];
Vector3f[] normals = new Vector3f[ 3 * slices ];
TexCoord2f[] texture = new TexCoord2f[ 3 * slices ];
Point3f tip = new Point3f( 0f, height, 0f );
int index = 0;
for ( int i = 0; i < slices; i++ )
{
final float angle0 = ( i + 0 ) * ( FastMath.TWO_PI / slices );
final float angle1 = ( i + 1 ) * ( FastMath.TWO_PI / slices );
// first corner
vertices[ index ] = new Point3f( FastMath.cos( angle0 ) * radius, 0f, -FastMath.sin( angle0 ) * radius );
normals[ index ] = compNormal( vertices[ index ], tip, height );
texture[ index ] = getTexCoord( angle0 );
index++;
// second corner (tip)
vertices[ index ] = new Point3f( tip );
normals[ index ] = new Vector3f( normals[ index - 1 ] );
texture[ index ] = new TexCoord2f( 0.5f, 0.5f );
index++;
// third corner
vertices[ index ] = new Point3f( FastMath.cos( angle1 ) * radius, 0f, -FastMath.sin( angle1 ) * radius );
normals[ index ] = compNormal( vertices[ index ], tip, height );
texture[ index ] = getTexCoord( angle1 );
index++;
}
return ( new GeometryConstruct( GeometryType.TRIANGLE_ARRAY, vertices, normals, texture ) );
}
/**
* Generate a TriangleArray to build
* a Cone pointing in the +y direction (with unit radius and length).
*
* @param radius the cone's base-radius
* @param height the cone's height
* @param slices Number of vertical stripes down the cone
* @param features Generate the data for GeometryArray.NORMALS | GeometryArray.TEXTURE_COORDINATES_2 ...
* @param colorAlpha
* @param texCoordsSize
*/
public static TriangleArray createGeometryTA( float radius, float height, int slices, int features, boolean colorAlpha, int texCoordsSize )
{
features |= Geometry.COORDINATES;
GeometryConstruct gc = createGeometryConstructTA( radius, height, slices, features, colorAlpha, texCoordsSize );
return ( GeomFactory.createTriangleArray( gc ) );
}
/**
* Creates the GeometryArray for a Sphere.
*
* <pre>
* Parametric equations:
* x = r * cos( theta ) * sin( phi )
* y = r * sin( theta ) * sin( phi )
* z = r * cos( phi )
* over theta in [ 0, 2 * PI ] and phi in [ 0, PI ]
* </pre>
*
* @param radius the cone's base-radius
* @param height the cone's height
* @param slices Number of vertical stripes down the sphere
* @param features Generate the data for GeometryArray.COLOR_3 | GeometryArray.NORMALS | ...
* @param colorAlpha
* @param texCoordsSize
*/
public static Geometry createGeometry( float radius, float height, int slices, int features, boolean colorAlpha, int texCoordsSize )
{
switch ( getGeometryConstructionTypeHint() )
{
case TRIANGLE_ARRAY:
return ( createGeometryTA( radius, height, slices, features, colorAlpha, texCoordsSize ) );
default:
throw new Error( getGeometryConstructionTypeHint().getCorrespondingClass().getSimpleName() + " creation is not yet implemented." );
}
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param radius the cone's base-radius
* @param height the cone's height
* @param slices Number of vertical stripes down the cone
* @param features Generate the data for GeometryArray.COLOR_3 | GeometryArray.NORMALS | ...
* @param colorAlpha
* @param texCoordsSize
*/
public Cone( float radius, float height, int slices, int features, boolean colorAlpha, int texCoordsSize )
{
super( createGeometry( radius, height, slices, features, colorAlpha, texCoordsSize ) );
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param slices Number of vertical stripes down the cone
* @param features Generate the data for GeometryArray.COLOR_3 | GeometryArray.NORMALS | ...
* @param colorAlpha
* @param texCoordsSize
*/
public Cone( int slices, int features, boolean colorAlpha, int texCoordsSize )
{
this( 1.0f, 1.0f, slices, features, colorAlpha, texCoordsSize );
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param radius the cone's base-radius
* @param height the cone's height
* @param slices Number of vertical stripes down the cone
* @param texture the Texture to apply to this Shape's Appearance
*/
public Cone( float radius, float height, int slices, Texture texture )
{
this( radius, height, slices, Geometry.COORDINATES | Geometry.TEXTURE_COORDINATES, false, 2 );
getAppearance( true ).setTexture( texture );
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param slices Number of vertical stripes down the cone
* @param texture the Texture to apply to this Shape's Appearance
*/
public Cone( int slices, Texture texture )
{
this( 1.0f, 1.0f, slices, Geometry.COORDINATES | Geometry.TEXTURE_COORDINATES, false, 2 );
getAppearance( true ).setTexture( texture );
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param radius the cone's base-radius
* @param height the cone's height
* @param slices Number of vertical stripes down the cone
* @param texture the Texture to apply to this Shape's Appearance
*/
public Cone( float radius, float height, int slices, String texture )
{
this( radius, height, slices, TextureLoader.getInstance().getTexture( texture ) );
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param slices Number of vertical stripes down the cone
* @param texture the Texture to apply to this Shape's Appearance
*/
public Cone( int slices, String texture )
{
this( 1.0f, 1.0f, slices, TextureLoader.getInstance().getTexture( texture ) );
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param radius the cone's base-radius
* @param height the cone's height
* @param slices Number of vertical stripes down the cone
* @param color the color to apply to this Shape's Appearance
*/
public Cone( float radius, float height, int slices, Colorf color )
{
this( radius, height, slices, Geometry.COORDINATES | Geometry.NORMALS, false, 2 );
getAppearance( true ).getColoringAttributes( true ).setColor( color );
if ( color.hasAlpha() )
this.getAppearance( true ).getTransparencyAttributes( true ).setTransparency( color.getAlpha() );
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param slices Number of vertical stripes down the cone
* @param color the color to apply to this Shape's Appearance
*/
public Cone( int slices, Colorf color )
{
this( 1.0f, 1.0f, slices, color );
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param radius the cone's base-radius
* @param height the cone's height
* @param slices Number of vertical stripes down the cone
* @param app the Appearance to be applied to this Shape
*/
public Cone( float radius, float height, int slices, Appearance app )
{
this( radius, height, slices, Geometry.COORDINATES | Geometry.NORMALS | GeomFactory.getFeaturesFromAppearance( app ), false, GeomFactory.getTexCoordsSize( app ) );
setAppearance( app );
}
/**
* Generate an open cone pointing in the +z direction.
* Has unit height and radius.
*
* @param slices Number of vertical stripes down the cone
* @param app the Appearance to be applied to this Shape
*/
public Cone( int slices, Appearance app )
{
this( 1.0f, 1.0f, slices, app );
}
}