/*******************************************************************************
* 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;
/**
* 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 = 0;
public static final int Color = 1;
public static final int ColorPacked = 5;
public static final int Normal = 2;
public static final int TextureCoordinates = 3;
public static final int Generic = 4;
}
/** the attributes in the order they were specified **/
private final VertexAttribute[] attributes;
/** the size of a single vertex in bytes **/
public final int vertexSize;
/** 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;
}
}