package j3deditor.bin.hierarchy;


import j3deditor.bin.hierarchy.util.Deletable;
import j3deditor.bin.hierarchy.util.HNodeType;

import j3deditor.bin.hierarchy.util.J3DePoint2D;

import j3deditor.bin.util.Utilities;

import java.awt.Color;
import java.awt.Image;

import java.util.ArrayList;

import javax.media.j3d.Appearance;
import javax.media.j3d.ImageComponent;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.ImageComponent3D;
import javax.media.j3d.Texture;
import javax.media.j3d.Texture2D;
import javax.media.j3d.Texture3D;

import javax.swing.ImageIcon;

import javax.vecmath.Color4f;
import javax.vecmath.Point3f;
import javax.vecmath.Tuple3f;


/**
 * Contains and manages an instance of
 * <code>javax.media.j3d.Texture</code>.
 *
 * @author Risto Seene
 * 
 * @see javax.media.j3d.Texture
 */
public class J3DeTexture extends HierarchyNode implements Deletable{

	/** Specifies that this is 2D texture. */
	public static final int TEXTURE_2D = 0;

	/** Specifies that this is 3D texture. */
	public static final int TEXTURE_3D = 1;

	/** number of <code>J3DeTexture</code> nodes */
	private static long numOfNodes = 0;

	/** appearance this texture is referenced from */
	private Appearance appearance;

	/** actual <code>Texture</code> object */
	private Texture tex;

	/** <code>J3DeImageComponent</code> objects bounded to this texture */
	private ArrayList<J3DeImageComponent> images;


	/**
	 * Creates an instance of <code>J3DeTexture</code>
	 * with the <code>Texture</code> object from the
	 * given <code>Appearance</code> object.
	 *
	 * @param appearance
	 *	an instance of <code>Appearance</code> which
	 *	texture component is not <code>null</code>
	 */
	public J3DeTexture(Appearance appearance){
		super("Texture", HNodeType.TEXTURE, numOfNodes);
		numOfNodes++;

		images = new ArrayList<J3DeImageComponent>();

		this.appearance = appearance;
		if(appearance.getTexture() != null){
			setTexture(appearance.getTexture());

		}
	}

	/**
	 * Sets the Texture of this J3DeTexture.
	 * 
	 * @param texture
	 * 	new Texture
	 */
	public void setTexture(Texture texture){
		this.tex = texture;
		setCapabilities();
		initImageComponents();
	}


	/**
	 * Sets the capabilities for the <code>Material</code> object.
	 *
	 * <br>Capabilities:<br>
	 * <ul><li><code>Texture.ALLOW_ANISOTROPIC_FILTER_READ</code></li>
	 * <li><code>Texture.ALLOW_BOUNDARY_COLOR_READ</code></li>
	 * <li><code>Texture.ALLOW_BOUNDARY_MODE_READ</code></li>
	 * <li><code>Texture.ALLOW_ENABLE_READ</code></li>
	 * <li><code>Texture.ALLOW_ENABLE_WRITE</code></li>
	 * <li><code>Texture.ALLOW_FILTER_READ</code></li>
	 * <li><code>Texture.ALLOW_FILTER4_READ</code></li>
	 * <li><code>Texture.ALLOW_FORMAT_READ</code></li>
	 * <li><code>Texture.ALLOW_IMAGE_READ</code></li>
	 * <li><code>Texture.ALLOW_IMAGE_WRITE</code></li>
	 * <li><code>Texture.ALLOW_LOD_RANGE_READ</code></li>
	 * <li><code>Texture.ALLOW_LOD_RANGE_WRITE</code></li>
	 * <li><code>Texture.ALLOW_MIPMAP_MODE_READ</code></li>
	 * <li><code>Texture.ALLOW_SHARPEN_TEXTURE_READ</code></li>
	 * <li><code>Texture.ALLOW_SIZE_READ</code></li></ul>
	 *
	 * @see javax.media.j3d.Texture#setCapability(int capability)
	 */
	private void setCapabilities(){
		tex.setCapability(Texture.ALLOW_ANISOTROPIC_FILTER_READ);
		tex.setCapability(Texture.ALLOW_BOUNDARY_COLOR_READ);
		tex.setCapability(Texture.ALLOW_BOUNDARY_MODE_READ);
		tex.setCapability(Texture.ALLOW_ENABLE_READ);
		tex.setCapability(Texture.ALLOW_ENABLE_WRITE);
		tex.setCapability(Texture.ALLOW_FILTER_READ);
		tex.setCapability(Texture.ALLOW_FILTER4_READ);
		tex.setCapability(Texture.ALLOW_FORMAT_READ);
		tex.setCapability(Texture.ALLOW_IMAGE_READ);
		tex.setCapability(Texture.ALLOW_IMAGE_WRITE);
		tex.setCapability(Texture.ALLOW_LOD_RANGE_READ);
		tex.setCapability(Texture.ALLOW_LOD_RANGE_WRITE);
		tex.setCapability(Texture.ALLOW_MIPMAP_MODE_READ);
		tex.setCapability(Texture.ALLOW_SHARPEN_TEXTURE_READ);
		tex.setCapability(Texture.ALLOW_SIZE_READ);
	}


	/**
	 * Initializes the image components objects
	 */
	private void initImageComponents(){
		this.images.clear();
		ImageComponent[] images = tex.getImages();
		if(images != null){
			for(int i = 0; i < images.length; i++){
				this.images.add(new J3DeImageComponent(images[i]));
			}
		}
	}

	/**
	 * Returns the number of ImageComponent objects
	 * this texture contains.
	 * 
	 * @return the number of ImageComponent objects
	 * 	this texture contains
	 */
	public int numberOfImageComponents(){
		return this.images.size();
	}

	/**
	 * Returns an ImageComponent from the specified index.
	 * 
	 * @param index
	 * 	the index of ImageComponent
	 * @return an ImageComponent from the specified index
	 */
	public J3DeImageComponent getImageComponent(int index){
		return this.images.get(index);
	}

	/**
	 * Returns the Texture contained in this J3DeTexture.
	 * 
	 * @return the Texture contained in this J3DeTexture
	 */
	public Texture getTexture(){
		return this.tex;
	}


	/**
	 * Returns an image from the specified level.
	 * 
	 * @param level
	 * 	the index of ImageComponent which image will be returned
	 * @return an image from the specified level
	 */
	public Image getImage(int level){
		return new J3DeImageComponent(this.tex.getImage(level)).getImage(0);
	}


	/**
	 * Returns the anisotropic filter degree of this texture.
	 * 
	 * @return the anisotropic filter degree of this texture
	 * 
	 * @see javax.media.j3d.Texture#getAnisotropicFilterDegree()
	 */
	public float getAnisotropicFilterDegree(){
		return this.tex.getAnisotropicFilterDegree();
	}

	/**
	 * Sets the anisotropic filter degree of this texture.
	 * 
	 * @param degree
	 * 	anisotropic filter degree
	 *        
	 * @see javax.media.j3d.Texture#setAnisotropicFilterDegree(float degree)
	 */
	public void setAnisotropicFilterDegree(float degree){
		this.tex.setAnisotropicFilterDegree(degree);
	}


	/**
	 * Returns the anisotropic filter mode of this texture.
	 * 
	 * @return the anisotropic filter mode of this texture
	 * 
	 * @see javax.media.j3d.Texture#getAnisotropicFilterMode()
	 */
	public int getAnisotropicFilterMode(){
		int mode = this.tex.getAnisotropicFilterMode();
		if(mode == Texture.ANISOTROPIC_NONE){
			return 0;
		}
		else if(mode == Texture.ANISOTROPIC_SINGLE_VALUE){
			return 1;
		}
		return -1;
	}

	/**
	 * Returns the list of the anisotropic filter mode names.
	 * 
	 * @return the list of the anisotropic filter mode names
	 */
	public static String[] getAnisotropicFilterModes(){
		String[] modes = new String[]{ "ANISOTROPIC NONE", "ANISOTROPIC SINGLE VALUE" };
		return modes;
	}

	/**
	 * Sets the anisotropic filter mode of this texture.
	 * 
	 * @param mode
	 * 	anisotropic filter mode.<br/>
	 *        Valid values are 0 and 1, see
	 *        getAnisotropicFilterModes().
	 *        
	 * @see javax.media.j3d.Texture#setAnisotropicFilterMode(int mode)
	 */
	public void setAnisotropicFilterMode(int mode){
		if(mode == 0){
			this.tex.setAnisotropicFilterMode(Texture.ANISOTROPIC_NONE);
		}
		else if(mode == 1){
			this.tex.setAnisotropicFilterMode(Texture.ANISOTROPIC_SINGLE_VALUE);
		}
	}


	/**
	 * Returns the base level of this texture.
	 * 
	 * @return the base level of this texture
	 * 
	 * @see javax.media.j3d.Texture#getBaseLevel()
	 */
	public int getBaseLevel(){
		return this.tex.getBaseLevel();
	}

	/**
	 * Sets the base level of this texture.
	 * 
	 * @param level
	 * 	base level
	 *        
	 * @see javax.media.j3d.Texture#setBaseLevel(int baseLevel)
	 */
	public void setBaseLevel(int level){
		this.tex.setBaseLevel(level);
	}


	/**
	 * Returns the boundary color of this texture.
	 * 
	 * @return the boundary color of this texture
	 * 
	 * @see javax.media.j3d.Texture#getBoundaryColor(Color4f boundaryColor)
	 */
	public Color getBoundaryColor(){
		Color4f color = new Color4f();
		this.tex.getBoundaryColor(color);
		return color.get();
	}

	/**
	 * Sets the boundary color of this texture.
	 * 
	 * @param color
	 * 	new boundary color
	 *        
	 * @see javax.media.j3d.Texture#setBoundaryColor(Color4f boundaryColor)
	 */
	public void setBoundaryColor(Color color){
		Color4f color4f = new Color4f();
		color4f.set(color);
		this.tex.setBoundaryColor(color4f);
	}


	/**
	 * Returns the boundary mode for the S coordinate.
	 * 
	 * @return the boundary mode for the S coordinate
	 * 
	 * @see javax.media.j3d.Texture#getBoundaryModeS()
	 */
	public int getBoundaryModeS(){
		return this.getBoundaryMode(this.tex.getBoundaryModeS());

	}

	/**
	 * Returns the boundary mode for the T coordinate.
	 * 
	 * @return the boundary mode for the T coordinate
	 * 
	 * @see javax.media.j3d.Texture#getBoundaryModeT()
	 */
	public int getBoundaryModeT(){
		return this.getBoundaryMode(this.tex.getBoundaryModeT());
	}

	/**
	 * Returns the boundary mode
	 * 
	 * @param mode
	 * 	boundary mode
	 * @return the boundary mode
	 */
	private int getBoundaryMode(int mode){
		if(mode == Texture.CLAMP){
			return 0;
		}
		if(mode == Texture.WRAP){
			return 1;
		}
		if(mode == Texture.CLAMP_TO_EDGE){
			return 2;
		}
		if(mode == Texture.CLAMP_TO_BOUNDARY){
			return 3;
		}
		return -1;
	}

	/**
	 * Returns the list of boundary mode names.
	 * 
	 * @return the list of boundary mode names
	 */
	public static String[] getBoundaryModes(){
		String[] modes = new String[]{ "CLAMP", "WRAP", "CLAMP TO EDGE", "CLAMP TO BOUNDARY" };
		return modes;
	}

	/**
	 * Sets the boundary mode for the S coordinate.
	 * 
	 * @param mode
	 * 	valid values are 0, 1, 2 and 3,
	 *        see getBoundaryModes().
	 *        
	 * @see javax.media.j3d.Texture#setBoundaryModeS(int boundaryModeS)
	 */
	public void setBoundaryModeS(int mode){
		this.setBoundaryMode(mode, 0);
	}

	/**
	 * Sets the boundary mode for the T coordinate.
	 * 
	 * @param mode
	 *        valid values are 0, 1, 2 and 3,
	 *        see getBoundaryModes().
	 *        
	 * @see javax.media.j3d.Texture#setBoundaryModeT(int boundaryModeT)
	 */
	public void setBoundaryModeT(int mode){
		this.setBoundaryMode(mode, 1);
	}

	/**
	 * Sets the right boundary mode for the right coordinate.
	 * 
	 * @param mode
	 * 	boundary mode
	 * @param type
	 * 	0 - S coordinate, 1 - T coordinate
	 */
	private void setBoundaryMode(int mode, int type){
		if(mode == 0){
			if(type == 0){
				this.tex.setBoundaryModeS(Texture.CLAMP);
			}
			else if(type == 1){
				this.tex.setBoundaryModeT(Texture.CLAMP);
			}
		}
		else if(mode == 1){
			if(type == 0){
				this.tex.setBoundaryModeS(Texture.WRAP);
			}
			else if(type == 1){
				this.tex.setBoundaryModeT(Texture.WRAP);
			}
		}
		else if(mode == 2){
			if(type == 0){
				this.tex.setBoundaryModeS(Texture.CLAMP_TO_EDGE);
			}
			else if(type == 1){
				this.tex.setBoundaryModeT(Texture.CLAMP_TO_EDGE);
			}
		}
		else if(mode == 3){
			if(type == 0){
				this.tex.setBoundaryModeS(Texture.CLAMP_TO_BOUNDARY);
			}
			else if(type == 1){
				this.tex.setBoundaryModeT(Texture.CLAMP_TO_BOUNDARY);
			}
		}
	}


	/**
	 * Returns the boundary width of this texture.
	 * 
	 * @return the boundary width of this texture
	 * 
	 * @see javax.media.j3d.Texture#getBoundaryWidth()
	 */
	public int getBoundaryWidth(){
		return this.tex.getBoundaryWidth();
	}


	/**
	 * Returns the filter 4 function of this texture.
	 * 
	 * @return the filter 4 function of this texture
	 * 
	 * @see javax.media.j3d.Texture#getFilter4Func(float[] weights)
	 */
	public float[] getFilter4Func(){
		float[] weights = new float[this.tex.getFilter4FuncPointsCount()];
		this.tex.getFilter4Func(weights);
		return weights;
	}

	/**
	 * Sets the filter 4 function of this texture.
	 * 
	 * @param weights
	 * 	see javax.media.j3d.Texture#setFilter4Func(float[] weights)
	 *        
	 * @see javax.media.j3d.Texture#setFilter4Func(float[] weights)
	 */
	public void setFilter4Func(float[] weights){
		this.tex.setFilter4Func(weights);
	}


	/**
	 * Returns the format of this texture.
	 * 
	 * @return the format of this texture
	 * 
	 * @see javax.media.j3d.Texture#getFormat()
	 */
	public int getFormat(){
		int format = this.tex.getFormat();
		if(format == Texture.INTENSITY){
			return 0;
		}
		else if(format == Texture.LUMINANCE){
			return 1;
		}
		else if(format == Texture.ALPHA){
			return 2;
		}
		else if(format == Texture.LUMINANCE_ALPHA){
			return 3;
		}
		else if(format == Texture.RGB){
			return 4;
		}
		else if(format == Texture.RGBA){
			return 5;
		}
		return -1;
	}

	/**
	 * Returns the list of texture format names.
	 * 
	 * @return the list of texture format names
	 */
	public static String[] getFormats(){
		String[] formats = new String[]{ "INTENSITY", "LUMINANCE", "ALPHA", "LUMINANCE ALPHA", "RGB", "RGBA" };
		return formats;
	}


	/**
	 * Returns the lod offset of this texture.
	 * 
	 * @return the lod offset of this texture
	 * 
	 * @see javax.media.j3d.Texture#getLodOffset(Tuple3f offset)
	 */
	public float[] getLodOffset(){
		Tuple3f offset = new Point3f();
		this.tex.getLodOffset(offset);
		float[] values = new float[3];
		offset.get(values);
		return values;
	}

	/**
	 * Sets the lod offset of this texture.
	 * 
	 * @param s
	 * 	see javax.media.j3d.Texture#setLodOffset(Tuple3f offset)
	 * @param t
	 * 	see javax.media.j3d.Texture#setLodOffset(Tuple3f offset)
	 * @param r
	 * 	see javax.media.j3d.Texture#setLodOffset(Tuple3f offset)
	 * 
	 * @see javax.media.j3d.Texture#setLodOffset(Tuple3f offset)
	 */
	public void setLodOffset(float s, float t, float r){
		this.tex.setLodOffset(s, t, r);
	}


	/**
	 * Returns the type of magnification filter.
	 * 
	 * @return the type of magnification filter
	 * 
	 * @see javax.media.j3d.Texture#getMagFilter()
	 */
	public int getMagFilter(){
		int filter = this.tex.getMagFilter();
		if(filter == Texture.FASTEST){
			return 0;
		}
		else if(filter == Texture.NICEST){
			return 1;
		}
		else if(filter == Texture.BASE_LEVEL_POINT){
			return 2;
		}
		else if(filter == Texture.BASE_LEVEL_LINEAR){
			return 3;
		}
		else if(filter == Texture.LINEAR_SHARPEN){
			return 4;
		}
		else if(filter == Texture.LINEAR_SHARPEN_RGB){
			return 5;
		}
		else if(filter == Texture.LINEAR_SHARPEN_ALPHA){
			return 6;
		}
		else if(filter == Texture.FILTER4){
			return 7;
		}
		return -1;
	}

	/**
	 * Returns the list of magnification filter names.
	 * 
	 * @return the list of magnification filter names
	 */
	public static String[] getMagFilters(){
		String[] filters = new String[]{ "FASTEST", "NICEST", "BASE LEVEL POINT", "BASE LEVEL LINEAR", "LINEAR SHARPEN", "LINEAR SHARPEN RGB", "LINEAR SHARPEN ALPHA", "FILTER4" };
		return filters;
	}

	/**
	 * Sets the magnification filter of this texture.
	 * 
	 * @param filter
	 * 	valid values are 0, 1, 2, 3, 4, 5, 6 and 7,
	 *        see getMagFilters()
	 *        
	 * @see javax.media.j3d.Texture#setMagFilter(int magFilter)
	 */
	public void setMagFilter(int filter){
		if(filter == 0){
			this.tex.setMagFilter(Texture.FASTEST);
		}
		else if(filter == 1){
			this.tex.setMagFilter(Texture.NICEST);
		}
		else if(filter == 2){
			this.tex.setMagFilter(Texture.BASE_LEVEL_POINT);
		}
		else if(filter == 3){
			this.tex.setMagFilter(Texture.BASE_LEVEL_LINEAR);
		}
		else if(filter == 4){
			this.tex.setMagFilter(Texture.LINEAR_SHARPEN);
		}
		else if(filter == 5){
			this.tex.setMagFilter(Texture.LINEAR_SHARPEN_RGB);
		}
		else if(filter == 6){
			this.tex.setMagFilter(Texture.LINEAR_SHARPEN_ALPHA);
		}
		else if(filter == 7){
			this.tex.setMagFilter(Texture.FILTER4);
		}
	}


	/**
	 * Returns the maximum level of this texture.
	 * 
	 * @return the maximum level of this texture
	 * 
	 * @see javax.media.j3d.Texture#getMaximumLevel()
	 */
	public int getMaximumLevel(){
		return this.tex.getMaximumLevel();
	}

	/**
	 * Sets the maximum level of this texture.
	 * 
	 * @param level
	 * 	maximum level of texture
	 *        
	 * @see javax.media.j3d.Texture#setMaximumLevel(int maximumLevel)
	 */
	public void setMaximumLevel(int level){
		this.tex.setMaximumLevel(level);
	}


	/**
	 * Returns the maximum lod of this texture.
	 * 
	 * @return the maximum lod of this texture
	 * 
	 * @see javax.media.j3d.Texture#getMaximumLOD()
	 */
	public float getMaximumLOD(){
		return this.tex.getMaximumLOD();
	}

	/**
	 * Sets the maximum lod of this texture.
	 * 
	 * @param lod
	 * 	maximum lod
	 *        
	 * @see javax.media.j3d.Texture#setMaximumLOD(float maximumLod)
	 */
	public void setMaximumLOD(float lod){
		this.tex.setMaximumLOD(lod);
	}


	/**
	 * Returns the minification filter of this texture.
	 * 
	 * @return the minification filter of this texture
	 * 
	 * @see javax.media.j3d.Texture#getMinFilter()
	 */
	public int getMinFilter(){
		int filter = this.tex.getMinFilter();
		if(filter == Texture.FASTEST){
			return 0;
		}
		else if(filter == Texture.NICEST){
			return 1;
		}
		else if(filter == Texture.BASE_LEVEL_POINT){
			return 2;
		}
		else if(filter == Texture.BASE_LEVEL_LINEAR){
			return 3;
		}
		else if(filter == Texture.MULTI_LEVEL_POINT){
			return 4;
		}
		else if(filter == Texture.MULTI_LEVEL_LINEAR){
			return 5;
		}
		else if(filter == Texture.FILTER4){
			return 6;
		}
		return -1;
	}

	/**
	 * Returns the list of the minification filters.
	 * 
	 * @return the list of the minification filters
	 */
	public static String[] getMinFilters(){
		String[] filters = new String[]{ "FASTEST", "NICEST", "BASE LEVEL POINT", "BASE LEVEL LINEAR", "MULTI LEVEL POINT", "MULTI LEVEL LINEAR", "FILTER4" };
		return filters;
	}

	/**
	 * Sets the minification filter of this texture.
	 * 
	 * @param filter
	 * 	valid values are 0, 1, 2, 3, 4, 5 and 6,
	 *        see getMinFilters()
	 * 
	 * @see javax.media.j3d.Texture#setMinFilter(int minFilter)
	 */
	public void setMinFilter(int filter){
		if(filter == 0){
			this.tex.setMinFilter(Texture.FASTEST);
		}
		else if(filter == 1){
			this.tex.setMinFilter(Texture.NICEST);
		}
		else if(filter == 2){
			this.tex.setMinFilter(Texture.BASE_LEVEL_POINT);
		}
		else if(filter == 3){
			this.tex.setMinFilter(Texture.BASE_LEVEL_LINEAR);
		}
		else if(filter == 4){
			this.tex.setMinFilter(Texture.MULTI_LEVEL_POINT);
		}
		else if(filter == 5){
			this.tex.setMinFilter(Texture.MULTI_LEVEL_LINEAR);
		}
		else if(filter == 6){
			this.tex.setMinFilter(Texture.FILTER4);
		}
	}


	/**
	 * Returns the minimum lod of this texture.
	 * 
	 * @return the minimum lod of this texture
	 * 
	 * @see javax.media.j3d.Texture#getMinimumLOD()
	 */
	public float getMinimumLOD(){
		return this.tex.getMinimumLOD();
	}

	/**
	 * Sets the minimum lod of this texture.
	 * 
	 * @param lod
	 * 	see javax.media.j3d.Texture#setMinimumLOD(float minimumLod)
	 * 
	 * @see javax.media.j3d.Texture#setMinimumLOD(float minimumLod)
	 */
	public void setMinimumLOD(float lod){
		this.tex.setMinimumLOD(lod);
	}


	/**
	 * Returns the mipmap mode of this texture.
	 * 
	 * @return the mipmap mode of this texture
	 * 
	 * @see javax.media.j3d.Texture#getMipMapMode()
	 */
	public int getMipMapMode(){
		int mode = this.tex.getMipMapMode();
		if(mode == Texture.BASE_LEVEL){
			return 0;
		}
		else if(mode == Texture.MULTI_LEVEL_MIPMAP){
			return 1;
		}
		return -1;
	}

	/**
	 * Returns the list of mipmap mode names.
	 * 
	 * @return the list of mipmap mode names
	 */
	public static String[] getMipMapModes(){
		String[] modes = new String[]{ "BASE LEVEL", "MULTI LEVEL MIPMAP" };
		return modes;
	}

	/**
	 * Sets the mipmap mode of this texture.
	 * 
	 * @param mode
	 * 	valid values are 0 and 1,
	 *        see getMipMapModes()
	 * 
	 * @see javax.media.j3d.Texture#setMipMapMode(int mipMapMode)
	 */
	public void setMipMapMode(int mode){
		if(mode == 0){
			this.tex.setMipMapMode(Texture.BASE_LEVEL);
		}
		else if(mode == 1){
			this.tex.setMipMapMode(Texture.MULTI_LEVEL_MIPMAP);
		}
	}


	/**
	 * Returns the sharpen texture function of this texture.
	 * 
	 * @return the sharpen texture function of this texture
	 * 
	 * @see javax.media.j3d.Texture#getSharpenTextureFunc(float[] lod, float[] pts)
	 */
	public float[][] getSharpenTextureFunc(){
		float[] lod = new float[this.tex.getSharpenTextureFuncPointsCount()];
		float[] pts = new float[this.tex.getSharpenTextureFuncPointsCount()];
		this.tex.getSharpenTextureFunc(lod, pts);
		float[][] values = new float[][]{ lod, pts };
		return values;
	}

	/**
	 * Sets the sharpen texture function of this texture.
	 * 
	 * @param lod
	 * 	see javax.media.j3d.Texture#setSharpenTextureFunc(float[] lod, float[] pts)
	 * @param pts
	 * 	see javax.media.j3d.Texture#setSharpenTextureFunc(float[] lod, float[] pts)
	 * 
	 * @see javax.media.j3d.Texture#setSharpenTextureFunc(float[] lod, float[] pts)
	 */
	public void setSharpenTextureFunc(float[] lod, float[] pts){
		this.tex.setSharpenTextureFunc(lod, pts);
	}


	/**
	 * Returns the number of mipmap levels.
	 * 
	 * @return the number of mipmap levels
	 * 
	 * @see javax.media.j3d.Texture#numMipMapLevels()
	 */
	public int numMipMapLevels(){
		return this.tex.numMipMapLevels();
	}


	/**
	 * Returns the size of this texture.
	 * 
	 * @return the size of this texture
	 * 
	 * @see javax.media.j3d.Texture#getWidth()
	 * @see javax.media.j3d.Texture#getHeight()
	 */
	public J3DePoint2D getSize(){
		return new J3DePoint2D(this.tex.getWidth(), this.tex.getHeight());
	}


	/**
	 * Creates new texture using the specified properties.
	 * 
	 * @param type
	 * 	either <code>TEXTURE_2D</code> or <code>TEXTURE_3D</code>
	 * @param images
	 * 	texture images (in 2D texture only first image is used)
	 * @param mipMapMode
	 * 	either <code>Texture.BASE_LEVEL</code> or <code>Texture.MULTI_LEVEL_MIPMAP</code>
	 * @param format
	 * 	0 - <code>INTENSITY</code><br/>
	 *        1 - <code>LUMINANCE</code><br/>
	 *        2 - <code>ALPHA</code><br/>
	 *        3 - <code>LUMINACE_ALPHA</code><br/>
	 *        4 - <code>RGB</code><br/>
	 *        5 - <code>RGBA</code>
	 * 
	 * @return the newly created texture
	 */
	public static Texture createTexture(int type, Image[] images, int mipMapMode, int format){
		Texture texture = null;
		ImageIcon ii = new ImageIcon(images[0]);

		int mipMap = Texture.BASE_LEVEL;
		boolean hasMMlevels = false;
		if(mipMapMode == 1){
			mipMap = Texture.MULTI_LEVEL_MIPMAP;
			hasMMlevels = true;
		}

		int frmt = Texture.RGB;
		if(format == 0){
			frmt = Texture.INTENSITY;
		}
		else if(format == 1){
			frmt = Texture.LUMINANCE;
		}
		else if(format == 2){
			frmt = Texture.ALPHA;
		}
		else if(format == 3){
			frmt = Texture.LUMINANCE_ALPHA;
		}
		else if(format == 5){
			frmt = Texture.RGBA;
		}

		if(type == J3DeTexture.TEXTURE_2D){
			texture = new Texture2D(mipMap, frmt, ii.getIconWidth(), ii.getIconHeight());
			ImageComponent2D[] imgComps = J3DeImageComponent.createImageComponents(images[0], texture.numMipMapLevels());
			texture.setImages(imgComps);
		}
		else if(type == J3DeTexture.TEXTURE_3D){
			for(int i = 1; i < images.length; i++){
				images[i] = images[i].getScaledInstance(ii.getIconWidth(), ii.getIconHeight(), Image.SCALE_SMOOTH);
			}
			texture = new Texture3D(mipMap, frmt, ii.getIconWidth(), ii.getIconHeight(), images.length);
			ImageComponent3D[] imgComps = J3DeImageComponent.createImageComponents(images, texture.numMipMapLevels());
			texture.setImages(imgComps);
		}

		return texture;
	}

	/**
	 * Removes this texture from the <code>Appearance</code> object.
	 */
	public void delete(){
		try{
		          this.appearance.setTexture(null);
			this.getParent().removeChild(this);
			this.setParent(null);
			this.appearance = null;
			this.tex = null;
		} catch(Throwable t){
			Utilities.out.throwError(t);
		}
	}

}
