Package com.ardor3d.renderer.state

Source Code of com.ardor3d.renderer.state.TextureState

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.renderer.state;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.ardor3d.image.Image;
import com.ardor3d.image.Texture;
import com.ardor3d.image.Texture2D;
import com.ardor3d.renderer.ContextCapabilities;
import com.ardor3d.renderer.state.record.StateRecord;
import com.ardor3d.renderer.state.record.TextureStateRecord;
import com.ardor3d.scenegraph.Spatial;
import com.ardor3d.scenegraph.hint.TextureCombineMode;
import com.ardor3d.util.TextureKey;
import com.ardor3d.util.TextureManager;
import com.ardor3d.util.export.InputCapsule;
import com.ardor3d.util.export.OutputCapsule;
import com.ardor3d.util.resource.ResourceLocatorTool;
import com.ardor3d.util.resource.ResourceSource;
import com.ardor3d.util.resource.URLResourceSource;

/**
* <code>TextureState</code> maintains a texture state for a given node and it's children. The number of states that a
* TextureState can maintain at one time is equal to the number of texture units available on the GPU. It is not within
* the scope of this class to generate the texture, and is recommended that <code>TextureManager</code> be used to
* create the Texture objects.
*
* @see com.ardor3d.util.TextureManager
*/
public class TextureState extends RenderState {
    private static final Logger logger = Logger.getLogger(TextureState.class.getName());

    public static final int MAX_TEXTURES = 32;

    protected static Texture _defaultTexture = null;
    protected static boolean defaultTextureLoaded = false;

    public enum CorrectionType {
        /**
         * Correction modifier makes no color corrections, and is the fastest.
         */
        Affine,

        /**
         * Correction modifier makes color corrections based on perspective and is slower than CM_AFFINE. (Default)
         */
        Perspective;
    }

    /** The texture(s). */
    protected List<Texture> _texture = new ArrayList<Texture>(1);

    /**
     * Perspective correction to use for the object rendered with this texture state. Default is
     * CorrectionType.Perspective.
     */
    private CorrectionType _correctionType = CorrectionType.Perspective;

    public transient TextureKey[] _keyCache = new TextureKey[MAX_TEXTURES];

    public static ResourceSource DEFAULT_TEXTURE_SOURCE;
    static {
        try {
            DEFAULT_TEXTURE_SOURCE = new URLResourceSource(ResourceLocatorTool.getClassPathResource(TextureState.class,
                    "com/ardor3d/renderer/state/notloaded.tga"));
        } catch (final Exception e) {
            // ignore.
            DEFAULT_TEXTURE_SOURCE = null;
        }
    }

    /**
     * Constructor instantiates a new <code>TextureState</code> object.
     */
    public TextureState() {
        if (!defaultTextureLoaded) {
            loadDefaultTexture();
        }
    }

    @Override
    public StateType getType() {
        return StateType.Texture;
    }

    /**
     * <code>setTexture</code> sets a single texture to the first texture unit.
     *
     * @param texture
     *            the texture to set.
     */
    public void setTexture(final Texture texture) {
        if (_texture.size() == 0) {
            _texture.add(texture);
        } else {
            _texture.set(0, texture);
        }
        setNeedsRefresh(true);
    }

    /**
     * <code>getTexture</code> gets the texture that is assigned to the first texture unit.
     *
     * @return the texture in the first texture unit.
     */
    public Texture getTexture() {
        if (_texture.size() > 0) {
            return _texture.get(0);
        } else {
            return null;
        }
    }

    /**
     * <code>setTexture</code> sets the texture object to be used by the state. The texture unit that this texture uses
     * is set, if the unit is not valid, i.e. less than zero or greater than the number of texture units supported by
     * the graphics card, it is ignored.
     *
     * @param texture
     *            the texture to be used by the state.
     * @param textureUnit
     *            the texture unit this texture will fill.
     */
    public void setTexture(final Texture texture, final int textureUnit) {
        if (textureUnit >= 0 && textureUnit < MAX_TEXTURES) {
            while (textureUnit >= _texture.size()) {
                _texture.add(null);
            }
            _texture.set(textureUnit, texture);
        }
        setNeedsRefresh(true);
    }

    /**
     * <code>getTexture</code> retrieves the texture being used by the state in a particular texture unit.
     *
     * @param textureUnit
     *            the texture unit to retrieve the texture from.
     * @return the texture being used by the state. If the texture unit is invalid, null is returned.
     */
    public Texture getTexture(final int textureUnit) {
        if (textureUnit < _texture.size() && textureUnit >= 0) {
            return _texture.get(textureUnit);
        }

        return null;
    }

    public boolean removeTexture(final Texture tex) {

        final int index = _texture.indexOf(tex);
        if (index == -1) {
            return false;
        }

        _texture.set(index, null);
        _keyCache[index] = null;
        return true;
    }

    public boolean removeTexture(final int textureUnit) {
        if (textureUnit < 0 || textureUnit >= MAX_TEXTURES || textureUnit >= _texture.size()) {
            return false;
        }

        final Texture t = _texture.get(textureUnit);
        if (t == null) {
            return false;
        }

        _texture.set(textureUnit, null);
        _keyCache[textureUnit] = null;
        return true;

    }

    /**
     * Removes all textures in this texture state. Does not delete them from the graphics card.
     */
    public void clearTextures() {
        for (int i = _texture.size(); --i >= 0;) {
            removeTexture(i);
        }
    }

    /**
     * <code>setCorrectionType</code> sets the image correction type for this texture state.
     *
     * @param type
     *            the correction type for this texture.
     * @throws IllegalArgumentException
     *             if type is null
     */
    public void setCorrectionType(final CorrectionType type) {
        if (type == null) {
            throw new IllegalArgumentException("type can not be null.");
        }
        _correctionType = type;
        setNeedsRefresh(true);
    }

    /**
     * <code>getCorrectionType</code> returns the correction mode for the texture state.
     *
     * @return the correction type for the texture state.
     */
    public CorrectionType getCorrectionType() {
        return _correctionType;
    }

    /**
     * Returns the number of textures this texture manager is maintaining.
     *
     * @return the number of textures.
     */
    public int getNumberOfSetTextures() {
        int set = 0;
        for (int i = 0; i < _texture.size(); i++) {
            if (_texture.get(i) != null) {
                set++;
            }
        }
        return set;
    }

    /**
     * Returns the max index in this TextureState that contains a non-null Texture.
     *
     * @return the max index, or -1 if no textures are contained by this state.
     */
    public int getMaxTextureIndexUsed() {
        int max = _texture.size() - 1;
        while (max > 0 && _texture.get(max) == null) {
            max--;
        }
        return max;
    }

    /**
     * Fast access for retrieving a TextureKey. A return is guaranteed when <code>textureUnit</code> is any number under
     * or equal to the highest texture unit currently in use. This value can be retrieved with
     * <code>getNumberOfSetTextures</code>. A higher value might result in unexpected behavior such as an exception
     * being thrown.
     *
     * @param textureUnit
     *            The texture unit from which to retrieve the TextureKey.
     * @return the TextureKey, or null if there is none.
     */
    public final TextureKey getTextureKey(final int textureUnit) {
        if (textureUnit < _keyCache.length && textureUnit >= 0) {
            return _keyCache[textureUnit];
        }

        return null;
    }

    @Override
    public void write(final OutputCapsule capsule) throws IOException {
        super.write(capsule);
        capsule.writeSavableList(_texture, "texture", new ArrayList<Texture>(1));
        capsule.write(_correctionType, "correctionType", CorrectionType.Perspective);

    }

    @Override
    public void read(final InputCapsule capsule) throws IOException {
        super.read(capsule);
        _texture = capsule.readSavableList("texture", new ArrayList<Texture>(1));
        _correctionType = capsule.readEnum("correctionType", CorrectionType.class, CorrectionType.Perspective);
    }

    public static Image getDefaultTextureImage() {
        return _defaultTexture != null ? _defaultTexture.getImage() : null;
    }

    public static Texture getDefaultTexture() {
        if (!defaultTextureLoaded) {
            loadDefaultTexture();
        }
        return _defaultTexture.createSimpleClone();
    }

    private static void loadDefaultTexture() {
        synchronized (logger) {
            if (!defaultTextureLoaded) {
                defaultTextureLoaded = true;
                _defaultTexture = new Texture2D();
                try {
                    _defaultTexture = TextureManager.load(DEFAULT_TEXTURE_SOURCE, Texture.MinificationFilter.Trilinear,
                            true);
                } catch (final Exception e) {
                    logger.log(Level.WARNING, "Failed to load default texture: notloaded.tga", e);
                }
            }
        }
    }

    @Override
    public StateRecord createStateRecord(final ContextCapabilities caps) {
        return new TextureStateRecord();
    }

    @Override
    public RenderState extract(final Stack<? extends RenderState> stack, final Spatial spat) {
        if (spat == null) {
            return stack.peek();
        }

        final TextureCombineMode mode = spat.getSceneHints().getTextureCombineMode();
        if (mode == TextureCombineMode.Replace || (mode != TextureCombineMode.Off && stack.size() == 1)) {
            // todo: use dummy state if off?
            return stack.peek();
        }

        // accumulate the textures in the stack into a single TextureState object
        final TextureState newTState = new TextureState();
        boolean foundEnabled = false;
        final Object states[] = stack.toArray();
        switch (mode) {
            case CombineClosest:
            case CombineClosestEnabled:
                for (int iIndex = states.length - 1; iIndex >= 0; iIndex--) {
                    final TextureState pkTState = (TextureState) states[iIndex];
                    if (!pkTState.isEnabled()) {
                        if (mode == TextureCombineMode.CombineClosestEnabled) {
                            break;
                        }

                        continue;
                    }

                    foundEnabled = true;
                    for (int i = 0, max = pkTState.getMaxTextureIndexUsed(); i <= max; i++) {
                        final Texture pkText = pkTState.getTexture(i);
                        if (newTState.getTexture(i) == null) {
                            newTState.setTexture(pkText, i);
                        }
                    }
                }
                break;
            case CombineFirst:
                for (int iIndex = 0, max = states.length; iIndex < max; iIndex++) {
                    final TextureState pkTState = (TextureState) states[iIndex];
                    if (!pkTState.isEnabled()) {
                        continue;
                    }

                    foundEnabled = true;
                    for (int i = 0; i < TextureState.MAX_TEXTURES; i++) {
                        final Texture pkText = pkTState.getTexture(i);
                        if (newTState.getTexture(i) == null) {
                            newTState.setTexture(pkText, i);
                        }
                    }
                }
                break;
            case Off:
                break;
        }
        newTState.setEnabled(foundEnabled);
        return newTState;
    }
}
TOP

Related Classes of com.ardor3d.renderer.state.TextureState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.