Cleanup seperation of Legacy and user attribs.  All user programs now use the new names.  Legacy vertex attribs are given default names.
diff --git a/rsProgramVertex.cpp b/rsProgramVertex.cpp
index cf6d7fc..2c9bdaa 100644
--- a/rsProgramVertex.cpp
+++ b/rsProgramVertex.cpp
@@ -168,27 +168,27 @@
         }
         mShader.append(mUserShader);
     } else {
+        mShader.append("attribute vec4 ATTRIB_LegacyPosition;\n");
+        mShader.append("attribute vec4 ATTRIB_LegacyColor;\n");
+        mShader.append("attribute vec3 ATTRIB_LegacyNormal;\n");
+        mShader.append("attribute float ATTRIB_LegacyPointSize;\n");
+        mShader.append("attribute vec4 ATTRIB_LegacyTexture;\n");
+
         for (uint32_t ct=0; ct < mUniformCount; ct++) {
             mShader.append("uniform mat4 ");
             mShader.append(mUniformNames[ct]);
             mShader.append(";\n");
         }
 
-        for (uint32_t ct=VertexArray::POSITION; ct < mAttribCount; ct++) {
-            mShader.append("attribute vec4 ");
-            mShader.append(mAttribNames[ct]);
-            mShader.append(";\n");
-        }
-
         mShader.append("void main() {\n");
-        mShader.append("  gl_Position = UNI_MVP * ATTRIB_Position;\n");
-        mShader.append("  gl_PointSize = ATTRIB_PointSize.x;\n");
+        mShader.append("  gl_Position = UNI_MVP * ATTRIB_LegacyPosition;\n");
+        mShader.append("  gl_PointSize = ATTRIB_LegacyPointSize;\n");
 
-        mShader.append("  varColor = ATTRIB_Color;\n");
+        mShader.append("  varColor = ATTRIB_LegacyColor;\n");
         if (mTextureMatrixEnable) {
-            mShader.append("  varTex0 = UNI_TexMatrix * ATTRIB_Texture;\n");
+            mShader.append("  varTex0 = UNI_TexMatrix * ATTRIB_LegacyTexture;\n");
         } else {
-            mShader.append("  varTex0 = ATTRIB_Texture;\n");
+            mShader.append("  varTex0 = ATTRIB_LegacyTexture;\n");
         }
         //mShader.append("  pos.x = pos.x / 480.0;\n");
         //mShader.append("  pos.y = pos.y / 800.0;\n");
@@ -326,10 +326,11 @@
     }
 }
 
+
 void ProgramVertex::init(Context *rsc)
 {
+    mAttribCount = 0;
     if (mUserShader.size() > 0) {
-        mAttribCount = 0;
         for (uint32_t ct=0; ct < mInputCount; ct++) {
             initAddUserElement(mInputElements[ct].get(), mAttribNames, &mAttribCount, "ATTRIB_");
         }
@@ -340,13 +341,6 @@
             initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, &mUniformCount, "UNI_");
         }
     } else {
-        mAttribCount = 5;
-        mAttribNames[0].setTo("ATTRIB_Position");
-        mAttribNames[1].setTo("ATTRIB_Color");
-        mAttribNames[2].setTo("ATTRIB_Normal");
-        mAttribNames[3].setTo("ATTRIB_PointSize");
-        mAttribNames[4].setTo("ATTRIB_Texture");
-
         mUniformCount = 2;
         mUniformNames[0].setTo("UNI_MVP");
         mUniformNames[1].setTo("UNI_TexMatrix");
diff --git a/rsScriptC_Lib.cpp b/rsScriptC_Lib.cpp
index eeb9468..6b8ed0d 100644
--- a/rsScriptC_Lib.cpp
+++ b/rsScriptC_Lib.cpp
@@ -687,7 +687,7 @@
 
     float vtx[] = { x1, y1, z1, x2, y2, z2 };
     VertexArray va;
-    va.setPosition(2, GL_FLOAT, 12, (uint32_t)&vtx);
+    va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx);
     if (rsc->checkVersion2_0()) {
         va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
     } else {
@@ -705,7 +705,7 @@
     float vtx[] = { x, y, z };
 
     VertexArray va;
-    va.setPosition(1, GL_FLOAT, 12, (uint32_t)&vtx);
+    va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx);
     if (rsc->checkVersion2_0()) {
         va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
     } else {
@@ -737,8 +737,8 @@
     const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
 
     VertexArray va;
-    va.setPosition(3, GL_FLOAT, 12, (uint32_t)&vtx);
-    va.setTexture(2, GL_FLOAT, 8, (uint32_t)&tex);
+    va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx);
+    va.addLegacy(GL_FLOAT, 2, 8, RS_KIND_TEXTURE, false, (uint32_t)tex);
     if (rsc->checkVersion2_0()) {
         va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
     } else {
diff --git a/rsShaderCache.cpp b/rsShaderCache.cpp
index 8ac2487..3a1f370 100644
--- a/rsShaderCache.cpp
+++ b/rsShaderCache.cpp
@@ -86,6 +86,7 @@
     e->vtx = vtx->getShaderID();
     e->frag = frag->getShaderID();
     e->program = glCreateProgram();
+    e->mUserVertexProgram = vtx->isUserProgram();
     if (mEntries[mEntryCount].program) {
         GLuint pgm = e->program;
         glAttachShader(pgm, vtx->getShaderID());
@@ -93,13 +94,16 @@
         glAttachShader(pgm, frag->getShaderID());
 
         if (!vtx->isUserProgram()) {
-            glBindAttribLocation(pgm, VertexArray::POSITION, "ATTRIB_Position");
-            glBindAttribLocation(pgm, VertexArray::COLOR, "ATTRIB_Color");
-            glBindAttribLocation(pgm, VertexArray::NORMAL, "ATTRIB_Normal");
-            glBindAttribLocation(pgm, VertexArray::POINT_SIZE, "ATTRIB_PointSize");
-            glBindAttribLocation(pgm, VertexArray::TEXTURE, "ATTRIB_T0");
-        } else {
-
+            glBindAttribLocation(pgm, 0, "ATTRIB_LegacyPosition");
+            glBindAttribLocation(pgm, 1, "ATTRIB_LegacyColor");
+            glBindAttribLocation(pgm, 2, "ATTRIB_LegacyNormal");
+            glBindAttribLocation(pgm, 3, "ATTRIB_LegacyPointSize");
+            glBindAttribLocation(pgm, 4, "ATTRIB_LegacyTexture");
+            e->mVtxAttribSlots[RS_KIND_POSITION] = 0;
+            e->mVtxAttribSlots[RS_KIND_COLOR] = 1;
+            e->mVtxAttribSlots[RS_KIND_NORMAL] = 2;
+            e->mVtxAttribSlots[RS_KIND_POINT_SIZE] = 3;
+            e->mVtxAttribSlots[RS_KIND_TEXTURE] = 4;
         }
 
         //LOGE("e2 %x", glGetError());
@@ -120,10 +124,12 @@
             }
             glDeleteProgram(pgm);
         }
-        for (uint32_t ct=0; ct < vtx->getAttribCount(); ct++) {
-            e->mVtxAttribSlots[ct] = glGetAttribLocation(pgm, vtx->getAttribName(ct));
-            if (rsc->props.mLogShaders) {
-                LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->mVtxAttribSlots[ct]);
+        if (vtx->isUserProgram()) {
+            for (uint32_t ct=0; ct < vtx->getAttribCount(); ct++) {
+                e->mVtxAttribSlots[ct] = glGetAttribLocation(pgm, vtx->getAttribName(ct));
+                if (rsc->props.mLogShaders) {
+                    LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->mVtxAttribSlots[ct]);
+                }
             }
         }
         for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
diff --git a/rsShaderCache.h b/rsShaderCache.h
index ede3734..7aa8183 100644
--- a/rsShaderCache.h
+++ b/rsShaderCache.h
@@ -44,6 +44,7 @@
     int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->mVtxUniformSlots[a];}
     int32_t fragAttribSlot(uint32_t a) const {return mCurrent->mFragAttribSlots[a];}
     int32_t fragUniformSlot(uint32_t a) const {return mCurrent->mFragUniformSlots[a];}
+    bool isUserVertexProgram() const {return mCurrent->mUserVertexProgram;}
 
 protected:
     typedef struct {
@@ -54,6 +55,7 @@
         int32_t mVtxUniformSlots[Program::MAX_UNIFORMS];
         int32_t mFragAttribSlots[Program::MAX_ATTRIBS];
         int32_t mFragUniformSlots[Program::MAX_UNIFORMS];
+        bool mUserVertexProgram;
     } entry_t;
     entry_t *mEntries;
     entry_t *mCurrent;
diff --git a/rsType.cpp b/rsType.cpp
index ddadd9f..22a267a 100644
--- a/rsType.cpp
+++ b/rsType.cpp
@@ -207,36 +207,48 @@
 
     uint32_t stride = mElement->getSizeBytes();
     if (mGL.mVtx.size) {
-        va->setPosition(mGL.mVtx.size,
-                        mGL.mVtx.type,
-                        stride,
-                        mGL.mVtx.offset);
+        va->addLegacy(mGL.mVtx.type,
+                      mGL.mVtx.size,
+                      stride,
+                      RS_KIND_POSITION,
+                      false,
+                      mGL.mVtx.offset);
     }
 
     if (mGL.mNorm.size) {
-        va->setNormal(mGL.mNorm.type,
-                      stride,
-                      mGL.mNorm.offset);
+        va->addLegacy(mGL.mNorm.type,
+                     3,
+                     stride,
+                     RS_KIND_NORMAL,
+                     false,
+                     mGL.mNorm.offset);
     }
 
     if (mGL.mColor.size) {
-        va->setColor(mGL.mColor.size,
-                     mGL.mColor.type,
+        va->addLegacy(mGL.mColor.type,
+                     mGL.mColor.size,
                      stride,
+                     RS_KIND_COLOR,
+                     true,
                      mGL.mColor.offset);
     }
 
     if (mGL.mTex.size) {
-        va->setTexture(mGL.mTex.size,
-                       mGL.mTex.type,
-                       stride,
-                       mGL.mTex.offset);
+        va->addLegacy(mGL.mTex.type,
+                     mGL.mTex.size,
+                     stride,
+                     RS_KIND_TEXTURE,
+                     false,
+                     mGL.mTex.offset);
     }
 
     if (mGL.mPointSize.size) {
-        va->setPointSize(mGL.mPointSize.type,
-                         stride,
-                         mGL.mPointSize.offset);
+        va->addLegacy(mGL.mPointSize.type,
+                     1,
+                     stride,
+                     RS_KIND_POINT_SIZE,
+                     false,
+                     mGL.mPointSize.offset);
     }
 
 }
@@ -249,7 +261,7 @@
     uint32_t stride = mElement->getSizeBytes();
     for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) {
         if (mGL.mUser[ct].size) {
-            va->setUser(mGL.mUser[ct], stride);
+            va->addUser(mGL.mUser[ct], stride);
         }
     }
 }
diff --git a/rsVertexArray.cpp b/rsVertexArray.cpp
index 7124eb5..a1fd744 100644
--- a/rsVertexArray.cpp
+++ b/rsVertexArray.cpp
@@ -25,7 +25,7 @@
 
 VertexArray::VertexArray()
 {
-    mActiveBuffer = 0;
+    clearAll();
 }
 
 VertexArray::~VertexArray()
@@ -39,6 +39,7 @@
         mAttribs[ct].clear();
     }
     mActiveBuffer = 0;
+    mCount = 0;
 }
 
 VertexArray::Attrib::Attrib()
@@ -54,6 +55,7 @@
     size = a.size;
     stride = a.stride;
     normalized = a.normalized;
+    kind = RS_KIND_USER;
     name.setTo(a.name);
 }
 
@@ -68,78 +70,42 @@
     name.setTo("");
 }
 
-void VertexArray::clear(AttribName n)
+void VertexArray::clear(uint32_t n)
 {
     mAttribs[n].clear();
 }
 
-void VertexArray::setPosition(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset)
+void VertexArray::addUser(const Attrib &a, uint32_t stride)
 {
-    mAttribs[POSITION].buffer = mActiveBuffer;
-    mAttribs[POSITION].type = type;
-    mAttribs[POSITION].size = size;
-    mAttribs[POSITION].offset = offset;
-    mAttribs[POSITION].stride = stride;
-    mAttribs[POSITION].normalized = false;
+    assert(mCount < RS_MAX_ATTRIBS);
+    mAttribs[mCount].set(a);
+    mAttribs[mCount].buffer = mActiveBuffer;
+    mAttribs[mCount].stride = stride;
+    mAttribs[mCount].kind = RS_KIND_USER;
+    mCount ++;
 }
 
-void VertexArray::setColor(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset)
+void VertexArray::addLegacy(uint32_t type, uint32_t size, uint32_t stride, RsDataKind kind, bool normalized, uint32_t offset)
 {
-    mAttribs[COLOR].buffer = mActiveBuffer;
-    mAttribs[COLOR].type = type;
-    mAttribs[COLOR].size = size;
-    mAttribs[COLOR].offset = offset;
-    mAttribs[COLOR].stride = stride;
-    mAttribs[COLOR].normalized = type != GL_FLOAT;
-}
-
-void VertexArray::setNormal(uint32_t type, uint32_t stride, uint32_t offset)
-{
-    mAttribs[NORMAL].buffer = mActiveBuffer;
-    mAttribs[NORMAL].type = type;
-    mAttribs[NORMAL].size = 3;
-    mAttribs[NORMAL].offset = offset;
-    mAttribs[NORMAL].stride = stride;
-    mAttribs[NORMAL].normalized = type != GL_FLOAT;
-}
-
-void VertexArray::setPointSize(uint32_t type, uint32_t stride, uint32_t offset)
-{
-    mAttribs[POINT_SIZE].buffer = mActiveBuffer;
-    mAttribs[POINT_SIZE].type = type;
-    mAttribs[POINT_SIZE].size = 1;
-    mAttribs[POINT_SIZE].offset = offset;
-    mAttribs[POINT_SIZE].stride = stride;
-    mAttribs[POINT_SIZE].normalized = false;
-}
-
-void VertexArray::setTexture(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset)
-{
-    mAttribs[TEXTURE].buffer = mActiveBuffer;
-    mAttribs[TEXTURE].type = type;
-    mAttribs[TEXTURE].size = size;
-    mAttribs[TEXTURE].offset = offset;
-    mAttribs[TEXTURE].stride = stride;
-    mAttribs[TEXTURE].normalized = false;
-}
-
-void VertexArray::setUser(const Attrib &a, uint32_t stride)
-{
-    // Find empty slot, some may be taken by legacy 1.1 slots.
-    uint32_t slot = 0;
-    while (mAttribs[slot].size) slot++;
-    rsAssert(slot < RS_MAX_ATTRIBS);
-    mAttribs[slot].set(a);
-    mAttribs[slot].buffer = mActiveBuffer;
-    mAttribs[slot].stride = stride;
+    assert(mCount < RS_MAX_ATTRIBS);
+    mAttribs[mCount].clear();
+    mAttribs[mCount].type = type;
+    mAttribs[mCount].size = size;
+    mAttribs[mCount].offset = offset;
+    mAttribs[mCount].normalized = normalized;
+    mAttribs[mCount].buffer = mActiveBuffer;
+    mAttribs[mCount].stride = stride;
+    mAttribs[mCount].kind = kind;
+    mCount ++;
 }
 
 void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
-    LOGE("va %i: slot=%i name=%s buf=%i  size=%i  type=0x%x  stride=0x%x  norm=%i  offset=0x%x", idx, slot,
+    LOGE("va %i: slot=%i name=%s buf=%i  size=%i  type=0x%x  kind=%i  stride=0x%x  norm=%i  offset=0x%x", idx, slot,
          mAttribs[idx].name.string(),
          mAttribs[idx].buffer,
          mAttribs[idx].size,
          mAttribs[idx].type,
+         mAttribs[idx].kind,
          mAttribs[idx].stride,
          mAttribs[idx].normalized,
          mAttribs[idx].offset);
@@ -147,87 +113,95 @@
 
 void VertexArray::setupGL(const Context *rsc, class VertexArrayState *state) const
 {
-    if (mAttribs[POSITION].size) {
-        //logAttrib(POSITION);
-        glEnableClientState(GL_VERTEX_ARRAY);
-        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[POSITION].buffer);
-        glVertexPointer(mAttribs[POSITION].size,
-                        mAttribs[POSITION].type,
-                        mAttribs[POSITION].stride,
-                        (void *)mAttribs[POSITION].offset);
-    } else {
-        rsAssert(0);
-    }
-
-    if (mAttribs[NORMAL].size) {
-        //logAttrib(NORMAL);
-        glEnableClientState(GL_NORMAL_ARRAY);
-        rsAssert(mAttribs[NORMAL].size == 3);
-        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[NORMAL].buffer);
-        glNormalPointer(mAttribs[NORMAL].type,
-                        mAttribs[NORMAL].stride,
-                        (void *)mAttribs[NORMAL].offset);
-    } else {
-        glDisableClientState(GL_NORMAL_ARRAY);
-    }
-
-    if (mAttribs[COLOR].size) {
-        //logAttrib(COLOR);
-        glEnableClientState(GL_COLOR_ARRAY);
-        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[COLOR].buffer);
-        glColorPointer(mAttribs[COLOR].size,
-                       mAttribs[COLOR].type,
-                       mAttribs[COLOR].stride,
-                       (void *)mAttribs[COLOR].offset);
-    } else {
-        glDisableClientState(GL_COLOR_ARRAY);
-    }
-
     glClientActiveTexture(GL_TEXTURE0);
-    if (mAttribs[TEXTURE].size) {
-        //logAttrib(TEXTURE);
-        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[TEXTURE].buffer);
-        glTexCoordPointer(mAttribs[TEXTURE].size,
-                          mAttribs[TEXTURE].type,
-                          mAttribs[TEXTURE].stride,
-                          (void *)mAttribs[TEXTURE].offset);
-    } else {
-        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    glDisableClientState(GL_NORMAL_ARRAY);
+    glDisableClientState(GL_COLOR_ARRAY);
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
+
+    for (uint32_t ct=0; ct < mCount; ct++) {
+        switch(mAttribs[ct].kind) {
+        case RS_KIND_POSITION:
+            //logAttrib(POSITION);
+            glEnableClientState(GL_VERTEX_ARRAY);
+            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
+            glVertexPointer(mAttribs[ct].size,
+                            mAttribs[ct].type,
+                            mAttribs[ct].stride,
+                            (void *)mAttribs[ct].offset);
+            break;
+
+        case RS_KIND_NORMAL:
+            //logAttrib(NORMAL);
+            glEnableClientState(GL_NORMAL_ARRAY);
+            rsAssert(mAttribs[ct].size == 3);
+            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
+            glNormalPointer(mAttribs[ct].type,
+                            mAttribs[ct].stride,
+                            (void *)mAttribs[ct].offset);
+            break;
+
+        case RS_KIND_COLOR:
+            //logAttrib(COLOR);
+            glEnableClientState(GL_COLOR_ARRAY);
+            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
+            glColorPointer(mAttribs[ct].size,
+                           mAttribs[ct].type,
+                           mAttribs[ct].stride,
+                           (void *)mAttribs[ct].offset);
+            break;
+
+        case RS_KIND_TEXTURE:
+            //logAttrib(TEXTURE);
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
+            glTexCoordPointer(mAttribs[ct].size,
+                              mAttribs[ct].type,
+                              mAttribs[ct].stride,
+                              (void *)mAttribs[ct].offset);
+            break;
+
+        case RS_KIND_POINT_SIZE:
+            //logAttrib(POINT_SIZE);
+            glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
+            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
+            glPointSizePointerOES(mAttribs[ct].type,
+                                  mAttribs[ct].stride,
+                                  (void *)mAttribs[ct].offset);
+            break;
+
+        default:
+            rsAssert(0);
+        }
     }
 
-    if (mAttribs[POINT_SIZE].size) {
-        //logAttrib(POINT_SIZE);
-        glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
-        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[POINT_SIZE].buffer);
-        glPointSizePointerOES(mAttribs[POINT_SIZE].type,
-                              mAttribs[POINT_SIZE].stride,
-                              (void *)mAttribs[POINT_SIZE].offset);
-    } else {
-        glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
-    }
     rsc->checkError("VertexArray::setupGL");
 }
 
 void VertexArray::setupGL2(const Context *rsc, class VertexArrayState *state, ShaderCache *sc) const
 {
-    for (int ct=1; ct < _LAST; ct++) {
+    for (int ct=1; ct < RS_MAX_ATTRIBS; ct++) {
         glDisableVertexAttribArray(ct);
     }
 
-    for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) {
-        if (mAttribs[ct].size && (sc->vtxAttribSlot(ct) >= 0)) {
-            //logAttrib(ct, sc->vtxAttribSlot(ct));
-            glEnableVertexAttribArray(sc->vtxAttribSlot(ct));
-            glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
-
-            glVertexAttribPointer(sc->vtxAttribSlot(ct),
-                                  mAttribs[ct].size,
-                                  mAttribs[ct].type,
-                                  mAttribs[ct].normalized,
-                                  mAttribs[ct].stride,
-                                  (void *)mAttribs[ct].offset);
+    for (uint32_t ct=0; ct < mCount; ct++) {
+        uint32_t slot = 0;
+        if (sc->isUserVertexProgram()) {
+            slot = sc->vtxAttribSlot(ct);
+        } else {
+            slot = sc->vtxAttribSlot(mAttribs[ct].kind);
         }
+
+        //logAttrib(ct, slot);
+        glEnableVertexAttribArray(slot);
+        glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer);
+
+        glVertexAttribPointer(slot,
+                              mAttribs[ct].size,
+                              mAttribs[ct].type,
+                              mAttribs[ct].normalized,
+                              mAttribs[ct].stride,
+                              (void *)mAttribs[ct].offset);
     }
     rsc->checkError("VertexArray::setupGL2");
 }
diff --git a/rsVertexArray.h b/rsVertexArray.h
index 26e6f84..66b3ab0 100644
--- a/rsVertexArray.h
+++ b/rsVertexArray.h
@@ -33,14 +33,6 @@
     VertexArray();
     virtual ~VertexArray();
 
-    enum AttribName {
-        POSITION,
-        COLOR,
-        NORMAL,
-        POINT_SIZE,
-        TEXTURE,
-        _LAST
-    };
 
     class Attrib {
     public:
@@ -51,6 +43,7 @@
         uint32_t stride;
         bool normalized;
         String8 name;
+        RsDataKind kind;
 
         Attrib();
         void set(const Attrib &);
@@ -59,23 +52,19 @@
 
 
     void clearAll();
-    void clear(AttribName);
-
     void setActiveBuffer(uint32_t id) {mActiveBuffer = id;}
-
-    void setUser(const Attrib &, uint32_t stride);
-    void setPosition(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset);
-    void setColor(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset);
-    void setNormal(uint32_t type, uint32_t stride, uint32_t offset);
-    void setPointSize(uint32_t type, uint32_t stride, uint32_t offset);
-    void setTexture(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset);
+    void addUser(const Attrib &, uint32_t stride);
+    void addLegacy(uint32_t type, uint32_t size, uint32_t stride, RsDataKind kind, bool normalized, uint32_t offset);
 
     void setupGL(const Context *rsc, class VertexArrayState *) const;
     void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const;
     void logAttrib(uint32_t idx, uint32_t slot) const;
 
 protected:
+    void clear(uint32_t index);
     uint32_t mActiveBuffer;
+    uint32_t mCount;
+
     Attrib mAttribs[RS_MAX_ATTRIBS];
 };