Package codeanticode.glgraphics

Source Code of codeanticode.glgraphics.GLModel

/**
* Part of the GLGraphics library: http://glgraphics.sourceforge.net/
* Copyright (c) 2008-11 Andres Colubri
*
* This source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
*
* A copy of the GNU General Public License is available on the World
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also
* obtain it by writing to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

package codeanticode.glgraphics;

import processing.core.*;
import processing.opengl.*;
import processing.xml.XMLElement;
import javax.media.opengl.*;

import com.sun.opengl.util.BufferUtil;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;

/**
* This class holds a 3D model composed of vertices, normals, colors (per
* vertex) and texture coordinates (also per vertex). All this data is stored in
* Vertex Buffer Objects (VBO) for fast access. This is class is still
* undergoing development, the API will probably change quickly in the following
* months as features are tested and refined. In particular, with the settings
* of the VBOs in this first implementation (GL.GL_DYNAMIC_DRAW_ARB) it is
* assumed that the coordinates will change often during the lifetime of the
* model. For static models a different VBO setting (GL.GL_STATIC_DRAW_ARB)
* should be used.
*/
public class GLModel implements PConstants, GLConstants {
  protected PApplet parent;
  protected GL gl;
  protected PGraphicsOpenGL pgl;
  protected GLState glstate;
  protected int size;
  protected int vertexMode;
  protected int vboUsage;
  protected int[] vertCoordsVBO = { 0 };
  protected String description;

  protected float[] tmpVertArray;
  protected float[] tmpColorArray;
  protected float[] tmpNormalsArray;
  protected float[] tmpTexCoordsArray;
  protected float[] tmpAttributesArray;
  protected int[] tmpIndexArray;
 
  protected int[] colorsVBO = null;
  protected int[] normCoordsVBO = null;
  protected int[] texCoordsVBO = null;
  protected int[] indicesVBO = null;
 
  protected boolean autoIndexBoundCalc;
 
  protected float tintR, tintG, tintB, tintA; 
  protected float[] specularColor = { 1.0f, 1.0f, 1.0f, 1.0f };
  protected float[] emissiveColor = { 0.0f, 0.0f, 0.0f, 1.0f };
  protected float[] shininess = { 0 };

  protected float pointSize = 1;
  protected float lineWidth = 1;

  protected boolean blend;
  protected int blendMode;
 
  protected boolean usingPointSprites; 
 
  protected int numAttributes;
  protected int[] attribVBO = null;
  protected String[] attribName;
  protected int[] attribSize;
  protected int curtAttrSize;

  protected int numTextures;

  protected int minIndex;
  protected int maxIndex;
  protected int maxIndicesCount;
  protected int indicesCount;
 
  public GLTexture[] textures;

  public FloatBuffer vertices;
  public FloatBuffer colors;
  public FloatBuffer normals;
  public FloatBuffer texCoords;
  public FloatBuffer attributes;
  public IntBuffer indices;
 
  // Dimensions of the model:
  public float width;
  public float height;
  public float depth;
  // Bounding box:
  public float xmin, xmax;
  public float ymin, ymax;
  public float zmin, zmax; 
 
  public static final int STATIC = 0;
  public static final int DYNAMIC = 1;
  public static final int STREAM = 2;
 
  float maxSpriteSize;
  // Coefficients for point sprite distance attenuation function. 
  // These default values correspond to the constant sprite size.
  protected float spriteDistAtt[] = { 1.0f, 0.0f, 0.0f };
 
  /**
   * Creates an instance of GLModel with the specified parameters: number of
   * vertices, mode to draw the vertices (as points, sprites, lines, etc) and
   * usage (static if the vertices will never change after the first time are
   * initialized, dynamic if they will change frequently or stream if they will
   * change at every frame).
   *
   * @param parent  PApplet
   * @param numVert int
   * @param mode int
   * @param usage int
   */
  public GLModel(PApplet parent, int numVert, int mode, int usage) {
    initModelCommon(parent);
    size = numVert;
   
    if (mode == POINTS)
      vertexMode = GL.GL_POINTS;
    else if (mode == POINT_SPRITES) {
      vertexMode = GL.GL_POINTS;
      usingPointSprites = true;     
      maxSpriteSize = GLState.glMaxAntialiasedPointSize;
    } else if (mode == LINES)
      vertexMode = GL.GL_LINES;
    else if (mode == LINE_STRIP)
      vertexMode = GL.GL_LINE_STRIP;
    else if (mode == LINE_LOOP)
      vertexMode = GL.GL_LINE_LOOP;
    else if (mode == TRIANGLES)
      vertexMode = GL.GL_TRIANGLES;
    else if (mode == TRIANGLE_FAN)
      vertexMode = GL.GL_TRIANGLE_FAN;
    else if (mode == TRIANGLE_STRIP)
      vertexMode = GL.GL_TRIANGLE_STRIP;
    else if (mode == QUADS)
      vertexMode = GL.GL_QUADS;
    else if (mode == QUAD_STRIP)
      vertexMode = GL.GL_QUAD_STRIP;
    else if (mode == POLYGON)
      vertexMode = GL.GL_POLYGON;

    if (usage == STATIC)
      vboUsage = GL.GL_STATIC_DRAW_ARB;
    else if (usage == DYNAMIC)
      vboUsage = GL.GL_DYNAMIC_DRAW_ARB;
    else if (usage == STREAM)
      vboUsage = GL.GL_STREAM_COPY;

    vertCoordsVBO[0] = GLState.createGLResource(GL_VERTEX_BUFFER);   
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, vertCoordsVBO[0]);
    gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, size * 4
        * BufferUtil.SIZEOF_FLOAT, null, vboUsage);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);

    description = "Just another GLModel";
  }

  public GLModel(PApplet parent, float[] vertArray, int mode, int usage) {
    this(parent, vertArray.length / 4, mode, usage);
    updateVertices(vertArray);
  }

  public GLModel(PApplet parent, ArrayList<PVector> vertArrayList, int mode, int usage) {
    this(parent, vertArrayList.size(), mode, usage);
    updateVertices(vertArrayList);
  }

  public GLModel(PApplet parent, String filename) {
    initModelCommon(parent);
    this.parent = parent;

    filename = filename.replace('\\', '/');
    XMLElement xml = new XMLElement(parent, filename);

    loadXML(xml);
  }

  public GLModel(PApplet parent, URL url) {
    initModelCommon(parent);
    this.parent = parent;

    try {
      String xmlText = PApplet
          .join(PApplet.loadStrings(url.openStream()), "\n");
      XMLElement xml = new XMLElement(xmlText);
      loadXML(xml);
    } catch (IOException e) {
      System.err.println("Error loading effect: " + e.getMessage());
    }
  }

  public void delete() {
    releaseModel();
  }

  public int getMode() {
    return vertexMode;
  }
 
  public int getSize() {
    return size;
  }

  public String getDescription() {
    return description;
  }

  /**
   * Returns the OpenGL identifier of the Vertex Buffer Object holding the
   * coordinates of this model.
   *
   * @return int
   */
  public int getCoordsVBO() {
    return vertCoordsVBO[0];
  }

  /**
   * This method creates the normals, i.e.: it creates the internal OpenGL
   * variables to store normal data.
   */
  public void initNormals() {
    normCoordsVBO = new int[1];
    normCoordsVBO[0] = GLState.createGLResource(GL_VERTEX_BUFFER);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, normCoordsVBO[0]);
    gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, size * 4
        * BufferUtil.SIZEOF_FLOAT, null, vboUsage);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
  }

  /**
   * This method creates the colors, i.e.: it creates the internal OpenGL
   * variables to store color data.
   */
  public void initColors() {
    colorsVBO = new int[1];
    colorsVBO[0] = GLState.createGLResource(GL_VERTEX_BUFFER);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, colorsVBO[0]);
    gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, size * 4
        * BufferUtil.SIZEOF_FLOAT, null, vboUsage);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
  }

  /**
   * Sets the number of attributes for this model. An attribute is a vector
   * value associated to each vertex of the model, and can be used for any
   * custom calculation (lighting, deformations, etc). This custom calculations
   * can be performed using a GLModelEffect.
   *
   * @param n int
   */
  public void initAttributes(int n) {
    numAttributes = n;
    attribVBO = new int[n];
    attribName = new String[n];
    attribSize = new int[n];
    for (int i = 0; i < n; i++) {
      attribVBO[i] = GLState.createGLResource(GL_VERTEX_BUFFER);
    }
  }

  /**
   * Sets the name and size (number of components per vertex) of attribute i.
   *
   * @param i int
   * @param aname String
   * @param asize int
   */
  public void setAttribute(int i, String aname, int asize) {
    attribName[i] = aname;
    attribSize[i] = asize;

    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, attribVBO[i]);
    gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, size * asize
        * BufferUtil.SIZEOF_FLOAT, null, vboUsage);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
  }

  /**
   * This method creates n textures, i.e.: it creates the internal OpenGL
   * variables to store n textures.
   *
   * @param n int
   */
  public void initTextures(int n) {
    numTextures = n;

    texCoordsVBO = new int[numTextures];
    textures = new GLTexture[numTextures];
    for (n = 0; n < numTextures; n++) {
      texCoordsVBO[n] = GLState.createGLResource(GL_VERTEX_BUFFER);
      gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, texCoordsVBO[n]); // Bind the
                                                                   // buffer.
      gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, size * 2
          * BufferUtil.SIZEOF_FLOAT, null, vboUsage);
    }
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
  }

  /**
   * This method initializes the index array in this GLModel, capable
   * to hold up to n vertex indices. The mode of the indices is STATIC,
   * meaning that they are optimized under the assumption that won't be
   * modified.
   *
   * @param n int
   */
  public void initIndices(int n) {
    initIndices(n, STATIC);
  }

  /**
   * This method initializes the index array in this GLModel, capable
   * to hold up to n vertex indices. The usage mode of the array can
   * also be indicated, different from the usage of the model geometry
   * itself.
   *
   * @param n maximum size of index array
   * @param usage could be STATIC, DYNAMIC, or STREAM
   */ 
  public void initIndices(int n, int usage) {
    int glUsage = GL.GL_STATIC_DRAW_ARB;
    if (usage == STATIC)
      vboUsage = GL.GL_STATIC_DRAW_ARB;
    else if (usage == DYNAMIC)
      vboUsage = GL.GL_DYNAMIC_DRAW_ARB;
    else if (usage == STREAM)
      vboUsage = GL.GL_STREAM_COPY;
   
    maxIndicesCount = n;
    indicesVBO = new int[1];
    indicesVBO[0] = GLState.createGLResource(GL_VERTEX_BUFFER);
    gl.glBindBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER, indicesVBO[0]);
    gl.glBufferDataARB(GL.GL_ELEMENT_ARRAY_BUFFER, maxIndicesCount * BufferUtil.SIZEOF_INT, null, glUsage);
    gl.glBindBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
   
    minIndex = 0;
    maxIndex = size;
    autoIndexBoundCalc = true;
  }
 
  /**
   * This method enables/disables the automatic calculation of
   * index bounds (maximum and minimum).
   *
   * @param val true or false
   */  
  public void autoIndexBounds(boolean val) {
    autoIndexBoundCalc = val;
  }
 
  /**
   * Prepares the indices for updating.
   */    
  public void beginUpdateIndices() {
    gl.glBindBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER, indicesVBO[0]);
    ByteBuffer temp = gl.glMapBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER, GL.GL_WRITE_ONLY);
    indices = temp.asIntBuffer();  
  }

  /**
   * Cleans-up index updating.
   */      
  public void endUpdateIndices() {
    if (tmpIndexArray != null) {
      indices.put(tmpIndexArray);
      tmpIndexArray = null;     
    }
    indices.position(0);
    gl.glUnmapBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER);
    gl.glBindBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
  }
   
  /**
   * Updates the indices with all the values provided in the array.
   *
   * @param indexArray array with new indices
   */
  public void updateIndices(int[] indexArray) {
    updateIndices(indexArray, indexArray.length);
  }

  /**
   * Updates the indices with the values provided in the array,
   * up to the element len-1.
   *
   * @param indexArray array with new indices
   * @param len number of values to read from intexArray, starting at zero.
   */ 
  public void updateIndices(int[] indexArray, int len) {
    if (maxIndicesCount < len) {
      System.err.println("Wrong number of indices!");
    }   
   
    indicesCount = len;
    beginUpdateIndices();
    indices.put(indexArray, 0, len);
    endUpdateIndices();

    if (autoIndexBoundCalc) {
      // Looking for the minimum and maximum indices in the array provided:
     
      // This to make sure we find the new minimum and maximum indices.
      minIndex = size;
      maxIndex = -size;
     
      for (int i = 0; i < len; i++) {
        if (indexArray[i] < minIndex) minIndex = indexArray[i];
        if (maxIndex < indexArray[i]) maxIndex = indexArray[i];
      }     
    }
  }

  /**
   * Sets the minimum index value to use when rendering the model.
   *
   * @param min minimum index
   */ 
  public void setMinIndex(int min) {
    minIndex = min;
 

  /**
   * Sets the maximum index value to use when rendering the model.
   *
   * @param max maximum index
   */   
  public void setMaxIndex(int max) {
    maxIndex = max;
 
 
  /**
   * Sets the i-th texture.
   *
   * @param i int
   */
  public void setTexture(int i, GLTexture tex) {
    textures[i] = tex;
  }

  /**
   * Returns the number of textures.
   *
   * @return int
   */
  public int getNumTextures() {
    return numTextures;
  }

  /**
   * Returns the i-th texture.
   *
   * @return GLTexture
   */
  public GLTexture getTexture(int i) {
    return textures[i];
  }

  /**
   * Enables vertex updating, to be done with the
   * updateVertex()/displaceVertex() methods.
   */
  public void beginUpdateVertices() {
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, vertCoordsVBO[0]);
    ByteBuffer temp = gl.glMapBufferARB(GL.GL_ARRAY_BUFFER_ARB, GL.GL_WRITE_ONLY);
    vertices = temp.asFloatBuffer();
  }

  /**
   * Disables vertex updating.
   */
  public void endUpdateVertices() {
    if (tmpVertArray != null) {
      vertices.put(tmpVertArray);
      tmpVertArray = null;     
    }
    vertices.position(0);
    gl.glUnmapBufferARB(GL.GL_ARRAY_BUFFER_ARB);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
  }

  /**
   * Returns array list with vertices stored in binary file.
   *
   * @param String filename
   * @return ArrayList<PVector>
   */
  public ArrayList<PVector> getVertices(String filename) {
    ArrayList<PVector> res = new ArrayList<PVector>();
    loadPVectorArrayListFromBinary(filename, res, 3);
    return res;
  }

  /**
   * Saves vertices in the given array list to binary file.
   *
   * @param String  filename
   * @param ArrayList<PVector> verts
   */
  public void saveVertices(String filename, ArrayList<PVector> verts) {
    savePVectorArrayListToBinary(filename, verts, 3);
  }

  /**
   * Loads vertices from binary file into model.
   *
   * @param String filename
   */
  public void loadVertices(String filename) {
    float[] tmp = new float[4 * size];
    for (int i = 0; i < size; i++)
      tmp[4 * i + 3] = 1.0f;

    beginUpdateVertices();
    loadFloatArrayFromBinary(filename, tmp, size, 4, 3);
    vertices.put(tmp);
    endUpdateVertices();
  }

  /**
   * Saves vertices in the model to binary file.
   */
  public void saveVertices(String filename) {
    float[] tmp = new float[4 * size];

    beginUpdateVertices();
    vertices.get(tmp);
    saveFloatArrayToBinary(filename, tmp, size, 4, 3);
    endUpdateVertices();
  }

  /**
   * Updates the coordinates of vertex idx.
   *
   * @param idx int
   * @param x float
   * @param y float
   */
  public void updateVertex(int idx, float x, float y) {
    updateVertex(idx, x, y, 0, 1);
  }

  /**
   * Updates the coordinates of vertex idx.
   *
   * @param idx int
   * @param x float
   * @param y float
   * @param z float
   */
  public void updateVertex(int idx, float x, float y, float z) {
    updateVertex(idx, x, y, z, 1);
  }

  /**
   * Updates the coordinates of vertex idx.
   *
   * @param idx int
   * @param x float
   * @param y float
   * @param z  float
   * @param w float
   */
  public void updateVertex(int idx, float x, float y, float z, float w) {
    if (tmpVertArray == null) {
      tmpVertArray = new float[4 * size];
      vertices.get(tmpVertArray);
      vertices.rewind();
    }

    tmpVertArray[4 * idx + 0] = x;
    tmpVertArray[4 * idx + 1] = y;
    tmpVertArray[4 * idx + 2] = z;
    tmpVertArray[4 * idx + 3] = w;
  }

  /**
   * Adds a displacement (dx, dy) to the vertex idx.
   *
   * @param idx int
   * @param dx float
   * @param dy float
   */
  public void displaceVertex(int idx, float dx, float dy) {
    displaceVertex(idx, dx, dy, 0, 0);
  }

  /**
   * Adds a displacement (dx, dy, dz) to the vertex idx.
   *
   * @param idx int
   * @param dx float
   * @param dy float
   * @param dz float
   */
  public void displaceVertex(int idx, float dx, float dy, float dz) {
    displaceVertex(idx, dx, dy, dz, 0);
  }

  /**
   * Adds a displacement (dx, dy, dz, dw) to the vertex idx.
   *
   * @param idx int
   * @param dx float
   * @param dy float
   * @param dz float
   * @param dw float
   */
  public void displaceVertex(int idx, float dx, float dy, float dz, float dw) {
    if (tmpVertArray == null) {
      tmpVertArray = new float[4 * size];
      vertices.get(tmpVertArray);
      vertices.rewind();
    }

    tmpVertArray[4 * idx + 0] += dx;
    tmpVertArray[4 * idx + 1] += dy;
    tmpVertArray[4 * idx + 2] += dz;
    tmpVertArray[4 * idx + 3] += dw;
  }

  /**
   * Updates all the vertices using the coordinates provided in the array
   * vertArray.
   *
   * @param vertArray float[]
   */
  public void updateVertices(float[] vertArray) {
    beginUpdateVertices();
    vertices.put(vertArray);
    endUpdateVertices();
  }

  /**
   * Updates all the vertices using the coordinates provided in the array
   * vertArray.
   *
   * @param vertArrayList ArrayList<PVector>
   */
  public void updateVertices(ArrayList<PVector> vertArrayList) {
    if (vertArrayList.size() != size) {
      System.err.println("Wrong number of vertices in the array list.");
      return;
    }

    float p[] = new float[4 * size];
    for (int i = 0; i < vertArrayList.size(); i++) {
      PVector point = (PVector) vertArrayList.get(i);
      p[4 * i + 0] = point.x;
      p[4 * i + 1] = point.y;
      p[4 * i + 2] = point.z;
      p[4 * i + 3] = 1.0f;
    }
    updateVertices(p);
  }

  /**
   * Centers the model to (0, 0, 0).
   */
  public void centerVertices() {
    centerVertices(0, 0, 0);
  }

  /**
   * Centers the model to (xc, yc, 0).
   *
   * @param xc float
   * @param yc float
   */
  public void centerVertices(float xc, float yc) {
    centerVertices(xc, yc, 0);
  }

  /**
   * Centers the model to (xc, yc, zc).
   *
   * @param xc float
   * @param yc float
   * @param zc float
   */
  public void centerVertices(float xc, float yc, float zc) {
    beginUpdateVertices();
    tmpVertArray = new float[4 * size];
    vertices.get(tmpVertArray);
    vertices.rewind();

    float xave, yave, zave;
    xave = yave = zave = 0;
    for (int i = 0; i < size; i++) {
      xave += tmpVertArray[4 * i + 0];
      yave += tmpVertArray[4 * i + 1];
      zave += tmpVertArray[4 * i + 2];
    }
    xave /= size;
    yave /= size;
    zave /= size;

    for (int i = 0; i < size; i++) {
      tmpVertArray[4 * i + 0] += xc - xave;
      tmpVertArray[4 * i + 1] += yc - yave;
      tmpVertArray[4 * i + 2] += zc - zave;
    }

    endUpdateVertices();
  }

  public void updateBounds() {
    beginUpdateVertices();
    tmpVertArray = new float[4 * size];
    vertices.get(tmpVertArray);
    vertices.rewind();
   
    resetBounds();
    for (int i = 0; i < size; i++) {
      updateBounds(tmpVertArray[4 * i + 0], tmpVertArray[4 * i + 1], tmpVertArray[4 * i + 2]);     
    }
   
    endUpdateVertices();
  }
 
  public void updateBounds(int indices[], int len) {
    beginUpdateVertices();
    tmpVertArray = new float[4 * size];
    vertices.get(tmpVertArray);
    vertices.rewind();
   
    resetBounds();
    for (int n = 0; n < len; n++) {
      int i = indices[n];
      updateBounds(tmpVertArray[4 * i + 0], tmpVertArray[4 * i + 1], tmpVertArray[4 * i + 2]);     
    }
   
    endUpdateVertices();
 
   
  protected void resetBounds() {
    width = height = depth = 0;
    xmin = ymin = zmin = 10000;
    xmax = ymax = zmax = -10000;   
  }
 
 
  protected void updateBounds(float x, float y, float z) {
    xmin = PApplet.min(xmin, x);
    xmax = PApplet.max(xmax, x);
   
    ymin = PApplet.min(ymin, y);
    ymax = PApplet.max(ymax, y);

    zmin = PApplet.min(zmin, z);
    zmax = PApplet.max(zmax, z);

    width = xmax - xmin;
    height = ymax - ymin;
    depth = zmax - zmin;
 
   
  public void beginUpdateColors() {
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, colorsVBO[0]);
    ByteBuffer temp = gl.glMapBufferARB(GL.GL_ARRAY_BUFFER_ARB, GL.GL_WRITE_ONLY);
    colors = temp.asFloatBuffer();   
  }

  public void endUpdateColors() {
    if (tmpColorArray != null) {
      colors.put(tmpColorArray);
      tmpColorArray = null;
    }
    colors.position(0);
    gl.glUnmapBufferARB(GL.GL_ARRAY_BUFFER_ARB);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
  }

  /**
   * Returns array list with colors stored in binary file.
   *
   * @param String filename
   * @return ArrayList<PVector>
   */
  public ArrayList<float[]> getColors(String filename) {
    ArrayList<float[]> res = new ArrayList<float[]>();
    loadFloatArrayListFromBinary(filename, res, 4);
    return res;
  }

  /**
   * Saves colors in the given array list to binary file.
   *
   * @param String filename
   * @param ArrayList<PVector> icolors
   */
  public void saveColors(String filename, ArrayList<float[]> icolors) {
    saveFloatArrayToBinary(filename, icolors, 4);
  }

  /**
   * Loads colors from binary file into model.
   *
   * @param String filename
   */
  public void loadColors(String filename) {
    float[] tmp = new float[4 * size];

    beginUpdateColors();
    loadFloatArrayFromBinary(filename, tmp, size, 4, 4);
    colors.put(tmp);
    endUpdateColors();
  }

  /**
   * Saves colors in the model to binary file.
   */
  public void saveColors(String filename) {
    float[] tmp = new float[4 * size];

    beginUpdateColors();
    colors.get(tmp);
    saveFloatArrayToBinary(filename, tmp, size, 4, 4);
    endUpdateColors();
  }

  /**
   * Paints the vertex i with the specified gray tone.
   *
   * @param gray float
   */
  public void updateColor(int i, float gray) {
    int c = parent.color(gray);
    putColorInTmpArray(i, c);
  }

  /**
   * Paints the vertex i with the specified gray tone and alpha value.
   *
   * @param gray int
   * @param alpha int
   */
  public void updateColor(int i, int gray, int alpha) {
    int c = parent.color(gray, alpha);
    putColorInTmpArray(i, c);
  }

  /**
   * Paints the vertex i with the specified rgb color and alpha value.
   *
   * @param rgb int
   * @param alpha float
   */
  public void updateColor(int i, int rgb, float alpha) {
    int c = parent.color(rgb, alpha);
    putColorInTmpArray(i, c);
  }

  /**
   * Paints the vertex i with the specified gray tone and alpha value.
   *
   * @param gray float
   * @param alpha float
   */
  public void updateColor(int i, float gray, float alpha) {
    int c = parent.color(gray, alpha);
    putColorInTmpArray(i, c);
  }

  /**
   * Paints the vertex i with the specified color components.
   *
   * @param x int
   * @param y int
   * @param z int
   */
  public void updateColor(int i, int x, int y, int z) {
    int c = parent.color(x, y, z);
    putColorInTmpArray(i, c);
  }

  /**
   * Paints the vertex i with the specified color components.
   *
   * @param x float
   * @param y float
   * @param z float
   */
  public void updateColor(int i, float x, float y, float z) {
    int c = parent.color(x, y, z);
    putColorInTmpArray(i, c);
  }

  /**
   * Paints the vertex i with the specified color components and alpha
   * component.
   *
   * @param x int
   * @param y int
   * @param z int
   * @param a int
   */
  public void updateColor(int i, int x, int y, int z, int a) {
    int c = parent.color(x, y, z, a);
    putColorInTmpArray(i, c);
  }

  /**
   * Paints the vertex i with the specified color components and alpha
   * component.
   *
   * @param x float
   * @param y float
   * @param z float
   * @param a float
   */
  public void updateColor(int i, float x, float y, float z, float a) {
    int c = parent.color(x, y, z, a);
    putColorInTmpArray(i, c);
  }

  /**
   * Paints all vertices with the specified gray tone.
   *
   * @param gray float
   */
  public void setColors(float gray) {
    int c = parent.color(gray);
    updateAllColors(c);
  }

  /**
   * Paints all vertices with the specified gray tone and alpha value.
   *
   * @param gray  int
   * @param alpha int
   */
  public void setColors(int gray, int alpha) {
    int c = parent.color(gray, alpha);
    updateAllColors(c);
  }

  /**
   * Paints all vertices with the specified rgb color and alpha value.
   *
   * @param rgb int
   * @param alpha float
   */
  public void setColors(int rgb, float alpha) {
    int c = parent.color(rgb, alpha);
    updateAllColors(c);
  }

  /**
   * Paints all vertices with the specified gray tone and alpha value.
   *
   * @param gray float
   * @param alpha float
   */
  public void setColors(float gray, float alpha) {
    int c = parent.color(gray, alpha);
    updateAllColors(c);
  }

  /**
   * Paints all vertices with the specified color components.
   *
   * @param x int
   * @param y int
   * @param z int
   */
  public void setColors(int x, int y, int z) {
    int c = parent.color(x, y, z);
    updateAllColors(c);
  }

  /**
   * Paints all vertices with the specified color components.
   *
   * @param x float
   * @param y float
   * @param z float
   */
  public void setColors(float x, float y, float z) {
    int c = parent.color(x, y, z);
    updateAllColors(c);
  }

  /**
   * Paints all vertices with the specified color components and alpha
   * component.
   *
   * @param x int
   * @param y int
   * @param z int
   * @param a int
   */
  public void setColors(int x, int y, int z, int a) {
    int c = parent.color(x, y, z, a);
    updateAllColors(c);
  }

  /**
   * Paints all vertices with the specified color components and alpha
   * component.
   *
   * @param x float
   * @param y float
   * @param z float
   * @param a float
   */
  public void setColors(float x, float y, float z, float a) {
    int c = parent.color(x, y, z, a);
    updateAllColors(c);
  }

  public void updateColors(float[] colArray) {
    beginUpdateColors();
    colors.put(colArray);
    endUpdateColors();
  }

  public void updateColors(ArrayList<float[]> colArrayList) {
    if (colArrayList.size() != size) {
      System.err.println("Wrong number of colors in the array list.");
      return;
    }

    float p[] = new float[4 * size];
    for (int i = 0; i < colArrayList.size(); i++) {
      float[] c = (float[]) colArrayList.get(i);

      if (c.length == 4) {
        p[4 * i + 0] = c[0];
        p[4 * i + 1] = c[1];
        p[4 * i + 2] = c[2];
        p[4 * i + 3] = c[3];
      }
    }
    updateColors(p);
  }

  public void beginUpdateTexCoords(int n) {
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, texCoordsVBO[n]);
    ByteBuffer temp = gl.glMapBufferARB(GL.GL_ARRAY_BUFFER_ARB, GL.GL_WRITE_ONLY);
    texCoords = temp.asFloatBuffer();   
  }

  public void updateTexCoord(int idx, float s, float t) {
    if (tmpTexCoordsArray == null) {
      tmpTexCoordsArray = new float[2 * size];
      texCoords.get(tmpTexCoordsArray);
      texCoords.rewind();
    }

    tmpTexCoordsArray[2 * idx + 0] = s;
    tmpTexCoordsArray[2 * idx + 1] = t;
  }

  /**
   * Returns array list with texture coordinates stored in binary file.
   *
   * @param String filename
   * @return ArrayList<PVector>
   */
  public ArrayList<PVector> getTexCoords(String filename) {
    ArrayList<PVector> res = new ArrayList<PVector>();
    loadPVectorArrayListFromBinary(filename, res, 2);
    return res;
  }

  /**
   * Saves texture coordinates in the given array list to binary file.
   *
   * @param String filename
   * @param ArrayList <PVector> icolors
   */
  public void saveTexCoords(String filename, ArrayList<PVector> itexCoords) {
    savePVectorArrayListToBinary(filename, itexCoords, 2);
  }

  /**
   * Loads texture coordinates of nth texture from binary file into model.
   *
   * @param n
   * @param String filename
   */
  public void loadTexCoords(int n, String filename) {
    float[] tmp = new float[2 * size];

    beginUpdateTexCoords(n);
    loadFloatArrayFromBinary(filename, tmp, size, 2, 2);
    texCoords.put(tmp);
    endUpdateTexCoords();
  }

  /**
   * Saves colors in the model to binary file.
   */
  public void saveTexCoords(int n, String filename) {
    float[] tmp = new float[2 * size];

    beginUpdateTexCoords(n);
    texCoords.get(tmp);
    saveFloatArrayToBinary(filename, tmp, size, 2, 2);
    endUpdateTexCoords();
  }

  public void displaceTexCoord(int idx, float ds, float dt) {
    if (tmpTexCoordsArray == null) {
      tmpTexCoordsArray = new float[2 * size];
      texCoords.get(tmpTexCoordsArray);
      texCoords.rewind();
    }

    tmpTexCoordsArray[2 * idx + 0] += ds;
    tmpTexCoordsArray[2 * idx + 1] += dt;
  }

  public void endUpdateTexCoords() {
    if (tmpTexCoordsArray != null) {
      texCoords.put(tmpTexCoordsArray);
      tmpTexCoordsArray = null;
    }
    texCoords.position(0);
    gl.glUnmapBufferARB(GL.GL_ARRAY_BUFFER_ARB);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
  }

  public void updateTexCoords(int n, float[] texCoordsArray) {
    beginUpdateTexCoords(n);
    texCoords.put(texCoordsArray);
    endUpdateTexCoords();
  }

  public void updateTexCoords(int n, ArrayList<PVector> texCoordsArrayList) {
    if (texCoordsArrayList.size() != size) {
      System.err
          .println("Wrong number of texture coordinates in the array list.");
      return;
    }

    float p[] = new float[2 * size];
    for (int i = 0; i < texCoordsArrayList.size(); i++) {
      PVector point = (PVector) texCoordsArrayList.get(i);
      p[2 * i + 0] = point.x;
      p[2 * i + 1] = point.y;
    }
    updateTexCoords(n, p);
  }

  public void beginUpdateNormals() {
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, normCoordsVBO[0]);
    ByteBuffer temp = gl.glMapBufferARB(GL.GL_ARRAY_BUFFER_ARB, GL.GL_WRITE_ONLY);
    normals = temp.asFloatBuffer();
  }

  public void endUpdateNormals() {
    if (tmpNormalsArray != null) {
      normals.put(tmpNormalsArray);
      tmpNormalsArray = null;
    }
    normals.position(0);

    gl.glUnmapBufferARB(GL.GL_ARRAY_BUFFER_ARB);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
  }

  /**
   * Returns array list with normals stored in binary file.
   *
   * @param String filename
   * @return ArrayList<PVector>
   */
  public ArrayList<PVector> getNormals(String filename) {
    ArrayList<PVector> res = new ArrayList<PVector>();
    loadPVectorArrayListFromBinary(filename, res, 3);
    return res;
  }

  /**
   * Saves normals in the given array list to binary file.
   *
   * @param String filename
   * @param ArrayList<PVector> verts
   */
  public void saveNormals(String filename, ArrayList<PVector> norms) {
    savePVectorArrayListToBinary(filename, norms, 3);
  }

  /**
   * Loads normals from binary file into model.
   *
   * @param String filename
   */
  public void loadNormals(String filename) {
    float[] tmp = new float[4 * size];

    beginUpdateNormals();
    loadFloatArrayFromBinary(filename, tmp, size, 4, 3);
    normals.put(tmp);
    endUpdateNormals();
  }

  /**
   * Saves normals in the model to binary file.
   */
  public void saveNormals(String filename) {
    float[] tmp = new float[4 * size];

    beginUpdateNormals();
    normals.get(tmp);
    saveFloatArrayToBinary(filename, tmp, size, 4, 3);
    endUpdateNormals();
  }

  public void updateNormal(int idx, float x, float y) {
    updateNormal(idx, x, y, 0, 0);
  }

  public void updateNormal(int idx, float x, float y, float z) {
    updateNormal(idx, x, y, z, 0);
  }

  public void updateNormal(int idx, float x, float y, float z, float w) {
    if (tmpNormalsArray == null) {
      tmpNormalsArray = new float[4 * size];
      normals.get(tmpNormalsArray);
      normals.rewind();
    }

    tmpNormalsArray[4 * idx + 0] = x;
    tmpNormalsArray[4 * idx + 1] = y;
    tmpNormalsArray[4 * idx + 2] = z;
    tmpNormalsArray[4 * idx + 3] = w;
  }

  public void displaceNormal(int idx, float dx, float dy) {
    displaceNormal(idx, dx, dy, 0, 0);
  }

  public void displaceNormal(int idx, float dx, float dy, float dz) {
    displaceNormal(idx, dx, dy, dz, 0);
  }

  public void displaceNormal(int idx, float dx, float dy, float dz, float dw) {
    if (tmpNormalsArray == null) {
      tmpNormalsArray = new float[4 * size];
      normals.get(tmpNormalsArray);
      normals.rewind();
    }

    tmpNormalsArray[4 * idx + 0] += dx;
    tmpNormalsArray[4 * idx + 1] += dy;
    tmpNormalsArray[4 * idx + 2] += dz;
    tmpNormalsArray[4 * idx + 3] += dw;
  }

  public void updateNormals(float[] normArray) {
    beginUpdateNormals();
    normals.put(normArray);
    endUpdateNormals();
  }

  public void updateNormals(ArrayList<PVector> normArrayList) {
    if (normArrayList.size() != size) {
      System.err.println("Wrong number of normals in the array list.");
      return;
    }

    float p[] = new float[4 * size];
    for (int i = 0; i < normArrayList.size(); i++) {
      PVector point = (PVector) normArrayList.get(i);
      p[4 * i + 0] = point.x;
      p[4 * i + 1] = point.y;
      p[4 * i + 2] = point.z;
      p[4 * i + 3] = 0.0f;
    }
    updateNormals(p);
  }

  public void beginUpdateAttributes(int n) {
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, attribVBO[n]);
    ByteBuffer temp = gl.glMapBufferARB(GL.GL_ARRAY_BUFFER_ARB, GL.GL_WRITE_ONLY);
    attributes = temp.asFloatBuffer();
    curtAttrSize = attribSize[n];
  }

  public void endUpdateAttributes() {
    if (tmpAttributesArray != null) {
      attributes.put(tmpAttributesArray);
      tmpAttributesArray = null;
    }
    attributes.position(0);
    gl.glUnmapBufferARB(GL.GL_ARRAY_BUFFER_ARB);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
  }

  /**
   * Returns array list with attributes stored in binary file. Each attribute
   * has size len.
   *
   * @param String filename
   * @return int len
   */
  public ArrayList<float[]> getAttributes(String filename, int len) {
    ArrayList<float[]> res = new ArrayList<float[]>();
    loadFloatArrayListFromBinary(filename, res, len);
    return res;
  }

  /**
   * Saves attributes in the given array list to binary file. Each attribute has
   * size len.
   *
   * @param String filename
   * @param ArrayList<PVector> iattrib
   */
  public void saveAttributes(String filename, ArrayList<float[]> iattrib,
      int len) {
    saveFloatArrayToBinary(filename, iattrib, len);
  }

  /**
   * Loads attribute nth from binary file into model.
   *
   * @param String filename
   */
  public void loadAttributes(int n, String filename) {
    int len = attribSize[n];
    float[] tmp = new float[len * size];

    beginUpdateAttributes(n);
    loadFloatArrayFromBinary(filename, tmp, size, len, len);
    attributes.put(tmp);
    endUpdateAttributes();
  }

  /**
   * Saves attribute n-th in the model to binary file.
   */
  public void saveAttributes(int n, String filename) {
    int len = attribSize[n];
    float[] tmp = new float[len * size];

    beginUpdateAttributes(n);
    attributes.get(tmp);
    saveFloatArrayToBinary(filename, tmp, size, len, len);
    endUpdateAttributes();
  }

  public void updateAttribute(int idx, float x) {
    updateAttribute(idx, new float[] { x });
  }

  public void updateAttribute(int idx, float x, float y) {
    updateAttribute(idx, new float[] { x, y });
  }

  public void updateAttribute(int idx, float x, float y, float z) {
    updateAttribute(idx, new float[] { x, y, z });
  }

  public void updateAttribute(int idx, float x, float y, float z, float w) {
    updateAttribute(idx, new float[] { x, y, z, w });
  }

  public void updateAttribute(int idx, float[] values) {
    if (values.length == curtAttrSize) {
      if (tmpAttributesArray == null) {
        tmpAttributesArray = new float[curtAttrSize * size];
        attributes.get(tmpAttributesArray);
        attributes.rewind();
      }

      for (int i = 0; i < curtAttrSize; i++)
        tmpAttributesArray[curtAttrSize * idx + i] = values[i];
    }
  }

  public void displaceAttribute(int idx, float dx) {
    displaceAttribute(idx, new float[] { dx });
  }

  public void displaceAttribute(int idx, float dx, float dy) {
    displaceAttribute(idx, new float[] { dx, dy });
  }

  public void displaceAttribute(int idx, float x, float y, float z) {
    displaceAttribute(idx, new float[] { x, y, z });
  }

  public void displaceAttribute(int idx, float x, float y, float z, float w) {
    displaceAttribute(idx, new float[] { x, y, z, w });
  }

  public void displaceAttribute(int idx, float[] dvalues) {
    int l = attribSize[idx];
    if (dvalues.length == l) {
      if (tmpAttributesArray == null) {
        tmpAttributesArray = new float[l * size];
        attributes.get(tmpAttributesArray);
        attributes.rewind();
      }

      for (int i = 0; i < l; i++)
        tmpAttributesArray[l * idx + i] += dvalues[i];
    }
  }

  public void updateAttributes(int n, float[] attributesArray) {
    beginUpdateAttributes(n);
    attributes.put(attributesArray);
    endUpdateAttributes();
  }

  public void updateAttributes(int n, ArrayList<float[]> vertAttribsArrayList) {
    if (vertAttribsArrayList.size() != size) {
      System.err
          .println("Wrong number of vertex attributes in the array list.");
      return;
    }

    int l = attribSize[n];
    float p[] = new float[l * size];
    for (int i = 0; i < vertAttribsArrayList.size(); i++) {
      float[] attrib = (float[]) vertAttribsArrayList.get(i);

      for (int j = 0; j < l; j++)
        p[l * i + j] = attrib[j];
    }
    updateAttributes(n, p);
  }

  public void setLineWidth(float w) {
    lineWidth = w;
  }

  public void setPointSize(float s) {
    pointSize = PApplet.min(GLState.glMaxAntialiasedPointSize, s);
  }
 
  public float getMaxPointSize() {
    return GLState.glMaxAntialiasedPointSize;
  }
 
  /**
   * Sets the maximum sprite size (which is capped by the
   * maximum point size).
   */   
  public void setMaxSpriteSize(float s) {
    maxSpriteSize = PApplet.min(GLState.glMaxAntialiasedPointSize, s);
  }

  /**
   * Sets the sprite size to be constant and equal to s.
   */ 
  public void setSpriteSize(float s) {
    setMaxSpriteSize(s);
    spriteDistAtt[1] = 0;
    spriteDistAtt[2] = 0;   
  }
 
  /**
   * Sets the sprite distance attenuation function for sprites using
   * quadratic dependence on the distance.
   */
  public void setSpriteSize(float s, float d) {
    setSpriteSize(s, d, true);
  }
 
  /**
   * Sets the sprite distance attenuation function for sprites such that
   * the sprite size at distance d from the camera is exactly s. The dependence
   * on the distance is quadratic (smax/(1+d^2)) or linear (smax/(1+d))
   * depending on the value of the argument quadratic. smax is the maximum
   * sprite size.
   */ 
  public void setSpriteSize(float s, float d, boolean quadratic) {
    float s0 = maxSpriteSize;
    if (quadratic) {
      spriteDistAtt[1] = 0;
      spriteDistAtt[2] = (s0 - s) / (d * d * s);     
    } else {
      spriteDistAtt[1] = (s0 - s) / (d * s);
      spriteDistAtt[2] = 0;
   
  }

  /**
   * Disables blending.
   */
  public void noBlend() {
    blend = false;
  }

  /**
   * Enables blending and sets the mode.
   *
   * @param MODE int
   */
  public void setBlendMode(int MODE) {
    blend = true;
    blendMode = MODE;
 
 
  /**
   * Set the tint color to the specified gray tone.
   *
   * @param gray float
   */
  public void setTint(float gray) {
    int c = parent.color(gray);
    setTintColor(c);
  }

  /**
   * Set the tint color to the specified gray tone and alpha value.
   *
   * @param gray int
   * @param alpha int
   */
  public void setTint(int gray, int alpha) {
    int c = parent.color(gray, alpha);
    setTintColor(c);
  }

  /**
   * Set the tint color to the specified rgb color and alpha value.
   *
   * @param rgb int
   * @param alpha float
   */
  public void setTint(int rgb, float alpha) {
    int c = parent.color(rgb, alpha);
    setTintColor(c);
  }

  /**
   * Set the tint color to the specified gray tone and alpha value.
   *
   * @param gray float
   * @param alpha float
   */
  public void setTint(float gray, float alpha) {
    int c = parent.color(gray, alpha);
    setTintColor(c);
  }

  /**
   * Set the tint color to the specified color components.
   *
   * @param x int
   * @param y int
   * @param z int
   */
  public void setTint(int x, int y, int z) {
    int c = parent.color(x, y, z);
    setTintColor(c);
  }

  /**
   * Set the tint color to the specified color components.
   *
   * @param x float
   * @param y float
   * @param z float
   */
  public void setTint(float x, float y, float z) {
    int c = parent.color(x, y, z);
    setTintColor(c);
  }

  /**
   * Set the tint color to the specified color components and alpha component.
   *
   * @param x int
   * @param y int
   * @param z int
   * @param a int
   */
  public void setTint(int x, int y, int z, int a) {
    int c = parent.color(x, y, z, a);
    setTintColor(c);
  }

  /**
   * Set the tint color to the specified color components and alpha component.
   *
   * @param x float
   * @param y float
   * @param z float
   * @param a float
   */
  public void setTint(float x, float y, float z, float a) {
    int c = parent.color(x, y, z, a);
    setTintColor(c);
  }

  /**
   * Set the tint color to solid white.
   *
   */ 
  public void noTint() {
    int c = parent.color(255, 255);
    setTintColor(c);
  }
 
  protected void setTintColor(int color) {
    int ir, ig, ib, ia;

    ia = (color >> 24) & 0xff;
    ir = (color >> 16) & 0xff;
    ig = (color >> 8) & 0xff;
    ib = color & 0xff;

    tintA = ia / 255.0f;
    tintR = ir / 255.0f;
    tintG = ig / 255.0f;
    tintB = ib / 255.0f;
  }

  /**
   * Set the specular color to the specified gray tone.
   *
   * @param gray float
   */
  public void setReflection(float gray) {
    int c = parent.color(gray);
    setSpecularColor(c);
  }

  /**
   * Set the specular color to the specified gray tone and alpha value.
   *
   * @param gray int
   * @param alpha int
   */
  public void setReflection(int gray, int alpha) {
    int c = parent.color(gray, alpha);
    setSpecularColor(c);
  }

  /**
   * Set the specular color to the specified rgb color and alpha value.
   *
   * @param rgb int
   * @param alpha float
   */
  public void setReflection(int rgb, float alpha) {
    int c = parent.color(rgb, alpha);
    setSpecularColor(c);
  }

  /**
   * Set the specular color to the specified gray tone and alpha value.
   *
   * @param gray float
   * @param alpha float
   */
  public void setReflection(float gray, float alpha) {
    int c = parent.color(gray, alpha);
    setSpecularColor(c);
  }

  /**
   * Set the specular color to the specified color components.
   *
   * @param x int
   * @param y int
   * @param z int
   */
  public void setReflection(int x, int y, int z) {
    int c = parent.color(x, y, z);
    setSpecularColor(c);
  }

  /**
   * Set the specular color to the specified color components.
   *
   * @param x float
   * @param y float
   * @param z float
   */
  public void setReflection(float x, float y, float z) {
    int c = parent.color(x, y, z);
    setSpecularColor(c);
  }

  /**
   * Set the specular color to the specified color components and alpha
   * component.
   *
   * @param x int
   * @param y int
   * @param z int
   * @param a int
   */
  public void setReflection(int x, int y, int z, int a) {
    int c = parent.color(x, y, z, a);
    setSpecularColor(c);
  }

  /**
   * Set the specular color to the specified color components and alpha
   * component.
   *
   * @param x float
   * @param y float
   * @param z float
   * @param a float
   */
  public void setReflection(float x, float y, float z, float a) {
    int c = parent.color(x, y, z, a);
    setSpecularColor(c);
  }

  protected void setSpecularColor(int color) {
    int ir, ig, ib, ia;

    ia = (color >> 24) & 0xff;
    ir = (color >> 16) & 0xff;
    ig = (color >> 8) & 0xff;
    ib = color & 0xff;

    specularColor[0] = ir / 255.0f;
    specularColor[1] = ig / 255.0f;
    specularColor[2] = ib / 255.0f;
    specularColor[3] = ia / 255.0f;
  }

  /**
   * Set the emissive color to the specified gray tone.
   *
   * @param gray float
   */
  public void setEmission(float gray) {
    int c = parent.color(gray);
    setEmissiveColor(c);
  }

  /**
   * Set the emissive color to the specified gray tone and alpha value.
   *
   * @param gray int
   * @param alpha int
   */
  public void setEmission(int gray, int alpha) {
    int c = parent.color(gray, alpha);
    setEmissiveColor(c);
  }

  /**
   * Set the emissive color to the specified rgb color and alpha value.
   *
   * @param rgb int
   * @param alpha float
   */
  public void setEmission(int rgb, float alpha) {
    int c = parent.color(rgb, alpha);
    setEmissiveColor(c);
  }

  /**
   * Set the emissive color to the specified gray tone and alpha value.
   *
   * @param gray float
   * @param alpha float
   */
  public void setEmission(float gray, float alpha) {
    int c = parent.color(gray, alpha);
    setEmissiveColor(c);
  }

  /**
   * Set the emissive color to the specified color components.
   *
   * @param x int
   * @param y int
   * @param z int
   */
  public void setEmission(int x, int y, int z) {
    int c = parent.color(x, y, z);
    setEmissiveColor(c);
  }

  /**
   * Set the emissive color to the specified color components.
   *
   * @param x float
   * @param y float
   * @param z float
   */
  public void setEmission(float x, float y, float z) {
    int c = parent.color(x, y, z);
    setEmissiveColor(c);
  }

  /**
   * Set the emissive color to the specified color components and alpha
   * component.
   *
   * @param x int
   * @param y int
   * @param z int
   * @param a int
   */
  public void setEmission(int x, int y, int z, int a) {
    int c = parent.color(x, y, z, a);
    setEmissiveColor(c);
  }

  /**
   * Set the emissive color to the specified color components and alpha
   * component.
   *
   * @param x float
   * @param y float
   * @param z float
   * @param a float
   */
  public void setEmission(float x, float y, float z, float a) {
    int c = parent.color(x, y, z, a);
    setEmissiveColor(c);
  }

  public void setShininess(float val) {
    shininess[0] = val;
  }
 
  protected void setEmissiveColor(int color) {
    int ir, ig, ib, ia;

    ia = (color >> 24) & 0xff;
    ir = (color >> 16) & 0xff;
    ig = (color >> 8) & 0xff;
    ib = color & 0xff;

    emissiveColor[0] = ir / 255.0f;
    emissiveColor[1] = ig / 255.0f;
    emissiveColor[2] = ib / 255.0f;
    emissiveColor[3] = ia / 255.0f;
  }

  public void render() {
    if (indicesVBO == null) {
      render(0, size - 1, null);
    } else {
      render(0, indicesCount, null);
    }
  }

  public void render(GLModelEffect effect) {
    if (indicesVBO == null) {
      render(0, size - 1, effect);
    } else {
      render(0, indicesCount, effect);
    }
  }

  public void render(int first, int last) {
    render(first, last, null);
  }

  public void render(int first, int last, GLModelEffect effect) {
    // Note about color/lights in Processing/OPENGL/GLGraphics.
    // Lighting is based on the assumption that color material tracking is enabled
    // and set to AMBIENT_AND_DIFFUSE, meaning that the ambient and diffuse components
    // of the material properties of vertices will be taken from the color set with
    // glColor() (or copied with a color buffer). This works in coordination with
    // the light setup in GLGraphics (see the implementation of glEnableLights
    // where you have:
    // gl.glEnable(GL.GL_COLOR_MATERIAL);
    // gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE);
    // For more flexible material/lighting setups, the best option is just to
    // override the built-in behaviour using OpenGL. This tutorial is quite
    // useful in this regard:
    // http://www.sjbaker.org/steve/omniv/opengl_lighting.html
    if (colorsVBO == null) {
      gl.glColor4f(tintR, tintG, tintB, tintA);
    }
   
    glstate.saveBlendConfig();
    if (blend) {
     glstate.enableBlend();
     glstate.setupBlending(blendMode);
    } else {
      glstate.disableBlend();
    }
   
    // Setting specular and emissive colors.    
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, specularColor, 0);   
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_EMISSION, emissiveColor, 0);
   
    // Setting shininess.
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SHININESS, shininess, 0);

    gl.glLineWidth(lineWidth);
    if (!usingPointSprites) {
      gl.glPointSize(pointSize);
    }

    if (effect != null)
      effect.start();

    if (normCoordsVBO != null) {
      gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
      gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, normCoordsVBO[0]);
      gl.glNormalPointer(GL.GL_FLOAT, 4 * BufferUtil.SIZEOF_FLOAT, 0);
    }

    if (colorsVBO != null) {
      gl.glEnableClientState(GL.GL_COLOR_ARRAY);
      gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, colorsVBO[0]);
      gl.glColorPointer(4, GL.GL_FLOAT, 0, 0);
    }

    if (indicesVBO != null) {
      gl.glBindBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER, indicesVBO[0]);
    }
   
    if (texCoordsVBO != null) {
      gl.glEnable(textures[0].getTextureTarget());

      // Binding texture units.
      for (int n = 0; n < numTextures; n++) {
        textures[n].bind(n);
      }

      if (usingPointSprites) {
        // Texturing with point sprites.
        gl.glEnable(GL.GL_POINT_SPRITE_ARB);
       
        // The alpha of a point is calculated to allow the fading of points
        // instead of shrinking them past a defined threshold size. The threshold
        // is defined by GL_POINT_FADE_THRESHOLD_SIZE and is not clamped to the
        // minimum and maximum point sizes.
        gl.glPointParameterfARB(GL.GL_POINT_FADE_THRESHOLD_SIZE_ARB, 0.6f * maxSpriteSize);
        gl.glPointParameterfARB(GL.GL_POINT_SIZE_MIN_ARB, 1.0f);
        gl.glPointParameterfARB(GL.GL_POINT_SIZE_MAX_ARB, maxSpriteSize);
        gl.glPointSize(maxSpriteSize);
       
        // This is how will our point sprite's size will be modified by
        // distance from the viewer:
        // actualSize = pointSize / sqrt(p[0] + p[1] * d + p[2] * d * d)
        // where pointSize is the value set with glPointSize(), clamped to the extreme values
        // in glPointParameterf(GL11.GL_POINT_SIZE_MIN/GL11.GL_POINT_SIZE_MAX.
        // d is the distance from the point sprite to the camera and p is the array parameter
        // passed in the following call:
        gl.glPointParameterfvARB(GL.GL_POINT_DISTANCE_ATTENUATION, spriteDistAtt, 0);

        // Specify point sprite texture coordinate replacement mode for each
        // texture unit
        gl.glTexEnvf(GL.GL_POINT_SPRITE_ARB, GL.GL_COORD_REPLACE_ARB, GL.GL_TRUE);
      } else {
        // Regular texturing.
        gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY);
        for (int n = 0; n < numTextures; n++) {
          gl.glClientActiveTexture(GL.GL_TEXTURE0 + n);
          gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, texCoordsVBO[n]);
          gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, 0);
        }
      }

      if (effect != null)
        effect.setTextures(textures);
    }

    // Drawing the vertices:
    gl.glEnableClientState(GL.GL_VERTEX_ARRAY);

    // ...with their attributes.
    if (effect != null) {
      effect.enableVertexAttribs();
     
      effect.setVertexAttribs(attribVBO, attribName, attribSize);     
    }

    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, vertCoordsVBO[0]);

    // The vertices in the array have 4 components: x, y, z, w. If the user
    // doesn't explicity specify w, then it is set to 1 by default.
    gl.glVertexPointer(4, GL.GL_FLOAT, 0, 0);

    if (indicesVBO == null) {
      gl.glDrawArrays(vertexMode, first, last - first + 1);
    } else {
      // The meaning for the minIndex and maxIndex arguments is discussed in this thread:
      // http://www.gamedev.net/topic/331317-trouble-with-gldrawrangeelements/
      gl.glDrawRangeElements(vertexMode, minIndex, maxIndex, last - first + 1, GL.GL_UNSIGNED_INT, first * BufferUtil.SIZEOF_INT);
    }

    if (effect != null)
      effect.disableVertexAttribs();

    gl.glBindBuffer(GL.GL_ARRAY_BUFFER_ARB, 0);
    gl.glDisableClientState(GL.GL_VERTEX_ARRAY);

    if (texCoordsVBO != null) {
      if (usingPointSprites) {       
        gl.glPointParameterfARB(GL.GL_POINT_SIZE_MIN_ARB, 1.0f);
        gl.glPointParameterfARB(GL.GL_POINT_SIZE_MAX_ARB, GLState.glMaxAntialiasedPointSize);
       
        gl.glPointSize(pgl.strokeWeight);
        gl.glDisable(GL.GL_POINT_SPRITE_ARB);
      } else {
        for (int n = 0; n < numTextures; n++) {
          gl.glClientActiveTexture(GL.GL_TEXTURE0 + n);
          gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
        }
        gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);
      }     
      for (int n = 0; n < numTextures; n++) {
        textures[n].unbind();
      }            
      gl.glDisable(textures[0].getTextureTarget());
    }
    if (colorsVBO != null) {
      gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
      gl.glDisableClientState(GL.GL_COLOR_ARRAY);
    }
    if (normCoordsVBO != null) {
      gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);
      gl.glDisableClientState(GL.GL_NORMAL_ARRAY);
    }
    if (indicesVBO != null) {
      gl.glBindBufferARB(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
    }

    if (effect != null)
      effect.stop();
   
    // Restoring state for Processing:   
    glstate.restoreBlendConfig();   

    gl.glLineWidth(pgl.strokeWeight);
    if (!usingPointSprites) {
      gl.glPointSize(pgl.strokeWeight)
      pgl.strokeWeight(pgl.strokeWeight);
    }
   
    gl.glEnable(GL.GL_COLOR_MATERIAL);
    gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE);
    gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR);
  }
 
  // /////////////////////////////////////////////////////////////////////////////////
  // Saving, loading from binary.

  protected void loadPVectorArrayListFromBinary(String filename,
      ArrayList<PVector> data, int nelem) {
    try {
      FileInputStream fis = new FileInputStream(parent.dataPath("") + filename);
      DataInputStream dis = new DataInputStream(fis);

      while (dis.available() > 2) {
        float x, y, z;
        x = y = z = 0;
        if (1 <= nelem)
          x = dis.readShort() / 100f;
        if (2 <= nelem)
          y = dis.readShort() / 100f;
        if (3 <= nelem)
          z = dis.readShort() / 100f;

        PVector thisLoc = new PVector(x, y, z);
        data.add(thisLoc);
      }
      fis.close();
    } catch (Exception e) {
      System.out.println("Exception: " + e);
    }
  }

  protected void savePVectorArrayListToBinary(String fileName,
      ArrayList<PVector> data, int nelem) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baos);
    for (int i = 0; i < data.size(); i++) {
      PVector loc = (PVector) data.get(i);
      try {
        if (1 <= nelem)
          dos.writeShort((short) (loc.x * 100f));
        if (2 <= nelem)
          dos.writeShort((short) (loc.y * 100f));
        if (3 <= nelem)
          dos.writeShort((short) (loc.z * 100f));
        dos.flush();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    byte[] saveBytes = baos.toByteArray();
    parent.saveBytes(fileName, saveBytes);
  }

  protected void loadFloatArrayListFromBinary(String filename,
      ArrayList<float[]> data, int nelem) {
    try {
      FileInputStream fis = new FileInputStream(parent.dataPath("") + filename);
      DataInputStream dis = new DataInputStream(fis);

      while (dis.available() > 2) {
        float[] loc = new float[nelem];
        for (int k = 0; k < nelem; k++)
          loc[k] = dis.readShort() / 100f;
        data.add(loc);
      }
      fis.close();
    } catch (Exception e) {
      System.out.println("Exception: " + e);
    }
  }

  protected void saveFloatArrayToBinary(String fileName,
      ArrayList<float[]> data, int nelem) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baos);
    for (int i = 0; i < data.size(); i++) {
      float[] loc = (float[]) data.get(i);
      try {
        for (int k = 0; k < nelem; k++)
          dos.writeShort((short) (loc[k] * 100f));
        dos.flush();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    byte[] saveBytes = baos.toByteArray();
    parent.saveBytes(fileName, saveBytes);
  }

  protected void loadFloatArrayFromBinary(String filename, float[] data,
      int nsize, int nelem, int nsave) {
    try {
      FileInputStream fis = new FileInputStream(parent.dataPath("") + filename);
      DataInputStream dis = new DataInputStream(fis);

      for (int n = 0; n < nsize; n++) {
        for (int k = 0; k < nsave; k++)
          //data[nelem * n + k] = dis.readShort() / 100f;
          data[nelem * n + k] = dis.readFloat();
        if (dis.available() <= 2)
          break;
      }

      fis.close();
    } catch (Exception e) {
      System.out.println("Exception: " + e);
    }
  }

  protected void saveFloatArrayToBinary(String fileName, float[] data,
      int nsize, int nelem, int nsave) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baos);
    for (int n = 0; n < nsize; n++) {
      try {
        for (int k = 0; k < nsave; k++)
          dos.writeFloat(data[nelem * n + k])
          //dos.writeShort((short) (data[nelem * n + k] * 100f));
        dos.flush();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    byte[] saveBytes = baos.toByteArray();
    parent.saveBytes(fileName, saveBytes);
  }

  /**
   * Sets the positions corresponding to vertex i in the tmpColorArray to the
   * specified color.
   *
   * @param i int
   * @param color int
   */
  protected void putColorInTmpArray(int i, int color) {
    int ir, ig, ib, ia;

    if (tmpColorArray == null) {
      tmpColorArray = new float[4 * size];
      colors.get(tmpColorArray);
      colors.rewind();
    }

    ia = (color >> 24) & 0xff;
    ir = (color >> 16) & 0xff;
    ig = (color >> 8) & 0xff;
    ib = color & 0xff;

    tmpColorArray[4 * i + 0] = ir / 255.0f;
    tmpColorArray[4 * i + 1] = ig / 255.0f;
    tmpColorArray[4 * i + 2] = ib / 255.0f;
    tmpColorArray[4 * i + 3] = ia / 255.0f;
  }

  /**
   * Sets all the vertices with the specified color.
   *
   * @param color int
   */
  protected void updateAllColors(int color) {
    int ir, ig, ib, ia;
    float fr, fg, fb, fa;

    beginUpdateColors();
    if (tmpColorArray == null) {
      tmpColorArray = new float[4 * size];
      colors.get(tmpColorArray);
      colors.rewind();
    }

    ia = (color >> 24) & 0xff;
    ir = (color >> 16) & 0xff;
    ig = (color >> 8) & 0xff;
    ib = color & 0xff;

    fa = ia / 255.0f;
    fr = ir / 255.0f;
    fg = ig / 255.0f;
    fb = ib / 255.0f;

    for (int i = 0; i < size; i++) {
      tmpColorArray[4 * i + 0] = fr;
      tmpColorArray[4 * i + 1] = fg;
      tmpColorArray[4 * i + 2] = fb;
      tmpColorArray[4 * i + 3] = fa;
    }
    endUpdateColors();
  }

  protected void initModelCommon(PApplet parent) {
    this.parent = parent;
    pgl = (PGraphicsOpenGL) parent.g;
    gl = pgl.gl;

    glstate = new GLState(gl);
   
    tintR = tintG = tintB = tintA = 1.0f;
    shininess[0] = 0.0f;

    pointSize = 1.0f;
    lineWidth = 1.0f;
    usingPointSprites = false;
   
    blend = true;
    blendMode = BLEND;

    tmpVertArray = null;
    tmpColorArray = null;
    tmpNormalsArray = null;
    tmpTexCoordsArray = null;
    tmpAttributesArray = null;
  }

  protected void releaseModel() {
    if (vertCoordsVBO[0] != 0) {
      GLState.deleteGLResource(vertCoordsVBO[0], GL_VERTEX_BUFFER);
    }

    if (colorsVBO != null && colorsVBO[0] != 0) {
      GLState.deleteGLResource(colorsVBO[0], GL_VERTEX_BUFFER);
    }

    if (normCoordsVBO != null && normCoordsVBO[0] != 0) {
      GLState.deleteGLResource(normCoordsVBO[0], GL_VERTEX_BUFFER);
    }

    if (texCoordsVBO != null && texCoordsVBO[0] != 0) {
      for (int n = 0; n < numTextures; n++) {
        GLState.deleteGLResource(texCoordsVBO[n], GL_VERTEX_BUFFER)
      }
    }

    if (indicesVBO != null && indicesVBO[0] != 0) {
      GLState.deleteGLResource(indicesVBO[0], GL_VERTEX_BUFFER);
    }   
   
    if (attribVBO != null && attribVBO[0] != 0) {
      for (int n = 0; n < numAttributes; n++) {
        GLState.deleteGLResource(attribVBO[n], GL_VERTEX_BUFFER)
      }
    }   
  }
 
  @SuppressWarnings("unchecked")
  protected void loadXML(XMLElement xml) {
    int n = xml.getChildCount();
    String name, content;
    XMLElement child;

    GLTexture[] texturesList;
    ArrayList<PVector> verticesList;
    ArrayList<PVector>[] texCoordsList;
    ArrayList<float[]>[] vertexAttribsList;
    ArrayList<PVector> normalsList;
    ArrayList<float[]> colorsList;
    String[] texNames;
    String[] attrNames;
    int[] attrSizes;

    texturesList = null;
    verticesList = new ArrayList<PVector>();
    texCoordsList = null;
    vertexAttribsList = null;
    normalsList = new ArrayList<PVector>();
    colorsList = new ArrayList<float[]>();
    texNames = null;
    attrNames = null;
    attrSizes = null;

    for (int i = 0; i < n; i++) {
      child = xml.getChild(i);
      name = child.getName();
      if (name.equals("description")) {
        description = child.getContent();
      } else if (name.equals("size")) {
        size = PApplet.parseInt(child.getContent());
      } else if (name.equals("geometry")) {
        content = child.getContent();
        vertexMode = GLUtils.parsePrimitive(content);
        if (vertexMode == GL.GL_POINTS && content.equals("POINT_SPRITES")) {
          vertexMode = GL.GL_POINTS;
          usingPointSprites = true;
          maxSpriteSize = GLState.glMaxAntialiasedPointSize;
        }
      } else if (name.equals("mode")) {
        vboUsage = GLUtils.parseVBOMode(child.getContent());
      } else if (name.equals("textures")) {
        int ntex = child.getChildCount();
        texturesList = new GLTexture[ntex];
        texNames = new String[ntex];
        texCoordsList = new ArrayList[ntex];

        loadTextures(child, texturesList, texCoordsList, texNames);
      } else if (name.equals("vertexattribs")) {
        int nattr = child.getChildCount();

        vertexAttribsList = new ArrayList[nattr];
        attrNames = new String[nattr];
        attrSizes = new int[nattr];

        loadVertexAttribs(child, vertexAttribsList, attrNames, attrSizes);
      } else if (name.equals("vertices")) {
        String binfile = child.getString("file");
        if (binfile != null)
          loadVertices(binfile, verticesList);
        else
          loadVertices(child, verticesList);
      } else if (name.equals("texcoords")) {
        if (texCoordsList != null) {
          int unit = child.getInt("unit");
          if (texCoordsList[unit] != null) {
            String binfile = child.getString("file");
            if (binfile != null)
              loadTexCoords(binfile, texCoordsList[unit]);
            else
              loadTexCoords(child, texCoordsList[unit]);
          }
        }
      } else if (name.equals("colors")) {
        String binfile = child.getString("file");
        if (binfile != null)
          loadColors(binfile, colorsList);
        else
          loadColors(child, colorsList);
      } else if (name.equals("normals")) {
        String binfile = child.getString("file");
        if (binfile != null)
          loadNormals(binfile, normalsList);
        else
          loadNormals(child, normalsList);
      } else if (name.equals("attribs")) {
        if (vertexAttribsList != null && attrSizes != null) {
          int num = child.getInt("number");
          if (vertexAttribsList[num] != null) {
            String binfile = child.getString("file");
            if (binfile != null)
              loadVertexAttrib(binfile, vertexAttribsList[num], attrSizes[num]);
            else
              loadVertexAttrib(child, vertexAttribsList[num], attrSizes[num]);
          }
        }
      }
    }

    vertCoordsVBO[0] = GLState.createGLResource(GL_VERTEX_BUFFER);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, vertCoordsVBO[0]);
    gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, size * 4
        * BufferUtil.SIZEOF_FLOAT, null, vboUsage);
    gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, 0);

    updateVertices(verticesList);

    int ntex = texturesList.length;
    if (0 < ntex) {
      initTextures(ntex);
      GLTexture tex;
      ArrayList<PVector> tcoords;

      for (int j = 0; j < ntex; j++) {
        tex = texturesList[j];
        setTexture(j, tex);
        // It should be something like:
        // setTexture(j, tex, texNames[j]);
        // but texture names are still not used.

        tcoords = (ArrayList<PVector>) texCoordsList[j];
        if (tcoords.size() == size)
          updateTexCoords(j, tcoords);
      }
    }

    if (normalsList.size() == size) {
      initNormals();
      updateNormals(normalsList);
    }

    if (colorsList.size() == size) {
      initColors();
      updateColors(colorsList);
    }

    int nattr = vertexAttribsList.length;
    if (0 < nattr) {
      initAttributes(nattr);
      ArrayList<float[]> attribs;

      for (int j = 0; j < nattr; j++) {
        setAttribute(j, attrNames[j], attrSizes[j]);

        attribs = vertexAttribsList[j];
        updateAttributes(j, attribs);
      }
    }
  }

  protected void loadTextures(XMLElement xml, GLTexture[] texturesList,
      ArrayList<PVector>[] texCoordsList, String[] texNames) {
    int n = xml.getChildCount();
    XMLElement child;
    String name;

    String unitStr, fn;
    int unit;
    for (int i = 0; i < n; i++) {
      child = xml.getChild(i);
      name = child.getName();
      if (name.equals("texture")) {
        unitStr = child.getContent();
        unit = PApplet.parseInt(unitStr);

        texCoordsList[unit] = new ArrayList<PVector>();

        texNames[unit] = child.getString("name");
        fn = child.getString("file");
        texturesList[unit] = new GLTexture(parent, fn);
        texturesList[unit].setName(texNames[unit]);
      }
    }
  }

  protected void loadVertexAttribs(XMLElement xml,
      ArrayList<float[]>[] vertexAttribsList, String[] attrNames,
      int[] attrSizes) {
    int n = xml.getChildCount();
    XMLElement child;
    String name;

    String numStr;
    int num;
    for (int i = 0; i < n; i++) {
      child = xml.getChild(i);
      name = child.getName();
      if (name.equals("vertexattrib")) {
        numStr = child.getContent();
        num = PApplet.parseInt(numStr);

        vertexAttribsList[num] = new ArrayList<float[]>();

        attrNames[num] = child.getString("name");
        attrSizes[num] = child.getInt("size");
      }
    }
  }

  protected void loadVertices(XMLElement xml, ArrayList<PVector> verticesList) {
    int n = xml.getChildCount();
    XMLElement child;
    String name;

    String coordStr;
    float[] coord;
    for (int i = 0; i < n; i++) {
      child = xml.getChild(i);
      name = child.getName();
      if (name.equals("vertex")) {
        coordStr = child.getContent();
        coord = PApplet.parseFloat(PApplet.split(coordStr, ' '));

        if (coord.length == 3)
          verticesList.add(new PVector(coord[0], coord[1], coord[2]));
      }
    }
  }

  protected void loadVertices(String binaryFN, ArrayList<PVector> verticesList) {
    loadPVectorArrayListFromBinary(binaryFN, verticesList, 3);
  }

  protected void loadTexCoords(XMLElement xml, ArrayList<PVector> texCoordsList) {
    int n = xml.getChildCount();
    XMLElement child;
    String name;

    String coordStr;
    float[] coord;
    for (int i = 0; i < n; i++) {
      child = xml.getChild(i);
      name = child.getName();
      if (name.equals("texcoord")) {
        coordStr = child.getContent();
        coord = PApplet.parseFloat(PApplet.split(coordStr, ' '));

        if (coord.length == 2)
          texCoordsList.add(new PVector(coord[0], coord[1]));
      }
    }
  }

  protected void loadTexCoords(String binaryFN, ArrayList<PVector> texCoordsList) {
    loadPVectorArrayListFromBinary(binaryFN, texCoordsList, 2);
  }

  protected void loadColors(XMLElement xml, ArrayList<float[]> colorsList) {
    int n = xml.getChildCount();
    XMLElement child;
    String name;

    String coordStr;
    float[] coord;
    for (int i = 0; i < n; i++) {
      child = xml.getChild(i);
      name = child.getName();
      if (name.equals("color")) {
        coordStr = child.getContent();
        coord = PApplet.parseFloat(PApplet.split(coordStr, ' '));

        if (coord.length == 4)
          colorsList.add(coord);
      }
    }
  }

  protected void loadColors(String binaryFN, ArrayList<float[]> colorsList) {
    loadFloatArrayListFromBinary(binaryFN, colorsList, 4);
  }

  protected void loadNormals(XMLElement xml, ArrayList<PVector> normalsList) {
    int n = xml.getChildCount();
    XMLElement child;
    String name;

    String coordStr;
    float[] coord;
    for (int i = 0; i < n; i++) {
      child = xml.getChild(i);
      name = child.getName();
      if (name.equals("normal")) {
        coordStr = child.getContent();
        coord = PApplet.parseFloat(PApplet.split(coordStr, ' '));

        if (coord.length == 3)
          normalsList.add(new PVector(coord[0], coord[1], coord[2]));
      }
    }
  }

  protected void loadNormals(String binaryFN, ArrayList<PVector> normalsList) {
    loadPVectorArrayListFromBinary(binaryFN, normalsList, 3);
  }

  protected void loadVertexAttrib(XMLElement xml,
      ArrayList<float[]> vertexAttribsList, int attrSize) {
    int n = xml.getChildCount();
    XMLElement child;
    String name;

    String coordStr;
    float[] coord;
    for (int i = 0; i < n; i++) {
      child = xml.getChild(i);
      name = child.getName();
      if (name.equals("attrib")) {
        coordStr = child.getContent();
        coord = PApplet.parseFloat(PApplet.split(coordStr, ' '));

        if (coord.length == attrSize)
          vertexAttribsList.add(coord);
      }
    }
  }

  protected void loadVertexAttrib(String binaryFN,
      ArrayList<float[]> vertexAttribsList, int attrSize) {
    loadFloatArrayListFromBinary(binaryFN, vertexAttribsList, attrSize);
  }
}
TOP

Related Classes of codeanticode.glgraphics.GLModel

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.