|  | 
 | /* | 
 |  * 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(rsc); | 
 |  | 
 |     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(); | 
 |     p->mRestartCounts = io->loadU16(); | 
 |     uint32_t bits = io->loadU8(); | 
 |     p->mType = (RsPrimitive)io->loadU8(); | 
 |  | 
 |     LOGE("processChunk_Primitive count %i, bits %i", p->mIndexCount, bits); | 
 |  | 
 |     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; | 
 |         } | 
 |         LOGE("  idx %i", p->mIndicies[ct]); | 
 |     } | 
 |  | 
 |     if (p->mRestartCounts) { | 
 |         p->mRestarts = new uint16_t[p->mRestartCounts]; | 
 |         for (uint32_t ct = 0; ct < p->mRestartCounts; ct++) { | 
 |             switch(bits) { | 
 |             case 8: | 
 |                 p->mRestarts[ct] = io->loadU8(); | 
 |                 break; | 
 |             case 16: | 
 |                 p->mRestarts[ct] = io->loadU16(); | 
 |                 break; | 
 |             case 32: | 
 |                 p->mRestarts[ct] = io->loadU32(); | 
 |                 break; | 
 |             } | 
 |             LOGE("  idx %i", p->mRestarts[ct]); | 
 |         } | 
 |     } else { | 
 |         p->mRestarts = NULL; | 
 |     } | 
 |  | 
 |     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]; | 
 |     LOGE("processChunk_Verticies count %i", cv->mAllocationCount); | 
 |     for (uint32_t ct = 0; ct < cv->mAllocationCount; ct++) { | 
 |         uint32_t i = io->loadU32(); | 
 |         cv->mAllocations[ct] = (Allocation *)mIndex[i].mRsObj; | 
 |         LOGE("  idx %i", i); | 
 |     } | 
 |     ie->mRsObj = cv; | 
 | } | 
 |  | 
 | void FileA3D::processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *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, 0); | 
 |     } | 
 |     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(); | 
 |  | 
 |     LOGE("processChunk_ElementSource count %i, index %i", count, index); | 
 |  | 
 |     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(); | 
 |         LOGE("  %f", *data); | 
 |         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; | 
 | } | 
 |  | 
 |  | 
 | } | 
 | } |