| |
| /* |
| * 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; |
| } |
| |
| |
| } |
| } |