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