/*******************************************************************************
* 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.glview.libgdx.graphics;
/** Instances of this class specify the vertex attributes of a mesh. VertexAttributes are used by {@link Mesh} instances to define
* its vertex structure. Vertex attributes have an order. The order is specified by the order they are added to this class.
*
* @author mzechner */
public final class VertexAttributes {
/** The usage of a vertex attribute.
*
* @author mzechner */
public static final class Usage {
public static final int Position = 1;
public static final int Color = 2;
public static final int ColorPacked = 4;
public static final int Normal = 8;
public static final int TextureCoordinates = 16;
public static final int Generic = 32;
public static final int BoneWeight = 64;
public static final int Tangent = 128;
public static final int BiNormal = 256;
}
/** the attributes in the order they were specified **/
private final VertexAttribute[] attributes;
/** the size of a single vertex in bytes **/
public final int vertexSize;
/** cache of the value calculated by {@link #getMask()} **/
private long mask = -1;
/** Constructor, sets the vertex attributes in a specific order */
public VertexAttributes (VertexAttribute... attributes) {
if (attributes.length == 0) throw new IllegalArgumentException("attributes must be >= 1");
VertexAttribute[] list = new VertexAttribute[attributes.length];
for (int i = 0; i < attributes.length; i++)
list[i] = attributes[i];
this.attributes = list;
checkValidity();
vertexSize = calculateOffsets();
}
/** Returns the offset for the first VertexAttribute with the specified usage.
* @param usage The usage of the VertexAttribute. */
public int getOffset (int usage) {
VertexAttribute vertexAttribute = findByUsage(usage);
if (vertexAttribute == null) return 0;
return vertexAttribute.offset / 4;
}
/** Returns the first VertexAttribute for the given usage.
* @param usage The usage of the VertexAttribute to find. */
public VertexAttribute findByUsage (int usage) {
int len = size();
for (int i = 0; i < len; i++)
if (get(i).usage == usage) return get(i);
return null;
}
private int calculateOffsets () {
int count = 0;
for (int i = 0; i < attributes.length; i++) {
VertexAttribute attribute = attributes[i];
attribute.offset = count;
if (attribute.usage == VertexAttributes.Usage.ColorPacked)
count += 4;
else
count += 4 * attribute.numComponents;
}
return count;
}
private void checkValidity () {
boolean pos = false;
boolean cols = false;
boolean nors = false;
for (int i = 0; i < attributes.length; i++) {
VertexAttribute attribute = attributes[i];
if (attribute.usage == Usage.Position) {
if (pos) throw new IllegalArgumentException("two position attributes were specified");
pos = true;
}
if (attribute.usage == Usage.Normal) {
if (nors) throw new IllegalArgumentException("two normal attributes were specified");
}
if (attribute.usage == Usage.Color || attribute.usage == Usage.ColorPacked) {
if (attribute.numComponents != 4) throw new IllegalArgumentException("color attribute must have 4 components");
if (cols) throw new IllegalArgumentException("two color attributes were specified");
cols = true;
}
}
if (pos == false) throw new IllegalArgumentException("no position attribute was specified");
}
/** @return the number of attributes */
public int size () {
return attributes.length;
}
/** @param index the index
* @return the VertexAttribute at the given index */
public VertexAttribute get (int index) {
return attributes[index];
}
public String toString () {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (int i = 0; i < attributes.length; i++) {
builder.append("(");
builder.append(attributes[i].alias);
builder.append(", ");
builder.append(attributes[i].usage);
builder.append(", ");
builder.append(attributes[i].numComponents);
builder.append(", ");
builder.append(attributes[i].offset);
builder.append(")");
builder.append("\n");
}
builder.append("]");
return builder.toString();
}
@Override
public boolean equals (final Object obj) {
if (!(obj instanceof VertexAttributes)) return false;
VertexAttributes other = (VertexAttributes)obj;
if (this.attributes.length != other.size()) return false;
for (int i = 0; i < attributes.length; i++) {
if (!attributes[i].equals(other.attributes[i])) return false;
}
return true;
}
/**
* Calculates a mask based on the contained {@link VertexAttribute} instances. The mask
* is a bit-wise or of each attributes {@link VertexAttribute#usage}.
* @return the mask
*/
public long getMask () {
if(mask == -1) {
long result = 0;
for(int i = 0; i < attributes.length; i++) {
result |= attributes[i].usage;
}
mask = result;
}
return mask;
}
}