Start of mesh API cleanup.
Switched all native code to go through Mesh class.
Removed SimpleMesh
Added java Mesh class
Will need to port all existing code to use java Mesh, then remove java SimpleMesh.

Change-Id: Idb9c03d0b06b4ef87db28dffcffa1881d39120e5
diff --git a/Android.mk b/Android.mk
index 7afc4f2..37c418b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -102,7 +102,6 @@
 	rsScriptC_LibGL.cpp \
 	rsShaderCache.cpp \
 	rsSignal.cpp \
-	rsSimpleMesh.cpp \
 	rsStream.cpp \
 	rsThreadIO.cpp \
 	rsType.cpp \
diff --git a/RenderScript.h b/RenderScript.h
index 1428318..8e6b5c6 100644
--- a/RenderScript.h
+++ b/RenderScript.h
@@ -38,7 +38,7 @@
 typedef void * RsFont;
 typedef void * RsSampler;
 typedef void * RsScript;
-typedef void * RsSimpleMesh;
+typedef void * RsMesh;
 typedef void * RsType;
 typedef void * RsLight;
 typedef void * RsObjectBase;
@@ -229,7 +229,6 @@
 enum RsA3DClassID {
     RS_A3D_CLASS_ID_UNKNOWN,
     RS_A3D_CLASS_ID_MESH,
-    RS_A3D_CLASS_ID_SIMPLE_MESH,
     RS_A3D_CLASS_ID_TYPE,
     RS_A3D_CLASS_ID_ELEMENT,
     RS_A3D_CLASS_ID_ALLOCATION,
diff --git a/RenderScriptEnv.h b/RenderScriptEnv.h
index 144e539..9225904 100644
--- a/RenderScriptEnv.h
+++ b/RenderScriptEnv.h
@@ -9,7 +9,7 @@
 typedef void * RsElement;
 typedef void * RsSampler;
 typedef void * RsScript;
-typedef void * RsSimpleMesh;
+typedef void * RsMesh;
 typedef void * RsType;
 typedef void * RsProgramFragment;
 typedef void * RsProgramStore;
diff --git a/java/Fountain/res/raw/fountain.rs b/java/Fountain/res/raw/fountain.rs
index 2ecb391..c8c10cd 100644
--- a/java/Fountain/res/raw/fountain.rs
+++ b/java/Fountain/res/raw/fountain.rs
@@ -35,7 +35,7 @@
         p++;
     }
 
-    rsgDrawSimpleMesh(partMesh);
+    rsgDrawMesh(partMesh);
     return 1;
 }
 
diff --git a/java/Fountain/res/raw/fountain_bc.bc b/java/Fountain/res/raw/fountain_bc.bc
index 822f30a..2c8ce8b 100644
--- a/java/Fountain/res/raw/fountain_bc.bc
+++ b/java/Fountain/res/raw/fountain_bc.bc
Binary files differ
diff --git a/java/Fountain/src/com/android/fountain/FountainRS.java b/java/Fountain/src/com/android/fountain/FountainRS.java
index c001e84..cfe8e27 100644
--- a/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -36,11 +36,10 @@
 
         ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
 
-        SimpleMesh.Builder smb = new SimpleMesh.Builder(mRS);
-        int vtxSlot = smb.addVertexType(points.getType());
-        smb.setPrimitive(Primitive.POINT);
-        SimpleMesh sm = smb.create();
-        sm.bindVertexAllocation(points.getAllocation(), vtxSlot);
+        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+        smb.addVertexAllocation(points.getAllocation());
+        smb.addIndexType(Primitive.POINT);
+        Mesh sm = smb.create();
 
         mScript = new ScriptC_Fountain(mRS, mRes, R.raw.fountain_bc, true);
         mScript.set_partMesh(sm);
diff --git a/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java b/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java
index 95ce1ab..0ec0009 100644
--- a/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java
+++ b/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java
@@ -27,13 +27,13 @@
     }
 
     private final static int mExportVarIdx_partMesh = 0;
-    private SimpleMesh mExportVar_partMesh;
-    public void set_partMesh(SimpleMesh v) {
+    private Mesh mExportVar_partMesh;
+    public void set_partMesh(Mesh v) {
         mExportVar_partMesh = v;
         setVar(mExportVarIdx_partMesh, (v == null) ? 0 : v.getID());
     }
 
-    public SimpleMesh get_partMesh() {
+    public Mesh get_partMesh() {
         return mExportVar_partMesh;
     }
 
diff --git a/java/ModelViewer/res/raw/modelviewer.rs b/java/ModelViewer/res/raw/modelviewer.rs
index 91194e8..559bf48 100644
--- a/java/ModelViewer/res/raw/modelviewer.rs
+++ b/java/ModelViewer/res/raw/modelviewer.rs
@@ -62,7 +62,7 @@
     rsMatrixRotate(&matrix, gRotate, 0.0f, 1.0f, 0.0f);
     rsgProgramVertexLoadModelMatrix(&matrix);
 
-    rsgDrawSimpleMesh(gTestMesh);
+    rsgDrawMesh(gTestMesh);
 
     color(0.3f, 0.3f, 0.3f, 1.0f);
     rsgDrawText("Renderscript model test", 30, 695);
diff --git a/java/ModelViewer/res/raw/modelviewer_bc.bc b/java/ModelViewer/res/raw/modelviewer_bc.bc
index a64e725..fb85028 100644
--- a/java/ModelViewer/res/raw/modelviewer_bc.bc
+++ b/java/ModelViewer/res/raw/modelviewer_bc.bc
Binary files differ
diff --git a/java/ModelViewer/res/raw/robot.a3d b/java/ModelViewer/res/raw/robot.a3d
index c0c66ae..430fe95 100644
--- a/java/ModelViewer/res/raw/robot.a3d
+++ b/java/ModelViewer/res/raw/robot.a3d
Binary files differ
diff --git a/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java b/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
index b6485dc..37eb9c1 100644
--- a/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
+++ b/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
@@ -55,7 +55,7 @@
     private Allocation mGridImage;
     private Allocation mAllocPV;
 
-    private SimpleMesh mMesh;
+    private Mesh mMesh;
 
     private Font mItalic;
     private Allocation mTextAlloc;
@@ -149,15 +149,15 @@
 
         FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
         FileA3D.IndexEntry entry = model.getIndexEntry(0);
-        if(entry == null || entry.getClassID() != FileA3D.ClassID.SIMPLE_MESH) {
+        if(entry == null || entry.getClassID() != FileA3D.ClassID.MESH) {
             Log.e("rs", "could not load model");
         }
         else {
-            mMesh = (SimpleMesh)entry.getObject();
+            mMesh = (Mesh)entry.getObject();
             mScript.set_gTestMesh(mMesh);
         }
 
-        mItalic = Font.create(mRS, mRes, "DroidSerif-Italic.ttf", 10);
+        mItalic = Font.create(mRS, mRes, "DroidSerif-Italic.ttf", 8);
         mScript.set_gItalic(mItalic);
 
         initTextAllocation();
diff --git a/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java b/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java
index d3a2a29..06c10ab 100644
--- a/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java
+++ b/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java
@@ -60,13 +60,13 @@
     }
 
     private final static int mExportVarIdx_gTestMesh = 3;
-    private SimpleMesh mExportVar_gTestMesh;
-    public void set_gTestMesh(SimpleMesh v) {
+    private Mesh mExportVar_gTestMesh;
+    public void set_gTestMesh(Mesh v) {
         mExportVar_gTestMesh = v;
         setVar(mExportVarIdx_gTestMesh, (v == null) ? 0 : v.getID());
     }
 
-    public SimpleMesh get_gTestMesh() {
+    public Mesh get_gTestMesh() {
         return mExportVar_gTestMesh;
     }
 
diff --git a/rs.spec b/rs.spec
index 3694b65..172ba66 100644
--- a/rs.spec
+++ b/rs.spec
@@ -478,8 +478,34 @@
 	ret RsFont
 	}
 
+MeshCreate {
+	ret RsMesh
+	param uint32_t vtxCount
+	param uint32_t idxCount
+	}
+
+MeshBindIndex {
+	param RsMesh mesh
+	param RsAllocation idx
+	param uint32_t primType
+	param uint32_t slot
+	}
+
+MeshBindPrimitive {
+	param RsMesh mesh
+	param RsAllocation prim
+	param uint32_t primType
+	param uint32_t slot
+	}
+
+MeshBindVertex {
+	param RsMesh mesh
+	param RsAllocation vtx
+	param uint32_t slot
+	}
+
 SimpleMeshCreate {
-	ret RsSimpleMesh
+	ret RsMesh
 	param RsAllocation prim
 	param RsAllocation index
 	param RsAllocation *vtx
@@ -489,17 +515,17 @@
 
 
 SimpleMeshBindIndex {
-	param RsSimpleMesh mesh
+	param RsMesh mesh
 	param RsAllocation idx
 	}
 
 SimpleMeshBindPrimitive {
-	param RsSimpleMesh mesh
+	param RsMesh mesh
 	param RsAllocation prim
 	}
 
 SimpleMeshBindVertex {
-	param RsSimpleMesh mesh
+	param RsMesh mesh
 	param RsAllocation vtx
 	param uint32_t slot
 	}
diff --git a/rsContext.h b/rsContext.h
index 73f478a..06433a1 100644
--- a/rsContext.h
+++ b/rsContext.h
@@ -24,7 +24,6 @@
 #include "rsType.h"
 #include "rsMatrix.h"
 #include "rsAllocation.h"
-#include "rsSimpleMesh.h"
 #include "rsMesh.h"
 #include "rsDevice.h"
 #include "rsScriptC.h"
diff --git a/rsContextHostStub.h b/rsContextHostStub.h
index be1fff6..c437606 100644
--- a/rsContextHostStub.h
+++ b/rsContextHostStub.h
@@ -24,7 +24,6 @@
 #include "rsType.h"
 #include "rsMatrix.h"
 #include "rsAllocation.h"
-#include "rsSimpleMesh.h"
 #include "rsMesh.h"
 //#include "rsDevice.h"
 #include "rsScriptC.h"
diff --git a/rsFileA3D.cpp b/rsFileA3D.cpp
index 4fac421..5709f2a 100644
--- a/rsFileA3D.cpp
+++ b/rsFileA3D.cpp
@@ -258,9 +258,6 @@
         case RS_A3D_CLASS_ID_MESH:
             entry->mRsObj = Mesh::createFromStream(mRSC, mReadStream);
             break;
-        case RS_A3D_CLASS_ID_SIMPLE_MESH:
-            entry->mRsObj = SimpleMesh::createFromStream(mRSC, mReadStream);
-            break;
         case RS_A3D_CLASS_ID_TYPE:
             entry->mRsObj = Type::createFromStream(mRSC, mReadStream);
             break;
diff --git a/rsMesh.cpp b/rsMesh.cpp
index bd9cd27..4f90f36 100644
--- a/rsMesh.cpp
+++ b/rsMesh.cpp
@@ -35,14 +35,124 @@
 {
     mAllocFile = __FILE__;
     mAllocLine = __LINE__;
-    mVerticies = NULL;
-    mVerticiesCount = 0;
     mPrimitives = NULL;
     mPrimitivesCount = 0;
+    mVertexBuffers = NULL;
+    mVertexTypes = NULL;
+    mVertexBufferCount = 0;
 }
 
 Mesh::~Mesh()
 {
+    if(mVertexTypes) {
+        delete[] mVertexTypes;
+    }
+
+    if(mVertexBuffers) {
+        delete[] mVertexBuffers;
+    }
+
+    if(mPrimitives) {
+        for(uint32_t i = 0; i < mPrimitivesCount; i ++) {
+            delete mPrimitives[i];
+        }
+        delete[] mPrimitives;
+    }
+}
+
+void Mesh::render(Context *rsc) const
+{
+    for(uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
+        renderPrimitive(rsc, ct);
+    }
+}
+
+void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const {
+    if (primIndex >= mPrimitivesCount) {
+        LOGE("Invalid primitive index");
+        return;
+    }
+
+    Primitive_t *prim = mPrimitives[primIndex];
+
+    if (prim->mIndexBuffer.get()) {
+        renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX());
+        return;
+    }
+
+    if (prim->mPrimitiveBuffer.get()) {
+        renderPrimitiveRange(rsc, primIndex, 0, prim->mPrimitiveBuffer->getType()->getDimX());
+        return;
+    }
+
+    renderPrimitiveRange(rsc, primIndex, 0, mVertexBuffers[0]->getType()->getDimX());
+}
+
+void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const
+{
+    if (len < 1 || primIndex >= mPrimitivesCount) {
+        return;
+    }
+
+    rsc->checkError("Mesh::renderPrimitiveRange 1");
+    VertexArray va;
+    for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
+        mVertexBuffers[ct]->uploadCheck(rsc);
+        if (mVertexBuffers[ct]->getIsBufferObject()) {
+            va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
+        } else {
+            va.setActiveBuffer(mVertexBuffers[ct]->getPtr());
+        }
+        mVertexBuffers[ct]->getType()->enableGLVertexBuffer(&va);
+    }
+    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
+
+    rsc->checkError("Mesh::renderPrimitiveRange 2");
+    Primitive_t *prim = mPrimitives[primIndex];
+    if (prim->mIndexBuffer.get()) {
+        prim->mIndexBuffer->uploadCheck(rsc);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
+        glDrawElements(prim->mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
+    } else {
+        glDrawArrays(prim->mGLPrimitive, start, len);
+    }
+
+    rsc->checkError("Mesh::renderPrimitiveRange");
+}
+
+
+void Mesh::uploadAll(Context *rsc)
+{
+    for (uint32_t ct = 0; ct < mVertexBufferCount; ct ++) {
+        if (mVertexBuffers[ct].get()) {
+            mVertexBuffers[ct]->deferedUploadToBufferObject(rsc);
+        }
+    }
+
+    for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
+        if (mPrimitives[ct]->mIndexBuffer.get()) {
+            mPrimitives[ct]->mIndexBuffer->deferedUploadToBufferObject(rsc);
+        }
+        if (mPrimitives[ct]->mPrimitiveBuffer.get()) {
+            mPrimitives[ct]->mPrimitiveBuffer->deferedUploadToBufferObject(rsc);
+        }
+    }
+
+    rsc->checkError("Mesh::uploadAll");
+}
+
+void Mesh::updateGLPrimitives()
+{
+    for(uint32_t i = 0; i < mPrimitivesCount; i ++) {
+        switch(mPrimitives[i]->mPrimitive) {
+            case RS_PRIMITIVE_POINT:          mPrimitives[i]->mGLPrimitive = GL_POINTS; break;
+            case RS_PRIMITIVE_LINE:           mPrimitives[i]->mGLPrimitive = GL_LINES; break;
+            case RS_PRIMITIVE_LINE_STRIP:     mPrimitives[i]->mGLPrimitive = GL_LINE_STRIP; break;
+            case RS_PRIMITIVE_TRIANGLE:       mPrimitives[i]->mGLPrimitive = GL_TRIANGLES; break;
+            case RS_PRIMITIVE_TRIANGLE_STRIP: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_STRIP; break;
+            case RS_PRIMITIVE_TRIANGLE_FAN:   mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_FAN; break;
+        }
+    }
 }
 
 void Mesh::serialize(OStream *stream) const
@@ -53,25 +163,10 @@
     String8 name(getName());
     stream->addString(&name);
 
-    stream->addU32(mVerticiesCount);
-
-    for(uint32_t vCount = 0; vCount < mVerticiesCount; vCount ++) {
-        Verticies_t *verts = mVerticies[vCount];
-
-        stream->addU32(verts->mAllocationCount);
-
-        for (uint32_t aCount = 0; aCount < verts->mAllocationCount; aCount++) {
-            verts->mAllocations[aCount]->serialize(stream);
-        }
-        stream->addU32(verts->mVertexDataSize);
-
-        stream->addU32(verts->mOffsetCoord);
-        stream->addU32(verts->mOffsetTex);
-        stream->addU32(verts->mOffsetNorm);
-
-        stream->addU32(verts->mSizeCoord);
-        stream->addU32(verts->mSizeTex);
-        stream->addU32(verts->mSizeNorm );
+    // Store number of vertex streams
+    stream->addU32(mVertexBufferCount);
+    for(uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) {
+        mVertexBuffers[vCount]->serialize(stream);
     }
 
     stream->addU32(mPrimitivesCount);
@@ -79,27 +174,22 @@
     for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) {
         Primitive_t * prim = mPrimitives[pCount];
 
-        stream->addU8((uint8_t)prim->mType);
+        stream->addU8((uint8_t)prim->mPrimitive);
 
-        // We store the index to the vertices
-        // So iterate over our vertices to find which one we point to
-        uint32_t vertexIndex = 0;
-        for(uint32_t vCount = 0; vCount < mVerticiesCount; vCount ++) {
-            if(prim->mVerticies == mVerticies[vCount]) {
-                vertexIndex = vCount;
-                break;
-            }
+        if(prim->mIndexBuffer.get()) {
+            stream->addU32(1);
+            prim->mIndexBuffer->serialize(stream);
         }
-        stream->addU32(vertexIndex);
-
-        stream->addU32(prim->mIndexCount);
-        for (uint32_t ct = 0; ct < prim->mIndexCount; ct++) {
-            stream->addU16(prim->mIndicies[ct]);
+        else {
+            stream->addU32(0);
         }
 
-        stream->addU32(prim->mRestartCounts);
-        for (uint32_t ct = 0; ct < prim->mRestartCounts; ct++) {
-            stream->addU16(prim->mRestarts[ct]);
+        if(prim->mPrimitiveBuffer.get()) {
+            stream->addU32(1);
+            prim->mPrimitiveBuffer->serialize(stream);
+        }
+        else {
+            stream->addU32(0);
         }
     }
 }
@@ -119,86 +209,46 @@
     stream->loadString(&name);
     mesh->setName(name.string(), name.size());
 
-    mesh->mVerticiesCount = stream->loadU32();
-    if(mesh->mVerticiesCount) {
-        mesh->mVerticies = new Verticies_t *[mesh->mVerticiesCount];
-    }
-    else {
-        mesh->mVerticies = NULL;
-    }
+    mesh->mVertexBufferCount = stream->loadU32();
+    if(mesh->mVertexBufferCount) {
+        mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount];
 
-    for(uint32_t vCount = 0; vCount < mesh->mVerticiesCount; vCount ++) {
-        Verticies_t *verts = new Verticies_t();
-        // Store our vertices one the mesh
-        mesh->mVerticies[vCount] = verts;
-
-        verts->mAllocationCount = stream->loadU32();
-        verts->mAllocations = new Allocation *[verts->mAllocationCount];
-
-        LOGE("processChunk_Verticies count %i", verts->mAllocationCount);
-        for (uint32_t aCount = 0; aCount < verts->mAllocationCount; aCount++) {
-            verts->mAllocations[aCount] = Allocation::createFromStream(rsc, stream);
+        for(uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) {
+            Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
+            mesh->mVertexBuffers[vCount].set(vertexAlloc);
         }
-        verts->mVertexDataSize = stream->loadU32();
-
-        verts->mOffsetCoord = stream->loadU32();
-        verts->mOffsetTex = stream->loadU32();
-        verts->mOffsetNorm = stream->loadU32();
-
-        verts->mSizeCoord = stream->loadU32();
-        verts->mSizeTex = stream->loadU32();
-        verts->mSizeNorm = stream->loadU32();
     }
 
     mesh->mPrimitivesCount = stream->loadU32();
     if(mesh->mPrimitivesCount) {
         mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount];
-    }
-    else {
-        mesh->mPrimitives = NULL;
-    }
 
-    // load all primitives
-    for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
-        Primitive_t * prim = new Primitive_t;
-        mesh->mPrimitives[pCount] = prim;
+        // load all primitives
+        for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
+            Primitive_t * prim = new Primitive_t;
+            mesh->mPrimitives[pCount] = prim;
 
-        prim->mType = (RsPrimitive)stream->loadU8();
+            prim->mPrimitive = (RsPrimitive)stream->loadU8();
 
-        // We store the index to the vertices
-        uint32_t vertexIndex = stream->loadU32();
-        if(vertexIndex < mesh->mVerticiesCount) {
-            prim->mVerticies = mesh->mVerticies[vertexIndex];
-        }
-        else {
-            prim->mVerticies = NULL;
-        }
+            // Check to see if the index buffer was stored
+            uint32_t isIndexPresent = stream->loadU32();
+            if(isIndexPresent) {
+                Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
+                prim->mIndexBuffer.set(indexAlloc);
+            }
 
-        prim->mIndexCount = stream->loadU32();
-        if(prim->mIndexCount){
-            prim->mIndicies = new uint16_t[prim->mIndexCount];
-            for (uint32_t ct = 0; ct < prim->mIndexCount; ct++) {
-                prim->mIndicies[ct] = stream->loadU16();
+            // Check to see if the primitive buffer was stored
+            uint32_t isPrimitivePresent = stream->loadU32();
+            if(isPrimitivePresent) {
+                Allocation *primitiveAlloc = Allocation::createFromStream(rsc, stream);
+                prim->mPrimitiveBuffer.set(primitiveAlloc);
             }
         }
-        else {
-            prim->mIndicies = NULL;
-        }
-
-        prim->mRestartCounts = stream->loadU32();
-        if (prim->mRestartCounts) {
-            prim->mRestarts = new uint16_t[prim->mRestartCounts];
-            for (uint32_t ct = 0; ct < prim->mRestartCounts; ct++) {
-                prim->mRestarts[ct] = stream->loadU16();
-
-            }
-        }
-        else {
-            prim->mRestarts = NULL;
-        }
-
     }
 
+    mesh->updateGLPrimitives();
+    mesh->uploadAll(rsc);
+
     return mesh;
 }
 
@@ -211,3 +261,103 @@
 {
 }
 
+namespace android {
+namespace renderscript {
+
+RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount)
+{
+    Mesh *sm = new Mesh(rsc);
+    sm->incUserRef();
+
+    sm->mPrimitivesCount = idxCount;
+    sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount];
+    for(uint32_t ct = 0; ct < idxCount; ct ++) {
+        sm->mPrimitives[ct] = new Mesh::Primitive_t;
+    }
+
+    sm->mVertexBufferCount = vtxCount;
+    sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
+    sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount];
+
+    return sm;
+}
+
+void rsi_MeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    rsAssert(slot < sm->mVertexBufferCount);
+
+    sm->mVertexBuffers[slot].set((Allocation *)va);
+}
+
+void rsi_MeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    rsAssert(slot < sm->mPrimitivesCount);
+
+    sm->mPrimitives[slot]->mIndexBuffer.set((Allocation *)va);
+    sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType;
+    sm->updateGLPrimitives();
+}
+
+void rsi_MeshBindPrimitive(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    rsAssert(slot < sm->mPrimitivesCount);
+
+    sm->mPrimitives[slot]->mPrimitiveBuffer.set((Allocation *)va);
+    sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType;
+    sm->updateGLPrimitives();
+}
+
+
+// Route all the simple mesh through mesh
+
+RsMesh rsi_SimpleMeshCreate(Context *rsc, RsType prim, RsType idx, RsType *vtx, uint32_t vtxCount, uint32_t primType)
+{
+    Mesh *sm = new Mesh(rsc);
+    sm->incUserRef();
+
+    sm->mPrimitivesCount = 1;
+    sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount];
+    sm->mPrimitives[0] = new Mesh::Primitive_t;
+
+    sm->mPrimitives[0]->mIndexType.set((const Type *)idx);
+    sm->mPrimitives[0]->mPrimitiveType.set((const Type *)prim);
+    sm->mPrimitives[0]->mPrimitive = (RsPrimitive)primType;
+    sm->updateGLPrimitives();
+
+    sm->mVertexBufferCount = vtxCount;
+    sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount];
+    sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
+    for (uint32_t ct=0; ct < vtxCount; ct++) {
+        sm->mVertexTypes[ct].set((const Type *)vtx[ct]);
+    }
+
+    return sm;
+}
+
+void rsi_SimpleMeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    rsAssert(slot < sm->mVertexBufferCount);
+
+    sm->mVertexBuffers[slot].set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    sm->mPrimitives[0]->mIndexBuffer.set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindPrimitive(Context *rsc, RsMesh mv, RsAllocation va)
+{
+    Mesh *sm = static_cast<Mesh *>(mv);
+    sm->mPrimitives[0]->mPrimitiveBuffer.set((Allocation *)va);
+}
+
+
+
+
+}}
diff --git a/rsMesh.h b/rsMesh.h
index 8c7e8a4..66174b7 100644
--- a/rsMesh.h
+++ b/rsMesh.h
@@ -32,43 +32,35 @@
     Mesh(Context *);
     ~Mesh();
 
-    struct Verticies_t
-    {
-        Allocation ** mAllocations;
-        uint32_t mAllocationCount;
+    // Contains vertex data
+    // Position, normal, texcoord, etc could either be strided in one allocation
+    // of provided separetely in multiple ones
+    ObjectBaseRef<Allocation> *mVertexBuffers;
+    ObjectBaseRef<const Type> *mVertexTypes;
+    uint32_t mVertexBufferCount;
 
-        size_t mVertexDataSize;
-
-        size_t mOffsetCoord;
-        size_t mOffsetTex;
-        size_t mOffsetNorm;
-
-        size_t mSizeCoord;
-        size_t mSizeTex;
-        size_t mSizeNorm;
-
-        uint32_t mBufferObject;
-    };
-
+    // Either mIndexBuffer, mPrimitiveBuffer or both could have a NULL reference
+    // If both are null, mPrimitive only would be used to render the mesh
     struct Primitive_t
     {
-        RsPrimitive mType;
-        Verticies_t *mVerticies;
+        ObjectBaseRef<Allocation> mIndexBuffer;
+        ObjectBaseRef<Allocation> mPrimitiveBuffer;
+        ObjectBaseRef<const Type> mIndexType;
+        ObjectBaseRef<const Type> mPrimitiveType;
 
-        uint32_t mIndexCount;
-        uint16_t *mIndicies;
-
-        uint32_t mRestartCounts;
-        uint16_t *mRestarts;
+        RsPrimitive mPrimitive;
+        uint32_t mGLPrimitive;
     };
 
-    Verticies_t ** mVerticies;
-    uint32_t mVerticiesCount;
-
     Primitive_t ** mPrimitives;
     uint32_t mPrimitivesCount;
 
-    void analyzeElement();
+    void render(Context *) const;
+    void renderPrimitive(Context *, uint32_t primIndex) const;
+    void renderPrimitiveRange(Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+    void uploadAll(Context *);
+    void updateGLPrimitives();
+
     virtual void serialize(OStream *stream) const;
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
     static Mesh *createFromStream(Context *rsc, IStream *stream);
@@ -90,3 +82,4 @@
 #endif //ANDROID_RS_TRIANGLE_MESH_H
 
 
+
diff --git a/rsScriptC_LibGL.cpp b/rsScriptC_LibGL.cpp
index dbd398e..7185009 100644
--- a/rsScriptC_LibGL.cpp
+++ b/rsScriptC_LibGL.cpp
@@ -43,10 +43,10 @@
 // IO routines
 //////////////////////////////////////////////////////////////////////////////
 
-static void SC_updateSimpleMesh(RsSimpleMesh mesh)
+static void SC_updateSimpleMesh(RsMesh mesh)
 {
     GET_TLS();
-    SimpleMesh *sm = static_cast<SimpleMesh *>(mesh);
+    Mesh *sm = static_cast<Mesh *>(mesh);
     sm->uploadAll(rsc);
 }
 
@@ -220,24 +220,54 @@
                 x1, y1, z);
 }
 
-static void SC_drawSimpleMesh(RsSimpleMesh vsm)
+static void SC_drawSimpleMesh(RsMesh vsm)
 {
     GET_TLS();
-    SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+    Mesh *sm = static_cast<Mesh *>(vsm);
+    if (!rsc->setupCheck()) {
+        return;
+    }
+    sm->renderPrimitive(rsc, 0);
+}
+
+static void SC_drawSimpleMeshRange(RsMesh vsm, uint32_t start, uint32_t len)
+{
+    GET_TLS();
+    Mesh *sm = static_cast<Mesh *>(vsm);
+    if (!rsc->setupCheck()) {
+        return;
+    }
+    sm->renderPrimitiveRange(rsc, 0, start, len);
+}
+
+static void SC_drawMesh(RsMesh vsm)
+{
+    GET_TLS();
+    Mesh *sm = static_cast<Mesh *>(vsm);
     if (!rsc->setupCheck()) {
         return;
     }
     sm->render(rsc);
 }
 
-static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len)
+static void SC_drawMeshPrimitive(RsMesh vsm, uint32_t primIndex)
 {
     GET_TLS();
-    SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+    Mesh *sm = static_cast<Mesh *>(vsm);
     if (!rsc->setupCheck()) {
         return;
     }
-    sm->renderRange(rsc, start, len);
+    sm->renderPrimitive(rsc, primIndex);
+}
+
+static void SC_drawMeshPrimitiveRange(RsMesh vsm, uint32_t primIndex, uint32_t start, uint32_t len)
+{
+    GET_TLS();
+    Mesh *sm = static_cast<Mesh *>(vsm);
+    if (!rsc->setupCheck()) {
+        return;
+    }
+    sm->renderPrimitiveRange(rsc, primIndex, start, len);
 }
 
 
@@ -375,6 +405,10 @@
     { "_Z17rsgDrawSimpleMesh7rs_mesh", (void *)&SC_drawSimpleMesh },
     { "_Z17rsgDrawSimpleMesh7rs_meshii", (void *)&SC_drawSimpleMeshRange },
 
+    { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh },
+    { "_Z11rsgDrawMesh7rs_meshi", (void *)&SC_drawMeshPrimitive },
+    { "_Z11rsgDrawMesh7rs_meshiii", (void *)&SC_drawMeshPrimitiveRange },
+
     { "rsgClearColor", (void *)&SC_ClearColor },
     { "rsgClearDepth", (void *)&SC_ClearDepth },
 
diff --git a/rsSimpleMesh.cpp b/rsSimpleMesh.cpp
deleted file mode 100644
index e5c2eb5..0000000
--- a/rsSimpleMesh.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_RS_BUILD_FOR_HOST
-#include "rsContext.h"
-
-#include <GLES/gl.h>
-#include <GLES2/gl2.h>
-#include <GLES/glext.h>
-#else
-#include "rsContextHostStub.h"
-
-#include <OpenGL/gl.h>
-#include <OpenGl/glext.h>
-#endif
-
-using namespace android;
-using namespace android::renderscript;
-
-
-
-
-SimpleMesh::SimpleMesh(Context *rsc) : ObjectBase(rsc)
-{
-    mAllocFile = __FILE__;
-    mAllocLine = __LINE__;
-}
-
-SimpleMesh::~SimpleMesh()
-{
-    delete[] mVertexTypes;
-    delete[] mVertexBuffers;
-}
-
-void SimpleMesh::render(Context *rsc) const
-{
-    if (mPrimitiveType.get()) {
-        renderRange(rsc, 0, mPrimitiveType->getDimX());
-        return;
-    }
-
-    if (mIndexType.get()) {
-        renderRange(rsc, 0, mIndexType->getDimX());
-        return;
-    }
-
-    renderRange(rsc, 0, mVertexTypes[0]->getDimX());
-}
-
-void SimpleMesh::renderRange(Context *rsc, uint32_t start, uint32_t len) const
-{
-    if (len < 1) {
-        return;
-    }
-
-    rsc->checkError("SimpleMesh::renderRange 1");
-    VertexArray va;
-    for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
-        mVertexBuffers[ct]->uploadCheck(rsc);
-        if (mVertexBuffers[ct]->getIsBufferObject()) {
-            va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
-        } else {
-            va.setActiveBuffer(mVertexBuffers[ct]->getPtr());
-        }
-        mVertexTypes[ct]->enableGLVertexBuffer(&va);
-    }
-    va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
-
-    rsc->checkError("SimpleMesh::renderRange 2");
-    if (mIndexType.get()) {
-        mIndexBuffer->uploadCheck(rsc);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
-        glDrawElements(mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
-    } else {
-        glDrawArrays(mGLPrimitive, start, len);
-    }
-
-    rsc->checkError("SimpleMesh::renderRange");
-}
-
-void SimpleMesh::uploadAll(Context *rsc)
-{
-    for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
-        if (mVertexBuffers[ct].get()) {
-            mVertexBuffers[ct]->deferedUploadToBufferObject(rsc);
-        }
-    }
-    if (mIndexBuffer.get()) {
-        mIndexBuffer->deferedUploadToBufferObject(rsc);
-    }
-    if (mPrimitiveBuffer.get()) {
-        mPrimitiveBuffer->deferedUploadToBufferObject(rsc);
-    }
-    rsc->checkError("SimpleMesh::uploadAll");
-}
-
-void SimpleMesh::updateGLPrimitive()
-{
-    switch(mPrimitive) {
-        case RS_PRIMITIVE_POINT:          mGLPrimitive = GL_POINTS; break;
-        case RS_PRIMITIVE_LINE:           mGLPrimitive = GL_LINES; break;
-        case RS_PRIMITIVE_LINE_STRIP:     mGLPrimitive = GL_LINE_STRIP; break;
-        case RS_PRIMITIVE_TRIANGLE:       mGLPrimitive = GL_TRIANGLES; break;
-        case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitive = GL_TRIANGLE_STRIP; break;
-        case RS_PRIMITIVE_TRIANGLE_FAN:   mGLPrimitive = GL_TRIANGLE_FAN; break;
-    }
-}
-
-void SimpleMesh::serialize(OStream *stream) const
-{
-    // Need to identify ourselves
-    stream->addU32((uint32_t)getClassId());
-
-    String8 name(getName());
-    stream->addString(&name);
-
-    // Add primitive type
-    stream->addU8((uint8_t)mPrimitive);
-
-    // And now serialize the allocations
-    mIndexBuffer->serialize(stream);
-
-    // We need to indicate if the primitive buffer is present
-    if(mPrimitiveBuffer.get() != NULL) {
-        // Write if the primitive buffer is present
-        stream->addU32(1);
-        mPrimitiveBuffer->serialize(stream);
-    }
-    else {
-        // No buffer present, will need this when we read
-        stream->addU32(0);
-    }
-
-    // Store number of vertex streams
-    stream->addU32(mVertexTypeCount);
-    for(uint32_t vCount = 0; vCount < mVertexTypeCount; vCount ++) {
-        mVertexBuffers[vCount]->serialize(stream);
-    }
-}
-
-SimpleMesh *SimpleMesh::createFromStream(Context *rsc, IStream *stream)
-{
-    // First make sure we are reading the correct object
-    RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
-    if(classID != RS_A3D_CLASS_ID_SIMPLE_MESH) {
-        LOGE("simple mesh loading skipped due to invalid class id");
-        return NULL;
-    }
-
-    SimpleMesh * mesh = new SimpleMesh(rsc);
-
-    String8 name;
-    stream->loadString(&name);
-    mesh->setName(name.string(), name.size());
-
-    mesh->mPrimitive = (RsPrimitive)stream->loadU8();
-    mesh->updateGLPrimitive();
-
-    Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
-    const Type *indexType = indexAlloc->getType();
-    mesh->mIndexBuffer.set(indexAlloc);
-    mesh->mIndexType.set(indexType);
-
-    bool isPrimitivePresent = stream->loadU32() != 0;
-    if(isPrimitivePresent) {
-        mesh->mPrimitiveBuffer.set(Allocation::createFromStream(rsc, stream));
-        mesh->mPrimitiveType.set(mesh->mPrimitiveBuffer->getType());
-    }
-
-    mesh->mVertexTypeCount = stream->loadU32();
-    if(mesh->mVertexTypeCount) {
-        mesh->mVertexTypes = new ObjectBaseRef<const Type>[mesh->mVertexTypeCount];
-        mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexTypeCount];
-
-        for(uint32_t vCount = 0; vCount < mesh->mVertexTypeCount; vCount ++) {
-            Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
-            const Type *vertexType = vertexAlloc->getType();
-            mesh->mVertexBuffers[vCount].set(vertexAlloc);
-            mesh->mVertexTypes[vCount].set(vertexType);
-        }
-    }
-
-    mesh->uploadAll(rsc);
-
-    return mesh;
-}
-
-
-SimpleMeshContext::SimpleMeshContext()
-{
-}
-
-SimpleMeshContext::~SimpleMeshContext()
-{
-}
-
-
-namespace android {
-namespace renderscript {
-
-
-RsSimpleMesh rsi_SimpleMeshCreate(Context *rsc, RsType prim, RsType idx, RsType *vtx, uint32_t vtxCount, uint32_t primType)
-{
-    SimpleMesh *sm = new SimpleMesh(rsc);
-    sm->incUserRef();
-
-    sm->mIndexType.set((const Type *)idx);
-    sm->mPrimitiveType.set((const Type *)prim);
-
-    sm->mVertexTypeCount = vtxCount;
-    sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount];
-    sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
-    for (uint32_t ct=0; ct < vtxCount; ct++) {
-        sm->mVertexTypes[ct].set((const Type *)vtx[ct]);
-    }
-
-    sm->mPrimitive = (RsPrimitive)primType;
-    sm->updateGLPrimitive();
-    return sm;
-}
-
-void rsi_SimpleMeshBindVertex(Context *rsc, RsSimpleMesh mv, RsAllocation va, uint32_t slot)
-{
-    SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
-    rsAssert(slot < sm->mVertexTypeCount);
-
-    sm->mVertexBuffers[slot].set((Allocation *)va);
-}
-
-void rsi_SimpleMeshBindIndex(Context *rsc, RsSimpleMesh mv, RsAllocation va)
-{
-    SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
-    sm->mIndexBuffer.set((Allocation *)va);
-}
-
-void rsi_SimpleMeshBindPrimitive(Context *rsc, RsSimpleMesh mv, RsAllocation va)
-{
-    SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
-    sm->mPrimitiveBuffer.set((Allocation *)va);
-}
-
-
-
-
-}}
-
diff --git a/rsSimpleMesh.h b/rsSimpleMesh.h
deleted file mode 100644
index 362c7fb..0000000
--- a/rsSimpleMesh.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_RS_SIMPLE_MESH_H
-#define ANDROID_RS_SIMPLE_MESH_H
-
-
-#include "RenderScript.h"
-
-// ---------------------------------------------------------------------------
-namespace android {
-namespace renderscript {
-
-
-// An element is a group of Components that occupies one cell in a structure.
-class SimpleMesh : public ObjectBase
-{
-public:
-    SimpleMesh(Context *);
-    ~SimpleMesh();
-
-    ObjectBaseRef<const Type> mIndexType;
-    ObjectBaseRef<const Type> mPrimitiveType;
-    ObjectBaseRef<const Type> *mVertexTypes;
-    uint32_t mVertexTypeCount;
-
-    ObjectBaseRef<Allocation> mIndexBuffer;
-    ObjectBaseRef<Allocation> mPrimitiveBuffer;
-    ObjectBaseRef<Allocation> *mVertexBuffers;
-
-    RsPrimitive mPrimitive;
-    uint32_t mGLPrimitive;
-
-
-    void render(Context *) const;
-    void renderRange(Context *, uint32_t start, uint32_t len) const;
-    void uploadAll(Context *);
-    void updateGLPrimitive();
-
-    virtual void serialize(OStream *stream) const;
-    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SIMPLE_MESH; }
-    static SimpleMesh *createFromStream(Context *rsc, IStream *stream);
-
-protected:
-};
-
-class SimpleMeshContext
-{
-public:
-    SimpleMeshContext();
-    ~SimpleMeshContext();
-
-
-};
-
-
-}
-}
-#endif //ANDROID_RS_SIMPLE_MESH_H
-
diff --git a/scriptc/rs_graphics.rsh b/scriptc/rs_graphics.rsh
index fba3d6d..1f1f1ac 100644
--- a/scriptc/rs_graphics.rsh
+++ b/scriptc/rs_graphics.rsh
@@ -32,6 +32,10 @@
 extern void __attribute__((overloadable)) rsgDrawSimpleMesh(rs_mesh ism);
 extern void __attribute__((overloadable)) rsgDrawSimpleMesh(rs_mesh ism, int start, int len);
 
+extern void __attribute__((overloadable)) rsgDrawMesh(rs_mesh ism);
+extern void __attribute__((overloadable)) rsgDrawMesh(rs_mesh ism, int primitiveIndex);
+extern void __attribute__((overloadable)) rsgDrawMesh(rs_mesh ism, int primitiveIndex, int start, int len);
+
 extern void rsgClearColor(float, float, float, float);
 extern void rsgClearDepth(float);