387 lines
10 KiB
C++
387 lines
10 KiB
C++
|
|
||
|
/*
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|