/*
 * Copyright (c) 2009-2012 jMonkeyEngine
 * All rights reserved.
 *
 * 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.jme3.asset;

import java.io.IOException;

import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.material.Material;
import com.jme3.material.RenderState.FaceCullMode;

/**
 * Blender key. Contains path of the blender file and its loading properties.
 * @author Marcin Roguski (Kaelthas)
 */
public class BlenderKey extends ModelKey {
    protected static final int         DEFAULT_FPS               = 25;
    /**
     * FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time
     * between the frames.
     */
    protected int                      fps                       = DEFAULT_FPS;
    /**
     * This variable is a bitwise flag of FeatureToLoad interface values; By default everything is being loaded.
     */
    protected int                      featuresToLoad            = FeaturesToLoad.ALL;
    /** The variable that tells if content of the file (along with data unlinked to any feature on the scene) should be stored as 'user data' in the result spatial. */
    protected boolean                  loadUnlinkedAssets;
    /** The root path for all the assets. */
    protected String                   assetRootPath;
    /** This variable indicate if Y axis is UP axis. If not then Z is up. By default set to true. */
    protected boolean                  fixUpAxis                 = true;
    /** Generated textures resolution (PPU - Pixels Per Unit). */
    protected int                      generatedTexturePPU       = 128;
    /**
     * The name of world settings that the importer will use. If not set or specified name does not occur in the file
     * then the first world settings in the file will be used.
     */
    protected String                   usedWorld;
    /**
     * User's default material that is set fo objects that have no material definition in blender. The default value is
     * null. If the value is null the importer will use its own default material (gray color - like in blender).
     */
    protected Material                 defaultMaterial;
    /** Face cull mode. By default it is disabled. */
    protected FaceCullMode             faceCullMode              = FaceCullMode.Back;
    /**
     * Variable describes which layers will be loaded. N-th bit set means N-th layer will be loaded.
     * If set to -1 then the current layer will be loaded.
     */
    protected int                      layersToLoad              = -1;
    /** A variable that toggles the object custom properties loading. */
    protected boolean                  loadObjectProperties      = true;
    /**
     * Maximum texture size. Might be dependant on the graphic card.
     * This value is taken from <b>org.lwjgl.opengl.GL11.GL_MAX_TEXTURE_SIZE</b>.
     */
    protected int                      maxTextureSize            = 8192;
    /** Allows to toggle generated textures loading. Disabled by default because it very often takes too much memory and needs to be used wisely. */
    protected boolean                  loadGeneratedTextures;
    /** Tells if the mipmaps will be generated by jme or not. By default generation is dependant on the blender settings. */
    protected MipmapGenerationMethod   mipmapGenerationMethod    = MipmapGenerationMethod.GENERATE_WHEN_NEEDED;
    /**
     * If the sky has only generated textures applied then they will have the following size (both width and height). If 2d textures are used then the generated
     * textures will get their proper size.
     */
    protected int                      skyGeneratedTextureSize   = 1000;
    /** The radius of a shape that will be used while creating the generated texture for the sky. The higher it is the larger part of the texture will be seen. */
    protected float                    skyGeneratedTextureRadius = 1;
    /** The shape against which the generated texture for the sky will be created. */
    protected SkyGeneratedTextureShape skyGeneratedTextureShape  = SkyGeneratedTextureShape.SPHERE;
    /**
     * This field tells if the importer should optimise the use of textures or not. If set to true, then textures of the same mapping type will be merged together
     * and textures that in the final result will never be visible - will be discarded.
     */
    protected boolean                  optimiseTextures;
    /** The method of matching animations to skeletons. The default value is: AT_LEAST_ONE_NAME_MATCH. */
    protected AnimationMatchMethod     animationMatchMethod      = AnimationMatchMethod.AT_LEAST_ONE_NAME_MATCH;
    /** The size of points that are loaded and do not belong to any edge of the mesh. */
    protected float                    pointsSize                = 1;
    /** The width of edges that are loaded from the mesh and do not belong to any face. */
    protected float                    linesWidth                = 1;

    /**
     * Constructor used by serialization mechanisms.
     */
    public BlenderKey() {
    }

    /**
     * Constructor. Creates a key for the given file name.
     * @param name
     *            the name (path) of a file
     */
    public BlenderKey(String name) {
        super(name);
    }

    /**
     * This method returns frames per second amount. The default value is BlenderKey.DEFAULT_FPS = 25.
     * @return the frames per second amount
     */
    public int getFps() {
        return fps;
    }

    /**
     * This method sets frames per second amount.
     * @param fps
     *            the frames per second amount
     */
    public void setFps(int fps) {
        this.fps = fps;
    }

    /**
     * This method returns the face cull mode.
     * @return the face cull mode
     */
    public FaceCullMode getFaceCullMode() {
        return faceCullMode;
    }

    /**
     * This method sets the face cull mode.
     * @param faceCullMode
     *            the face cull mode
     */
    public void setFaceCullMode(FaceCullMode faceCullMode) {
        this.faceCullMode = faceCullMode;
    }

    /**
     * This method sets layers to be loaded.
     * @param layersToLoad
     *            layers to be loaded
     */
    public void setLayersToLoad(int layersToLoad) {
        this.layersToLoad = layersToLoad;
    }

    /**
     * This method returns layers to be loaded.
     * @return layers to be loaded
     */
    public int getLayersToLoad() {
        return layersToLoad;
    }

    /**
     * This method sets the properies loading policy.
     * By default the value is true.
     * @param loadObjectProperties
     *            true to load properties and false to suspend their loading
     */
    public void setLoadObjectProperties(boolean loadObjectProperties) {
        this.loadObjectProperties = loadObjectProperties;
    }

    /**
     * @return the current properties loading properties
     */
    public boolean isLoadObjectProperties() {
        return loadObjectProperties;
    }

    /**
     * The default value for this parameter is the same as defined by: org.lwjgl.opengl.GL11.GL_MAX_TEXTURE_SIZE.
     * If by any means this is too large for user's hardware configuration use the 'setMaxTextureSize' method to change that.
     * @return maximum texture size (width/height)
     */
    public int getMaxTextureSize() {
        return maxTextureSize;
    }

    /**
     * This method sets the maximum texture size.
     * @param maxTextureSize
     *            the maximum texture size
     */
    public void setMaxTextureSize(int maxTextureSize) {
        this.maxTextureSize = maxTextureSize;
    }

    /**
     * This method sets the flag that toggles the generated textures loading.
     * @param loadGeneratedTextures
     *            <b>true</b> if generated textures should be loaded and <b>false</b> otherwise
     */
    public void setLoadGeneratedTextures(boolean loadGeneratedTextures) {
        this.loadGeneratedTextures = loadGeneratedTextures;
    }

    /**
     * @return tells if the generated textures should be loaded (<b>false</b> is the default value)
     */
    public boolean isLoadGeneratedTextures() {
        return loadGeneratedTextures;
    }

    /**
     * Not used any more.
     * This method sets the asset root path.
     * @param assetRootPath
     *            the assets root path
     */
    @Deprecated
    public void setAssetRootPath(String assetRootPath) {
        this.assetRootPath = assetRootPath;
    }

    /**
     * Not used any more.
     * This method returns the asset root path.
     * @return the asset root path
     */
    @Deprecated
    public String getAssetRootPath() {
        return assetRootPath;
    }

    /**
     * This method adds features to be loaded.
     * @param featuresToLoad
     *            bitwise flag of FeaturesToLoad interface values
     */
    @Deprecated
    public void includeInLoading(int featuresToLoad) {
        this.featuresToLoad |= featuresToLoad;
    }

    /**
     * This method removes features from being loaded.
     * @param featuresNotToLoad
     *            bitwise flag of FeaturesToLoad interface values
     */
    @Deprecated
    public void excludeFromLoading(int featuresNotToLoad) {
        featuresToLoad &= ~featuresNotToLoad;
    }

    @Deprecated
    public boolean shouldLoad(int featureToLoad) {
        return (featuresToLoad & featureToLoad) != 0;
    }

    /**
     * This method returns bitwise value of FeaturesToLoad interface value. It describes features that will be loaded by
     * the blender file loader.
     * @return features that will be loaded by the blender file loader
     */
    @Deprecated
    public int getFeaturesToLoad() {
        return featuresToLoad;
    }

    /**
     * This method determines if unlinked assets should be loaded.
     * If not then only objects on selected layers will be loaded and their assets if required.
     * If yes then all assets will be loaded even if they are on inactive layers or are not linked
     * to anything.
     * @return <b>true</b> if unlinked assets should be loaded and <b>false</b> otherwise
     */
    public boolean isLoadUnlinkedAssets() {
        return loadUnlinkedAssets;
    }

    /**
     * This method sets if unlinked assets should be loaded.
     * If not then only objects on selected layers will be loaded and their assets if required.
     * If yes then all assets will be loaded even if they are on inactive layers or are not linked
     * to anything.
     * @param loadUnlinkedAssets
     *            <b>true</b> if unlinked assets should be loaded and <b>false</b> otherwise
     */
    public void setLoadUnlinkedAssets(boolean loadUnlinkedAssets) {
        this.loadUnlinkedAssets = loadUnlinkedAssets;
    }

    /**
     * This method sets the fix up axis state. If set to true then Y is up axis. Otherwise the up i Z axis. By default Y
     * is up axis.
     * @param fixUpAxis
     *            the up axis state variable
     */
    public void setFixUpAxis(boolean fixUpAxis) {
        this.fixUpAxis = fixUpAxis;
    }

    /**
     * This method returns the fix up axis state. If set to true then Y is up axis. Otherwise the up i Z axis. By
     * default Y is up axis.
     * @return the up axis state variable
     */
    public boolean isFixUpAxis() {
        return fixUpAxis;
    }

    /**
     * This method sets the generated textures resolution.
     * @param generatedTexturePPU
     *            the generated textures resolution
     */
    public void setGeneratedTexturePPU(int generatedTexturePPU) {
        this.generatedTexturePPU = generatedTexturePPU;
    }

    /**
     * @return the generated textures resolution
     */
    public int getGeneratedTexturePPU() {
        return generatedTexturePPU;
    }

    /**
     * @return mipmaps generation method
     */
    public MipmapGenerationMethod getMipmapGenerationMethod() {
        return mipmapGenerationMethod;
    }

    /**
     * @param mipmapGenerationMethod
     *            mipmaps generation method
     */
    public void setMipmapGenerationMethod(MipmapGenerationMethod mipmapGenerationMethod) {
        this.mipmapGenerationMethod = mipmapGenerationMethod;
    }

    /**
     * @return the size of the generated textures for the sky (used if no flat textures are applied)
     */
    public int getSkyGeneratedTextureSize() {
        return skyGeneratedTextureSize;
    }

    /**
     * @param skyGeneratedTextureSize
     *            the size of the generated textures for the sky (used if no flat textures are applied)
     */
    public void setSkyGeneratedTextureSize(int skyGeneratedTextureSize) {
        if (skyGeneratedTextureSize <= 0) {
            throw new IllegalArgumentException("The texture size must be a positive value (the value given as a parameter: " + skyGeneratedTextureSize + ")!");
        }
        this.skyGeneratedTextureSize = skyGeneratedTextureSize;
    }

    /**
     * @return the radius of a shape that will be used while creating the generated texture for the sky, the higher it is the larger part of the texture will be seen
     */
    public float getSkyGeneratedTextureRadius() {
        return skyGeneratedTextureRadius;
    }

    /**
     * @param skyGeneratedTextureRadius
     *            the radius of a shape that will be used while creating the generated texture for the sky, the higher it is the larger part of the texture will be seen
     */
    public void setSkyGeneratedTextureRadius(float skyGeneratedTextureRadius) {
        this.skyGeneratedTextureRadius = skyGeneratedTextureRadius;
    }

    /**
     * @return the shape against which the generated texture for the sky will be created (by default it is a sphere).
     */
    public SkyGeneratedTextureShape getSkyGeneratedTextureShape() {
        return skyGeneratedTextureShape;
    }

    /**
     * @param skyGeneratedTextureShape
     *            the shape against which the generated texture for the sky will be created
     */
    public void setSkyGeneratedTextureShape(SkyGeneratedTextureShape skyGeneratedTextureShape) {
        if (skyGeneratedTextureShape == null) {
            throw new IllegalArgumentException("The sky generated shape type cannot be null!");
        }
        this.skyGeneratedTextureShape = skyGeneratedTextureShape;
    }

    /**
     * If set to true, then textures of the same mapping type will be merged together
     * and textures that in the final result will never be visible - will be discarded.
     * @param optimiseTextures
     *            the variable that tells if the textures should be optimised or not
     */
    public void setOptimiseTextures(boolean optimiseTextures) {
        this.optimiseTextures = optimiseTextures;
    }

    /**
     * @return the variable that tells if the textures should be optimised or not (by default the optimisation is disabled)
     */
    public boolean isOptimiseTextures() {
        return optimiseTextures;
    }

    /**
     * Sets the way the animations will be matched with skeletons.
     * 
     * @param animationMatchMethod
     *            the way the animations will be matched with skeletons
     */
    public void setAnimationMatchMethod(AnimationMatchMethod animationMatchMethod) {
        this.animationMatchMethod = animationMatchMethod;
    }

    /**
     * @return the way the animations will be matched with skeletons
     */
    public AnimationMatchMethod getAnimationMatchMethod() {
        return animationMatchMethod;
    }

    /**
     * @return the size of points that are loaded and do not belong to any edge of the mesh
     */
    public float getPointsSize() {
        return pointsSize;
    }

    /**
     * Sets the size of points that are loaded and do not belong to any edge of the mesh.
     * @param pointsSize
     *            The size of points that are loaded and do not belong to any edge of the mesh
     */
    public void setPointsSize(float pointsSize) {
        this.pointsSize = pointsSize;
    }

    /**
     * @return the width of edges that are loaded from the mesh and do not belong to any face
     */
    public float getLinesWidth() {
        return linesWidth;
    }

    /**
     * Sets the width of edges that are loaded from the mesh and do not belong to any face.
     * @param linesWidth
     *            the width of edges that are loaded from the mesh and do not belong to any face
     */
    public void setLinesWidth(float linesWidth) {
        this.linesWidth = linesWidth;
    }

    /**
     * This mehtod sets the name of the WORLD data block taht should be used during file loading. By default the name is
     * not set. If no name is set or the given name does not occur in the file - the first WORLD data block will be used
     * during loading (assumin any exists in the file).
     * @param usedWorld
     *            the name of the WORLD block used during loading
     */
    public void setUsedWorld(String usedWorld) {
        this.usedWorld = usedWorld;
    }

    /**
     * This mehtod returns the name of the WORLD data block taht should be used during file loading.
     * @return the name of the WORLD block used during loading
     */
    public String getUsedWorld() {
        return usedWorld;
    }

    /**
     * This method sets the default material for objects.
     * @param defaultMaterial
     *            the default material
     */
    public void setDefaultMaterial(Material defaultMaterial) {
        this.defaultMaterial = defaultMaterial;
    }

    /**
     * This method returns the default material.
     * @return the default material
     */
    public Material getDefaultMaterial() {
        return defaultMaterial;
    }

    @Override
    public void write(JmeExporter e) throws IOException {
        super.write(e);
        OutputCapsule oc = e.getCapsule(this);
        oc.write(fps, "fps", DEFAULT_FPS);
        oc.write(featuresToLoad, "features-to-load", FeaturesToLoad.ALL);
        oc.write(loadUnlinkedAssets, "load-unlinked-assets", false);
        oc.write(assetRootPath, "asset-root-path", null);
        oc.write(fixUpAxis, "fix-up-axis", true);
        oc.write(generatedTexturePPU, "generated-texture-ppu", 128);
        oc.write(usedWorld, "used-world", null);
        oc.write(defaultMaterial, "default-material", null);
        oc.write(faceCullMode, "face-cull-mode", FaceCullMode.Off);
        oc.write(layersToLoad, "layers-to-load", -1);
        oc.write(mipmapGenerationMethod, "mipmap-generation-method", MipmapGenerationMethod.GENERATE_WHEN_NEEDED);
        oc.write(skyGeneratedTextureSize, "sky-generated-texture-size", 1000);
        oc.write(skyGeneratedTextureRadius, "sky-generated-texture-radius", 1f);
        oc.write(skyGeneratedTextureShape, "sky-generated-texture-shape", SkyGeneratedTextureShape.SPHERE);
        oc.write(optimiseTextures, "optimise-textures", false);
        oc.write(animationMatchMethod, "animation-match-method", AnimationMatchMethod.AT_LEAST_ONE_NAME_MATCH);
        oc.write(pointsSize, "points-size", 1);
        oc.write(linesWidth, "lines-width", 1);
    }

    @Override
    public void read(JmeImporter e) throws IOException {
        super.read(e);
        InputCapsule ic = e.getCapsule(this);
        fps = ic.readInt("fps", DEFAULT_FPS);
        featuresToLoad = ic.readInt("features-to-load", FeaturesToLoad.ALL);
        loadUnlinkedAssets = ic.readBoolean("load-unlinked-assets", false);
        assetRootPath = ic.readString("asset-root-path", null);
        fixUpAxis = ic.readBoolean("fix-up-axis", true);
        generatedTexturePPU = ic.readInt("generated-texture-ppu", 128);
        usedWorld = ic.readString("used-world", null);
        defaultMaterial = (Material) ic.readSavable("default-material", null);
        faceCullMode = ic.readEnum("face-cull-mode", FaceCullMode.class, FaceCullMode.Off);
        layersToLoad = ic.readInt("layers-to=load", -1);
        mipmapGenerationMethod = ic.readEnum("mipmap-generation-method", MipmapGenerationMethod.class, MipmapGenerationMethod.GENERATE_WHEN_NEEDED);
        skyGeneratedTextureSize = ic.readInt("sky-generated-texture-size", 1000);
        skyGeneratedTextureRadius = ic.readFloat("sky-generated-texture-radius", 1f);
        skyGeneratedTextureShape = ic.readEnum("sky-generated-texture-shape", SkyGeneratedTextureShape.class, SkyGeneratedTextureShape.SPHERE);
        optimiseTextures = ic.readBoolean("optimise-textures", false);
        animationMatchMethod = ic.readEnum("animation-match-method", AnimationMatchMethod.class, AnimationMatchMethod.AT_LEAST_ONE_NAME_MATCH);
        pointsSize = ic.readFloat("points-size", 1);
        linesWidth = ic.readFloat("lines-width", 1);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + (animationMatchMethod == null ? 0 : animationMatchMethod.hashCode());
        result = prime * result + (assetRootPath == null ? 0 : assetRootPath.hashCode());
        result = prime * result + (defaultMaterial == null ? 0 : defaultMaterial.hashCode());
        result = prime * result + (faceCullMode == null ? 0 : faceCullMode.hashCode());
        result = prime * result + featuresToLoad;
        result = prime * result + (fixUpAxis ? 1231 : 1237);
        result = prime * result + fps;
        result = prime * result + generatedTexturePPU;
        result = prime * result + layersToLoad;
        result = prime * result + (loadGeneratedTextures ? 1231 : 1237);
        result = prime * result + (loadObjectProperties ? 1231 : 1237);
        result = prime * result + (loadUnlinkedAssets ? 1231 : 1237);
        result = prime * result + maxTextureSize;
        result = prime * result + (mipmapGenerationMethod == null ? 0 : mipmapGenerationMethod.hashCode());
        result = prime * result + (optimiseTextures ? 1231 : 1237);
        result = prime * result + Float.floatToIntBits(skyGeneratedTextureRadius);
        result = prime * result + (skyGeneratedTextureShape == null ? 0 : skyGeneratedTextureShape.hashCode());
        result = prime * result + skyGeneratedTextureSize;
        result = prime * result + (usedWorld == null ? 0 : usedWorld.hashCode());
        result = prime * result + (int) pointsSize;
        result = prime * result + (int) linesWidth;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BlenderKey) {
            return false;
        }
        BlenderKey other = (BlenderKey) obj;
        if (animationMatchMethod != other.animationMatchMethod) {
            return false;
        }
        if (assetRootPath == null) {
            if (other.assetRootPath != null) {
                return false;
            }
        } else if (!assetRootPath.equals(other.assetRootPath)) {
            return false;
        }
        if (defaultMaterial == null) {
            if (other.defaultMaterial != null) {
                return false;
            }
        } else if (!defaultMaterial.equals(other.defaultMaterial)) {
            return false;
        }
        if (faceCullMode != other.faceCullMode) {
            return false;
        }
        if (featuresToLoad != other.featuresToLoad) {
            return false;
        }
        if (fixUpAxis != other.fixUpAxis) {
            return false;
        }
        if (fps != other.fps) {
            return false;
        }
        if (generatedTexturePPU != other.generatedTexturePPU) {
            return false;
        }
        if (layersToLoad != other.layersToLoad) {
            return false;
        }
        if (loadGeneratedTextures != other.loadGeneratedTextures) {
            return false;
        }
        if (loadObjectProperties != other.loadObjectProperties) {
            return false;
        }
        if (loadUnlinkedAssets != other.loadUnlinkedAssets) {
            return false;
        }
        if (maxTextureSize != other.maxTextureSize) {
            return false;
        }
        if (mipmapGenerationMethod != other.mipmapGenerationMethod) {
            return false;
        }
        if (optimiseTextures != other.optimiseTextures) {
            return false;
        }
        if (Float.floatToIntBits(skyGeneratedTextureRadius) != Float.floatToIntBits(other.skyGeneratedTextureRadius)) {
            return false;
        }
        if (skyGeneratedTextureShape != other.skyGeneratedTextureShape) {
            return false;
        }
        if (skyGeneratedTextureSize != other.skyGeneratedTextureSize) {
            return false;
        }
        if (usedWorld == null) {
            if (other.usedWorld != null) {
                return false;
            }
        } else if (!usedWorld.equals(other.usedWorld)) {
            return false;
        }
        if (pointsSize != other.pointsSize) {
            return false;
        }
        if (linesWidth != other.linesWidth) {
            return false;
        }
        return true;
    }

    /**
     * This enum tells the importer if the mipmaps for textures will be generated by jme. <li>NEVER_GENERATE and ALWAYS_GENERATE are quite understandable <li>GENERATE_WHEN_NEEDED is an option that checks if the texture had 'Generate mipmaps' option set in blender, mipmaps are generated only when the option is set
     * @author Marcin Roguski (Kaelthas)
     */
    public static enum MipmapGenerationMethod {
        NEVER_GENERATE, ALWAYS_GENERATE, GENERATE_WHEN_NEEDED;
    }

    /**
     * This interface describes the features of the scene that are to be loaded.
     * @deprecated this interface is deprecated and is not used anymore; to ensure the loading models consistency
     *             everything must be loaded because in blender one feature might depend on another
     * @author Marcin Roguski (Kaelthas)
     */
    @Deprecated
    public static interface FeaturesToLoad {

        int SCENES     = 0x0000FFFF;
        int OBJECTS    = 0x0000000B;
        int ANIMATIONS = 0x00000004;
        int MATERIALS  = 0x00000003;
        int TEXTURES   = 0x00000001;
        int CAMERAS    = 0x00000020;
        int LIGHTS     = 0x00000010;
        int WORLD      = 0x00000040;
        int ALL        = 0xFFFFFFFF;
    }

    /**
     * The shape againts which the sky generated texture will be created.
     * 
     * @author Marcin Roguski (Kaelthas)
     */
    public static enum SkyGeneratedTextureShape {
        CUBE, SPHERE;
    }

    /**
     * This enum describes which animations should be attached to which armature.
     * Blender does not store the mapping between action and armature. That is why the importer
     * will try to match those by comparing bone name of the armature with the channel names
     * int the actions.
     * 
     * @author Marcin Roguski (Kaelthas)
     */
    public static enum AnimationMatchMethod {
        /**
         * Animation is matched with skeleton when at leas one bone name matches the name of the action channel.
         * All the bones that do not have their corresponding channel in the animation will not get the proper tracks for
         * this particulat animation.
         * Also the channel will not be used for the animation if it does not find the proper bone name.
         */
        AT_LEAST_ONE_NAME_MATCH,
        /**
         * Animation is matched when all action names are covered by the target names (bone names or the name of the
         * animated spatial.
         */
        ALL_NAMES_MATCH;
    }
}
