Java tutorial
/******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.badlogic.gdx.graphics.g3d; import java.util.Comparator; import java.util.Iterator; import com.badlogic.gdx.utils.Array; public class Attributes implements Iterable<Attribute>, Comparator<Attribute> { protected long mask; protected final Array<Attribute> attributes = new Array<Attribute>(); protected boolean sorted = true; /** Sort the attributes by their ID */ public final void sort() { if (!sorted) { attributes.sort(this); sorted = true; } } /** @return Bitwise mask of the ID's of all the containing attributes */ public final long getMask() { return mask; } /** Example usage: ((BlendingAttribute)material.get(BlendingAttribute.ID)).sourceFunction; * @return The attribute (which can safely be cast) if any, otherwise null */ public final Attribute get(final long type) { if (has(type)) for (int i = 0; i < attributes.size; i++) if (attributes.get(i).type == type) return attributes.get(i); return null; } /** Example usage: ((BlendingAttribute)material.get(BlendingAttribute.ID)).sourceFunction; * @return The attribute if any, otherwise null */ public final <T extends Attribute> T get(Class<T> clazz, final long type) { return (T) get(type); } /** Get multiple attributes at once. Example: material.get(out, ColorAttribute.Diffuse | ColorAttribute.Specular | * TextureAttribute.Diffuse); */ public final Array<Attribute> get(final Array<Attribute> out, final long type) { for (int i = 0; i < attributes.size; i++) if ((attributes.get(i).type & type) != 0) out.add(attributes.get(i)); return out; } /** Removes all attributes */ public void clear() { mask = 0; attributes.clear(); } /** @return The amount of attributes this material contains. */ public int size() { return attributes.size; } private final void enable(final long mask) { this.mask |= mask; } private final void disable(final long mask) { this.mask &= -1L ^ mask; } /** Add a attribute to this material. If the material already contains an attribute of the same type it is overwritten. */ public final void set(final Attribute attribute) { final int idx = indexOf(attribute.type); if (idx < 0) { enable(attribute.type); attributes.add(attribute); sorted = false; } else { attributes.set(idx, attribute); } } /** Add multiple attributes to this material. If the material already contains an attribute of the same type it is overwritten. */ public final void set(final Attribute attribute1, final Attribute attribute2) { set(attribute1); set(attribute2); } /** Add multiple attributes to this material. If the material already contains an attribute of the same type it is overwritten. */ public final void set(final Attribute attribute1, final Attribute attribute2, final Attribute attribute3) { set(attribute1); set(attribute2); set(attribute3); } /** Add multiple attributes to this material. If the material already contains an attribute of the same type it is overwritten. */ public final void set(final Attribute attribute1, final Attribute attribute2, final Attribute attribute3, final Attribute attribute4) { set(attribute1); set(attribute2); set(attribute3); set(attribute4); } /** Add an array of attributes to this material. If the material already contains an attribute of the same type it is * overwritten. */ public final void set(final Attribute... attributes) { for (final Attribute attr : attributes) set(attr); } /** Add an array of attributes to this material. If the material already contains an attribute of the same type it is * overwritten. */ public final void set(final Iterable<Attribute> attributes) { for (final Attribute attr : attributes) set(attr); } /** Removes the attribute from the material, i.e.: material.remove(BlendingAttribute.ID); Can also be used to remove multiple * attributes also, i.e. remove(AttributeA.ID | AttributeB.ID); */ public final void remove(final long mask) { for (int i = 0; i < attributes.size; i++) { final long type = attributes.get(i).type; if ((mask & type) == type) { attributes.removeIndex(i); disable(type); sorted = false; } } } /** @return True if this collection has the specified attribute, i.e. attributes.has(ColorAttribute.Diffuse); Or when multiple * attribute types are specified, true if this collection has all specified attributes, i.e. attributes.has(out, * ColorAttribute.Diffuse | ColorAttribute.Specular | TextureAttribute.Diffuse); */ public final boolean has(final long type) { return type != 0 && (this.mask & type) == type; } /** @return the index of the attribute with the specified type or negative if not available. */ protected int indexOf(final long type) { if (has(type)) for (int i = 0; i < attributes.size; i++) if (attributes.get(i).type == type) return i; return -1; } /** Check if this collection has the same attributes as the other collection. If compareValues is true, it also compares the * values of each attribute. * @param compareValues True to compare attribute values, false to only compare attribute types * @return True if this collection contains the same attributes (and optionally attribute values) as the other. */ public final boolean same(final Attributes other, boolean compareValues) { if (other == this) return true; if ((other == null) || (mask != other.mask)) return false; if (!compareValues) return true; sort(); other.sort(); for (int i = 0; i < attributes.size; i++) if (!attributes.get(i).equals(other.attributes.get(i))) return false; return true; } /** See {@link #same(Attributes, boolean)} * @return True if this collection contains the same attributes (but not values) as the other. */ public final boolean same(final Attributes other) { return same(other, false); } /** Used for sorting attributes */ @Override public final int compare(final Attribute arg0, final Attribute arg1) { return (int) (arg0.type - arg1.type); } /** Used for iterating through the attributes */ @Override public final Iterator<Attribute> iterator() { return attributes.iterator(); } @Override public int hashCode() { sort(); final int n = attributes.size; int result = 71 + (int) mask; int m = 1; for (int i = 0; i < n; i++) result += mask * attributes.get(i).hashCode() * (m = (m * 7) & 0xFFFF); return result; } @Override public boolean equals(Object other) { if (other == null) return false; if (other == this) return true; if (!(other instanceof Attributes)) return false; return hashCode() == other.hashCode(); } }