Switched all native code to go through Mesh class. Removed SimpleMesh Added java Mesh class Will need to port all existing code to use java Mesh, then remove java SimpleMesh. Change-Id: Idb9c03d0b06b4ef87db28dffcffa1881d39120e5
479 lines
13 KiB
C++
479 lines
13 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.
|
|
*/
|
|
|
|
#ifndef ANDROID_RS_BUILD_FOR_HOST
|
|
#include "rsContext.h"
|
|
#else
|
|
#include "rsContextHostStub.h"
|
|
#endif
|
|
|
|
#include "rsFileA3D.h"
|
|
|
|
#include "rsMesh.h"
|
|
#include "rsAnimation.h"
|
|
|
|
|
|
using namespace android;
|
|
using namespace android::renderscript;
|
|
|
|
FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc)
|
|
{
|
|
mAlloc = NULL;
|
|
mData = NULL;
|
|
mWriteStream = NULL;
|
|
mReadStream = NULL;
|
|
|
|
mMajorVersion = 0;
|
|
mMinorVersion = 1;
|
|
mDataSize = 0;
|
|
}
|
|
|
|
FileA3D::~FileA3D()
|
|
{
|
|
for(size_t i = 0; i < mIndex.size(); i ++) {
|
|
delete mIndex[i];
|
|
}
|
|
for(size_t i = 0; i < mWriteIndex.size(); i ++) {
|
|
delete mWriteIndex[i];
|
|
}
|
|
if(mWriteStream) {
|
|
delete mWriteStream;
|
|
}
|
|
if(mReadStream) {
|
|
delete mWriteStream;
|
|
}
|
|
if(mAlloc) {
|
|
free(mAlloc);
|
|
}
|
|
}
|
|
|
|
void FileA3D::parseHeader(IStream *headerStream)
|
|
{
|
|
mMajorVersion = headerStream->loadU32();
|
|
mMinorVersion = headerStream->loadU32();
|
|
uint32_t flags = headerStream->loadU32();
|
|
mUse64BitOffsets = (flags & 1) != 0;
|
|
|
|
LOGE("file open 64bit = %i", mUse64BitOffsets);
|
|
|
|
uint32_t numIndexEntries = headerStream->loadU32();
|
|
for(uint32_t i = 0; i < numIndexEntries; i ++) {
|
|
A3DIndexEntry *entry = new A3DIndexEntry();
|
|
headerStream->loadString(&entry->mObjectName);
|
|
LOGE("Header data, entry name = %s", entry->mObjectName.string());
|
|
entry->mType = (RsA3DClassID)headerStream->loadU32();
|
|
if(mUse64BitOffsets){
|
|
entry->mOffset = headerStream->loadOffset();
|
|
entry->mLength = headerStream->loadOffset();
|
|
}
|
|
else {
|
|
entry->mOffset = headerStream->loadU32();
|
|
entry->mLength = headerStream->loadU32();
|
|
}
|
|
entry->mRsObj = NULL;
|
|
mIndex.push(entry);
|
|
}
|
|
}
|
|
|
|
bool FileA3D::load(const void *data, size_t length)
|
|
{
|
|
LOGE("Loading data. Size: %u", length);
|
|
const uint8_t *localData = (const uint8_t *)data;
|
|
|
|
size_t lengthRemaining = length;
|
|
size_t magicStrLen = 12;
|
|
if ((length < magicStrLen) ||
|
|
memcmp(data, "Android3D_ff", magicStrLen)) {
|
|
return false;
|
|
}
|
|
|
|
localData += magicStrLen;
|
|
lengthRemaining -= magicStrLen;
|
|
|
|
// Next we get our header size
|
|
uint64_t headerSize = 0;
|
|
if(lengthRemaining < sizeof(headerSize)) {
|
|
return false;
|
|
}
|
|
|
|
memcpy(&headerSize, localData, sizeof(headerSize));
|
|
localData += sizeof(headerSize);
|
|
lengthRemaining -= sizeof(headerSize);
|
|
|
|
LOGE("Loading data, headerSize = %lli", headerSize);
|
|
|
|
if(lengthRemaining < headerSize) {
|
|
return false;
|
|
}
|
|
|
|
uint8_t *headerData = (uint8_t *)malloc(headerSize);
|
|
if(!headerData) {
|
|
return false;
|
|
}
|
|
|
|
memcpy(headerData, localData, headerSize);
|
|
|
|
// Now open the stream to parse the header
|
|
IStream headerStream(headerData, false);
|
|
parseHeader(&headerStream);
|
|
|
|
free(headerData);
|
|
|
|
localData += headerSize;
|
|
lengthRemaining -= headerSize;
|
|
|
|
if(lengthRemaining < sizeof(mDataSize)) {
|
|
return false;
|
|
}
|
|
|
|
// Read the size of the data
|
|
memcpy(&mDataSize, localData, sizeof(mDataSize));
|
|
localData += sizeof(mDataSize);
|
|
lengthRemaining -= sizeof(mDataSize);
|
|
|
|
LOGE("Loading data, mDataSize = %lli", mDataSize);
|
|
|
|
if(lengthRemaining < mDataSize) {
|
|
return false;
|
|
}
|
|
|
|
// We should know enough to read the file in at this point.
|
|
mAlloc = malloc(mDataSize);
|
|
if (!mAlloc) {
|
|
return false;
|
|
}
|
|
mData = (uint8_t *)mAlloc;
|
|
memcpy(mAlloc, localData, mDataSize);
|
|
|
|
mReadStream = new IStream(mData, mUse64BitOffsets);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FileA3D::load(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;
|
|
}
|
|
|
|
// Next thing is the size of the header
|
|
uint64_t headerSize = 0;
|
|
len = fread(&headerSize, 1, sizeof(headerSize), f);
|
|
if (len != sizeof(headerSize) || headerSize == 0) {
|
|
return false;
|
|
}
|
|
|
|
uint8_t *headerData = (uint8_t *)malloc(headerSize);
|
|
if(!headerData) {
|
|
return false;
|
|
}
|
|
|
|
len = fread(headerData, 1, headerSize, f);
|
|
if (len != headerSize) {
|
|
return false;
|
|
}
|
|
|
|
// Now open the stream to parse the header
|
|
IStream headerStream(headerData, false);
|
|
parseHeader(&headerStream);
|
|
|
|
free(headerData);
|
|
|
|
// Next thing is the size of the header
|
|
len = fread(&mDataSize, 1, sizeof(mDataSize), f);
|
|
if (len != sizeof(mDataSize) || mDataSize == 0) {
|
|
return false;
|
|
}
|
|
|
|
LOGE("file open size = %lli", mDataSize);
|
|
|
|
// We should know enough to read the file in at this point.
|
|
mAlloc = malloc(mDataSize);
|
|
if (!mAlloc) {
|
|
return false;
|
|
}
|
|
mData = (uint8_t *)mAlloc;
|
|
len = fread(mAlloc, 1, mDataSize, f);
|
|
if (len != mDataSize) {
|
|
return false;
|
|
}
|
|
|
|
mReadStream = new IStream(mData, mUse64BitOffsets);
|
|
|
|
LOGE("Header is read an stream initialized");
|
|
return true;
|
|
}
|
|
|
|
size_t FileA3D::getNumIndexEntries() const {
|
|
return mIndex.size();
|
|
}
|
|
|
|
const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const {
|
|
if(index < mIndex.size()) {
|
|
return mIndex[index];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ObjectBase *FileA3D::initializeFromEntry(size_t index) {
|
|
if(index >= mIndex.size()) {
|
|
return NULL;
|
|
}
|
|
|
|
FileA3D::A3DIndexEntry *entry = mIndex[index];
|
|
if(!entry) {
|
|
return NULL;
|
|
}
|
|
|
|
if(entry->mRsObj) {
|
|
entry->mRsObj->incUserRef();
|
|
return entry->mRsObj;
|
|
}
|
|
|
|
// Seek to the beginning of object
|
|
mReadStream->reset(entry->mOffset);
|
|
switch (entry->mType) {
|
|
case RS_A3D_CLASS_ID_UNKNOWN:
|
|
return NULL;
|
|
case RS_A3D_CLASS_ID_MESH:
|
|
entry->mRsObj = Mesh::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_TYPE:
|
|
entry->mRsObj = Type::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_ELEMENT:
|
|
entry->mRsObj = Element::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_ALLOCATION:
|
|
entry->mRsObj = Allocation::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_PROGRAM_VERTEX:
|
|
entry->mRsObj = ProgramVertex::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_PROGRAM_RASTER:
|
|
entry->mRsObj = ProgramRaster::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_PROGRAM_FRAGMENT:
|
|
entry->mRsObj = ProgramFragment::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_PROGRAM_STORE:
|
|
entry->mRsObj = ProgramStore::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_SAMPLER:
|
|
entry->mRsObj = Sampler::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_ANIMATION:
|
|
entry->mRsObj = Animation::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_LIGHT:
|
|
entry->mRsObj = Light::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_ADAPTER_1D:
|
|
entry->mRsObj = Adapter1D::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_ADAPTER_2D:
|
|
entry->mRsObj = Adapter2D::createFromStream(mRSC, mReadStream);
|
|
break;
|
|
case RS_A3D_CLASS_ID_SCRIPT_C:
|
|
return NULL;
|
|
}
|
|
if(entry->mRsObj) {
|
|
entry->mRsObj->incUserRef();
|
|
}
|
|
return entry->mRsObj;
|
|
}
|
|
|
|
bool FileA3D::writeFile(const char *filename)
|
|
{
|
|
if(!mWriteStream) {
|
|
LOGE("No objects to write\n");
|
|
return false;
|
|
}
|
|
if(mWriteStream->getPos() == 0) {
|
|
LOGE("No objects to write\n");
|
|
return false;
|
|
}
|
|
|
|
FILE *writeHandle = fopen(filename, "wb");
|
|
if(!writeHandle) {
|
|
LOGE("Couldn't open the file for writing\n");
|
|
return false;
|
|
}
|
|
|
|
// Open a new stream to make writing the header easier
|
|
OStream headerStream(5*1024, false);
|
|
headerStream.addU32(mMajorVersion);
|
|
headerStream.addU32(mMinorVersion);
|
|
uint32_t is64Bit = 0;
|
|
headerStream.addU32(is64Bit);
|
|
|
|
uint32_t writeIndexSize = mWriteIndex.size();
|
|
headerStream.addU32(writeIndexSize);
|
|
for(uint32_t i = 0; i < writeIndexSize; i ++) {
|
|
headerStream.addString(&mWriteIndex[i]->mObjectName);
|
|
headerStream.addU32((uint32_t)mWriteIndex[i]->mType);
|
|
if(mUse64BitOffsets){
|
|
headerStream.addOffset(mWriteIndex[i]->mOffset);
|
|
headerStream.addOffset(mWriteIndex[i]->mLength);
|
|
}
|
|
else {
|
|
uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset;
|
|
headerStream.addU32(offset);
|
|
offset = (uint32_t)mWriteIndex[i]->mLength;
|
|
headerStream.addU32(offset);
|
|
}
|
|
}
|
|
|
|
// Write our magic string so we know we are reading the right file
|
|
String8 magicString(A3D_MAGIC_KEY);
|
|
fwrite(magicString.string(), sizeof(char), magicString.size(), writeHandle);
|
|
|
|
// Store the size of the header to make it easier to parse when we read it
|
|
uint64_t headerSize = headerStream.getPos();
|
|
fwrite(&headerSize, sizeof(headerSize), 1, writeHandle);
|
|
|
|
// Now write our header
|
|
fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle);
|
|
|
|
// Now write the size of the data part of the file for easier parsing later
|
|
uint64_t fileDataSize = mWriteStream->getPos();
|
|
fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle);
|
|
|
|
fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle);
|
|
|
|
int status = fclose(writeHandle);
|
|
|
|
if(status != 0) {
|
|
LOGE("Couldn't close file\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void FileA3D::appendToFile(ObjectBase *obj) {
|
|
if(!obj) {
|
|
return;
|
|
}
|
|
if(!mWriteStream) {
|
|
const uint64_t initialStreamSize = 256*1024;
|
|
mWriteStream = new OStream(initialStreamSize, false);
|
|
}
|
|
A3DIndexEntry *indexEntry = new A3DIndexEntry();
|
|
indexEntry->mObjectName.setTo(obj->getName());
|
|
indexEntry->mType = obj->getClassId();
|
|
indexEntry->mOffset = mWriteStream->getPos();
|
|
indexEntry->mRsObj = obj;
|
|
mWriteIndex.push(indexEntry);
|
|
obj->serialize(mWriteStream);
|
|
indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset;
|
|
mWriteStream->align(4);
|
|
}
|
|
|
|
namespace android {
|
|
namespace renderscript {
|
|
|
|
void rsi_FileA3DGetNumIndexEntries(Context *rsc, int32_t *numEntries, RsFile file)
|
|
{
|
|
FileA3D *fa3d = static_cast<FileA3D *>(file);
|
|
|
|
if(fa3d) {
|
|
*numEntries = fa3d->getNumIndexEntries();
|
|
}
|
|
else {
|
|
*numEntries = 0;
|
|
}
|
|
}
|
|
|
|
void rsi_FileA3DGetIndexEntries(Context *rsc, RsFileIndexEntry *fileEntries, uint32_t numEntries, RsFile file)
|
|
{
|
|
FileA3D *fa3d = static_cast<FileA3D *>(file);
|
|
|
|
if(!fa3d) {
|
|
LOGE("Can't load index entries. No valid file");
|
|
return;
|
|
}
|
|
|
|
uint32_t numFileEntries = fa3d->getNumIndexEntries();
|
|
if(numFileEntries != numEntries || numEntries == 0 || fileEntries == NULL) {
|
|
LOGE("Can't load index entries. Invalid number requested");
|
|
return;
|
|
}
|
|
|
|
for(uint32_t i = 0; i < numFileEntries; i ++) {
|
|
const FileA3D::A3DIndexEntry *entry = fa3d->getIndexEntry(i);
|
|
fileEntries[i].classID = entry->getType();
|
|
fileEntries[i].objectName = entry->getObjectName().string();
|
|
}
|
|
|
|
}
|
|
|
|
RsObjectBase rsi_FileA3DGetEntryByIndex(Context *rsc, uint32_t index, RsFile file)
|
|
{
|
|
FileA3D *fa3d = static_cast<FileA3D *>(file);
|
|
if(!fa3d) {
|
|
LOGE("Can't load entry. No valid file");
|
|
return NULL;
|
|
}
|
|
|
|
ObjectBase *obj = fa3d->initializeFromEntry(index);
|
|
LOGE("Returning object with name %s", obj->getName());
|
|
|
|
return obj;
|
|
}
|
|
|
|
RsFile rsi_FileA3DCreateFromAssetStream(Context *rsc, const void *data, uint32_t len)
|
|
{
|
|
if (data == NULL) {
|
|
LOGE("File load failed. Asset stream is NULL");
|
|
return NULL;
|
|
}
|
|
|
|
FileA3D *fa3d = new FileA3D(rsc);
|
|
|
|
fa3d->load(data, len);
|
|
fa3d->incUserRef();
|
|
|
|
return fa3d;
|
|
}
|
|
|
|
|
|
RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len)
|
|
{
|
|
FileA3D *fa3d = new FileA3D(rsc);
|
|
|
|
FILE *f = fopen("/sdcard/test.a3d", "rb");
|
|
if (f) {
|
|
fa3d->load(f);
|
|
fclose(f);
|
|
fa3d->incUserRef();
|
|
return fa3d;
|
|
}
|
|
delete fa3d;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
}
|
|
}
|