1st cut of a3d file loader.
diff --git a/RenderScript.h b/RenderScript.h
index 5f551df..855ea63 100644
--- a/RenderScript.h
+++ b/RenderScript.h
@@ -33,6 +33,7 @@
 typedef void * RsContext;
 typedef void * RsDevice;
 typedef void * RsElement;
+typedef void * RsFile;
 typedef void * RsSampler;
 typedef void * RsScript;
 typedef void * RsScriptBasicTemp;
diff --git a/java/RenderScript/android/renderscript/RenderScript.java b/java/RenderScript/android/renderscript/RenderScript.java
index a9db15f..09d1836 100644
--- a/java/RenderScript/android/renderscript/RenderScript.java
+++ b/java/RenderScript/android/renderscript/RenderScript.java
@@ -70,6 +70,7 @@
     native private void nContextBindProgramVertex(int pf);
 
     native private void nAssignName(int obj, byte[] name);
+    native private int  nFileOpen(byte[] name);
 
     native private void nElementBegin();
     native private void nElementAddPredefined(int predef);
@@ -916,6 +917,36 @@
         return new Light(id);
     }
 
+    //////////////////////////////////////////////////////////////////////////////////
+    // File
+
+    public class File extends BaseObj {
+        File(int id) {
+            mID = id;
+        }
+
+        public void destroy() {
+            //nLightDestroy(mID);
+            mID = 0;
+        }
+    }
+
+    public File fileOpen(String s) throws IllegalStateException, IllegalArgumentException
+    {
+        if(s.length() < 1) {
+            throw new IllegalArgumentException("fileOpen does not accept a zero length string.");
+        }
+
+        try {
+            byte[] bytes = s.getBytes("UTF-8");
+            int id = nFileOpen(bytes);
+            return new File(id);
+        } catch (java.io.UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
     ///////////////////////////////////////////////////////////////////////////////////
     // Root state
 
diff --git a/jni/RenderScript_jni.cpp b/jni/RenderScript_jni.cpp
index 5677bb7..248a6bd 100644
--- a/jni/RenderScript_jni.cpp
+++ b/jni/RenderScript_jni.cpp
@@ -75,6 +75,19 @@
 }
 
 
+static jint
+nFileOpen(JNIEnv *_env, jobject _this, jbyteArray str)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nFileOpen, con(%p)", con);
+
+    jint len = _env->GetArrayLength(str);
+    jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0);
+    jint ret = (jint)rsFileOpen((const char *)cptr, len);
+    _env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT);
+    return ret;
+}
+
 // ---------------------------------------------------------------------------
 
 static jint
@@ -955,6 +968,8 @@
 {"nContextDestroy",                "(I)V",                                 (void*)nContextDestroy },
 {"nAssignName",                    "(I[B)V",                               (void*)nAssignName },
 
+{"nFileOpen",                      "([B)I",                                (void*)nFileOpen },
+
 {"nElementBegin",                  "()V",                                  (void*)nElementBegin },
 {"nElementAddPredefined",          "(I)V",                                 (void*)nElementAddPredefined },
 {"nElementAdd",                    "(IIII)V",                              (void*)nElementAdd },
diff --git a/rs.spec b/rs.spec
index fadda59..62533af 100644
--- a/rs.spec
+++ b/rs.spec
@@ -436,3 +436,10 @@
 	param float b
 	}
 
+FileOpen {
+	ret RsFile
+	param const char *name
+	param size_t len
+	}
+
+
diff --git a/rsFileA3D.cpp b/rsFileA3D.cpp
new file mode 100644
index 0000000..f669417
--- /dev/null
+++ b/rsFileA3D.cpp
@@ -0,0 +1,356 @@
+
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+
+#include <utils/String8.h>
+#include "rsFileA3D.h"
+
+#include "rsMesh.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+
+FileA3D::FileA3D()
+{
+    mRsc = NULL;
+}
+
+FileA3D::~FileA3D()
+{
+}
+
+bool FileA3D::load(Context *rsc, FILE *f)
+{
+    char magicString[12];
+    size_t len;
+
+    LOGE("file open 1");
+    len = fread(magicString, 1, 12, f);
+    if ((len != 12) ||
+        memcmp(magicString, "Android3D_ff", 12)) {
+        return false;
+    }
+
+    LOGE("file open 2");
+    len = fread(&mMajorVersion, 1, sizeof(mMajorVersion), f);
+    if (len != sizeof(mMajorVersion)) {
+        return false;
+    }
+
+    LOGE("file open 3");
+    len = fread(&mMinorVersion, 1, sizeof(mMinorVersion), f);
+    if (len != sizeof(mMinorVersion)) {
+        return false;
+    }
+
+    LOGE("file open 4");
+    uint32_t flags;
+    len = fread(&flags, 1, sizeof(flags), f);
+    if (len != sizeof(flags)) {
+        return false;
+    }
+    mUse64BitOffsets = (flags & 1) != 0;
+
+    LOGE("file open 64bit = %i", mUse64BitOffsets);
+
+    if (mUse64BitOffsets) {
+        len = fread(&mDataSize, 1, sizeof(mDataSize), f);
+        if (len != sizeof(mDataSize)) {
+            return false;
+        }
+    } else {
+        uint32_t tmp;
+        len = fread(&tmp, 1, sizeof(tmp), f);
+        if (len != sizeof(tmp)) {
+            return false;
+        }
+        mDataSize = tmp;
+    }
+
+    LOGE("file open size = %lli", mDataSize);
+
+    // We should know enough to read the file in at this point.
+    fseek(f, SEEK_SET, 0);
+    mAlloc= malloc(mDataSize);
+    if (!mAlloc) {
+        return false;
+    }
+    mData = (uint8_t *)mAlloc;
+    len = fread(mAlloc, 1, mDataSize, f);
+    if (len != mDataSize) {
+        return false;
+    }
+
+    LOGE("file start processing");
+    return process(rsc);
+}
+
+bool FileA3D::processIndex(Context *rsc, A3DIndexEntry *ie)
+{
+    bool ret = false;
+    IO io(mData + ie->mOffset, mUse64BitOffsets);
+
+    LOGE("process index, type %i", ie->mType);
+
+    switch(ie->mType) {
+    case CHUNK_ELEMENT:
+        processChunk_Element(rsc, &io, ie);
+        break;
+    case CHUNK_ELEMENT_SOURCE:
+        processChunk_ElementSource(rsc, &io, ie);
+        break;
+    case CHUNK_VERTICIES:
+        processChunk_Verticies(rsc, &io, ie);
+        break;
+    case CHUNK_MESH:
+        processChunk_Mesh(rsc, &io, ie);
+        break;
+    case CHUNK_PRIMITIVE:
+        processChunk_Primitive(rsc, &io, ie);
+        break;
+    default:
+        LOGE("FileA3D Unknown chunk type");
+        break;
+    }
+    return (ie->mRsObj != NULL);
+}
+
+bool FileA3D::process(Context *rsc)
+{
+    LOGE("process");
+    IO io(mData + 12, mUse64BitOffsets);
+    bool ret = true;
+
+    // Build the index first
+    LOGE("process 1");
+    io.loadU32(); // major version, already loaded
+    io.loadU32(); // minor version, already loaded
+    LOGE("process 2");
+
+    io.loadU32();  // flags
+    io.loadOffset(); // filesize, already loaded.
+    LOGE("process 4");
+    uint64_t mIndexOffset = io.loadOffset();
+    uint64_t mStringOffset = io.loadOffset();
+
+    LOGE("process mIndexOffset= 0x%016llx", mIndexOffset);
+    LOGE("process mStringOffset= 0x%016llx", mStringOffset);
+
+    IO index(mData + mIndexOffset, mUse64BitOffsets);
+    IO stringTable(mData + mStringOffset, mUse64BitOffsets);
+
+    uint32_t stringEntryCount = stringTable.loadU32();
+    LOGE("stringEntryCount %i", stringEntryCount);
+    mStrings.setCapacity(stringEntryCount);
+    mStringIndexValues.setCapacity(stringEntryCount);
+    if (stringEntryCount) {
+        uint32_t stringType = stringTable.loadU32();
+        LOGE("stringType %i", stringType);
+        rsAssert(stringType==0);
+        for (uint32_t ct = 0; ct < stringEntryCount; ct++) {
+            uint64_t offset = stringTable.loadOffset();
+            LOGE("string offset 0x%016llx", offset);
+            IO tmp(mData + offset, mUse64BitOffsets);
+            String8 s;
+            tmp.loadString(&s);
+            LOGE("string %s", s.string());
+            mStrings.push(s);
+        }
+    }
+
+    LOGE("strings done");
+    uint32_t indexEntryCount = index.loadU32();
+    LOGE("index count %i", indexEntryCount);
+    mIndex.setCapacity(indexEntryCount);
+    for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
+        A3DIndexEntry e;
+        uint32_t stringIndex = index.loadU32();
+        LOGE("index %i", ct);
+        LOGE("  string index %i", stringIndex);
+        e.mType = (A3DChunkType)index.loadU32();
+        LOGE("  type %i", e.mType);
+        e.mOffset = index.loadOffset();
+        LOGE("  offset 0x%016llx", e.mOffset);
+
+        if (stringIndex && (stringIndex < mStrings.size())) {
+            e.mID = mStrings[stringIndex];
+            mStringIndexValues.editItemAt(stringIndex) = ct;
+            LOGE("  id %s", e.mID.string());
+        }
+
+        mIndex.push(e);
+    }
+    LOGE("index done");
+
+    // At this point the index should be fully populated.
+    // We can now walk though it and load all the objects.
+    for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
+        LOGE("processing index entry %i", ct);
+        processIndex(rsc, &mIndex.editItemAt(ct));
+    }
+
+    return ret;
+}
+
+
+FileA3D::IO::IO(const uint8_t *buf, bool use64)
+{
+    mData = buf;
+    mPos = 0;
+    mUse64 = use64;
+}
+
+uint64_t FileA3D::IO::loadOffset()
+{
+    uint64_t tmp;
+    if (mUse64) {
+        mPos = (mPos + 7) & (~7);
+        tmp = reinterpret_cast<const uint64_t *>(&mData[mPos])[0];
+        mPos += sizeof(uint64_t);
+        return tmp;
+    }
+    return loadU32();
+}
+
+void FileA3D::IO::loadString(String8 *s)
+{
+    LOGE("loadString");
+    uint32_t len = loadU32();
+    LOGE("loadString len %i", len);
+    s->setTo((const char *)&mData[mPos], len);
+    mPos += len;
+}
+
+
+void FileA3D::processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+    Mesh * m = new Mesh;
+
+    m->mPrimitivesCount = io->loadU32();
+    m->mPrimitives = new Mesh::Primitive_t *[m->mPrimitivesCount];
+
+    for (uint32_t ct = 0; ct < m->mPrimitivesCount; ct++) {
+        uint32_t index = io->loadU32();
+
+        m->mPrimitives[ct] = (Mesh::Primitive_t *)mIndex[index].mRsObj;
+    }
+    ie->mRsObj = m;
+}
+
+void FileA3D::processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+    Mesh::Primitive_t * p = new Mesh::Primitive_t;
+
+    p->mIndexCount = io->loadU32();
+    uint32_t vertIdx = io->loadU32();
+    uint32_t bits = io->loadU8();
+    p->mType = (RsPrimitive)io->loadU8();
+
+    p->mVerticies = (Mesh::Verticies_t *)mIndex[vertIdx].mRsObj;
+
+    p->mIndicies = new uint16_t[p->mIndexCount];
+    for (uint32_t ct = 0; ct < p->mIndexCount; ct++) {
+        switch(bits) {
+        case 8:
+            p->mIndicies[ct] = io->loadU8();
+            break;
+        case 16:
+            p->mIndicies[ct] = io->loadU16();
+            break;
+        case 32:
+            p->mIndicies[ct] = io->loadU32();
+            break;
+        }
+    }
+
+    ie->mRsObj = p;
+}
+
+void FileA3D::processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+    Mesh::Verticies_t *cv = new Mesh::Verticies_t;
+    cv->mAllocationCount = io->loadU32();
+    cv->mAllocations = new Allocation *[cv->mAllocationCount];
+    for (uint32_t ct = 0; ct < cv->mAllocationCount; ct++) {
+        uint32_t i = io->loadU32();
+        cv->mAllocations[ct] = (Allocation *)mIndex[i].mRsObj;
+    }
+    ie->mRsObj = cv;
+}
+
+void FileA3D::processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+    LOGE("processChunk_Element ie %p", ie);
+    rsi_ElementBegin(rsc);
+
+    uint32_t count = io->loadU32();
+    LOGE("processChunk_Element count %i", count);
+    while (count--) {
+        RsDataKind dk = (RsDataKind)io->loadU8();
+        RsDataType dt = (RsDataType)io->loadU8();
+        uint32_t bits = io->loadU8();
+        bool isNorm = io->loadU8() != 0;
+        LOGE("  %i %i %i %i", dk, dt, bits, isNorm);
+        rsi_ElementAdd(rsc, dk, dt, isNorm, bits);
+    }
+    LOGE("processChunk_Element create");
+    ie->mRsObj = rsi_ElementCreate(rsc);
+}
+
+void FileA3D::processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+    uint32_t index = io->loadU32();
+    uint32_t count = io->loadU32();
+
+    RsElement e = (RsElement)mIndex[index].mRsObj;
+
+    RsAllocation a = rsi_AllocationCreateSized(rsc, e, count);
+    Allocation * alloc = static_cast<Allocation *>(a);
+
+    float * data = (float *)alloc->getPtr();
+    while(count--) {
+        *data = io->loadF();
+        data++;
+    }
+    ie->mRsObj = alloc;
+}
+
+namespace android {
+namespace renderscript {
+
+
+RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len)
+{
+    FileA3D *fa3d = new FileA3D;
+
+    FILE *f = fopen("/sdcard/test.a3d", "rb");
+    if (f) {
+        fa3d->load(rsc, f);
+        fclose(f);
+        return fa3d;
+    }
+    delete fa3d;
+    return NULL;
+}
+
+
+}
+}
diff --git a/rsFileA3D.h b/rsFileA3D.h
new file mode 100644
index 0000000..9ee08ec
--- /dev/null
+++ b/rsFileA3D.h
@@ -0,0 +1,122 @@
+/*
+ * 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_FILE_A3D_H
+#define ANDROID_RS_FILE_A3D_H
+
+#include "RenderScript.h"
+#include "rsFileA3DDecls.h"
+#include "rsMesh.h"
+
+#include <utils/String8.h>
+#include <stdio.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class FileA3D
+{
+public:
+    FileA3D();
+    ~FileA3D();
+
+    uint32_t mMajorVersion;
+    uint32_t mMinorVersion;
+    uint64_t mIndexOffset;
+    uint64_t mStringTableOffset;
+    bool mUse64BitOffsets;
+
+    struct A3DIndexEntry {
+        String8 mID;
+        A3DChunkType mType;
+        uint64_t mOffset;
+        void * mRsObj;
+    };
+
+    bool load(Context *rsc, FILE *f);
+
+protected:
+    class IO
+    {
+    public:
+        IO(const uint8_t *, bool use64);
+    
+        float loadF() {
+            mPos = (mPos + 3) & (~3);
+            float tmp = reinterpret_cast<const float *>(&mData[mPos])[0];
+            mPos += sizeof(float);
+            return tmp;
+        }
+        int32_t loadI32() {
+            mPos = (mPos + 3) & (~3);
+            int32_t tmp = reinterpret_cast<const int32_t *>(&mData[mPos])[0];
+            mPos += sizeof(int32_t);
+            return tmp;
+        }
+        uint32_t loadU32() {
+            mPos = (mPos + 3) & (~3);
+            uint32_t tmp = reinterpret_cast<const uint32_t *>(&mData[mPos])[0];
+            mPos += sizeof(uint32_t);
+            return tmp;
+        }
+        uint16_t loadU16() {
+            mPos = (mPos + 1) & (~1);
+            uint16_t tmp = reinterpret_cast<const uint16_t *>(&mData[mPos])[0];
+            mPos += sizeof(uint16_t);
+            return tmp;
+        }
+        uint8_t loadU8() {
+            uint8_t tmp = reinterpret_cast<const uint8_t *>(&mData[mPos])[0];
+            mPos += sizeof(uint8_t);
+            return tmp;
+        }
+        uint64_t loadOffset();
+        void loadString(String8 *s);
+        uint64_t getPos() const {return mPos;}
+        const uint8_t * getPtr() const;
+    protected:
+        const uint8_t * mData;
+        uint64_t mPos;
+        bool mUse64;
+    };
+
+
+    bool process(Context *rsc);
+    bool processIndex(Context *rsc, A3DIndexEntry *);
+    void processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie);
+    void processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie);
+    void processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie);
+    void processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie);
+    void processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie);
+
+    const uint8_t * mData;
+    void * mAlloc;
+    uint64_t mDataSize;
+    Context * mRsc;
+
+    Vector<A3DIndexEntry> mIndex;
+    Vector<String8> mStrings;
+    Vector<uint32_t> mStringIndexValues;
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_FILE_A3D_H
+
+
diff --git a/rsFileA3DDecls.h b/rsFileA3DDecls.h
new file mode 100644
index 0000000..2a08bd3
--- /dev/null
+++ b/rsFileA3DDecls.h
@@ -0,0 +1,44 @@
+/*
+ * 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_FILE_A3D_DECLS_H
+#define ANDROID_RS_FILE_A3D_DECLS_H
+
+
+#define A3D_MAGIC_KEY "Android3D_ff"
+
+namespace android {
+namespace renderscript {
+
+    enum A3DChunkType {
+        CHUNK_EMPTY,
+
+        CHUNK_ELEMENT,
+        CHUNK_ELEMENT_SOURCE,
+        CHUNK_VERTICIES,
+        CHUNK_MESH,
+        CHUNK_PRIMITIVE,
+
+        CHUNK_LAST
+    };
+
+
+}
+}
+#endif //ANDROID_RS_FILE_A3D_H
+
+
+
diff --git a/rsMesh.cpp b/rsMesh.cpp
index 6eb95fc..aeb52ed 100644
--- a/rsMesh.cpp
+++ b/rsMesh.cpp
@@ -24,9 +24,10 @@
 
 Mesh::Mesh()
 {
-    mSources = NULL;
+    mVerticies = NULL;
+    mVerticiesCount = 0;
     mPrimitives = NULL;
-    mPrimitiveCount = 0;
+    mPrimitivesCount = 0;
 }
 
 Mesh::~Mesh()
diff --git a/rsMesh.h b/rsMesh.h
index c6d3bc9..1db36e1 100644
--- a/rsMesh.h
+++ b/rsMesh.h
@@ -32,10 +32,11 @@
     Mesh();
     ~Mesh();
 
-    struct VertexSource_t
+    struct Verticies_t
     {
-        const Element * mVertexElement;
-        void * mVertexData;
+        Allocation ** mAllocations;
+        uint32_t mAllocationCount;
+
         size_t mVertexDataSize;
 
         size_t mOffsetCoord;
@@ -52,16 +53,19 @@
     struct Primitive_t
     {
         RsPrimitive mType;
-        const Element * mIndexElement;
-        void * mVertexData;
-        size_t mIndexDataSize;
+        Verticies_t *mVerticies;
 
-        uint32_t mBufferObject;
+        uint32_t mIndexCount;
+        uint16_t *mIndicies;
     };
 
-    VertexSource_t * mSources;
-    Primitive_t * mPrimitives;
-    uint32_t mPrimitiveCount;
+    Verticies_t * mVerticies;
+    uint32_t mVerticiesCount;
+
+    Primitive_t ** mPrimitives;
+    uint32_t mPrimitivesCount;
+
+
 
     void analyzeElement();
 protected: