rsFileA3D.cpp revision b825f67adb5d1e1751fe108e6dbf9c6f2555c283
1 2/* 3 * Copyright (C) 2009 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18#ifndef ANDROID_RS_BUILD_FOR_HOST 19#include "rsContext.h" 20#else 21#include "rsContextHostStub.h" 22#endif 23 24#include "rsFileA3D.h" 25 26#include "rsMesh.h" 27#include "rsAnimation.h" 28 29using namespace android; 30using namespace android::renderscript; 31 32FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc) 33{ 34 mAlloc = NULL; 35 mData = NULL; 36 mWriteStream = NULL; 37 mReadStream = NULL; 38 39 mMajorVersion = 0; 40 mMinorVersion = 1; 41 mDataSize = 0; 42} 43 44FileA3D::~FileA3D() 45{ 46 for(size_t i = 0; i < mIndex.size(); i ++) { 47 delete mIndex[i]; 48 } 49 for(size_t i = 0; i < mWriteIndex.size(); i ++) { 50 delete mWriteIndex[i]; 51 } 52 if(mWriteStream) { 53 delete mWriteStream; 54 } 55 if(mReadStream) { 56 delete mWriteStream; 57 } 58 if(mAlloc) { 59 free(mAlloc); 60 } 61} 62 63void FileA3D::parseHeader(IStream *headerStream) 64{ 65 mMajorVersion = headerStream->loadU32(); 66 mMinorVersion = headerStream->loadU32(); 67 uint32_t flags = headerStream->loadU32(); 68 mUse64BitOffsets = (flags & 1) != 0; 69 70 LOGE("file open 64bit = %i", mUse64BitOffsets); 71 72 uint32_t numIndexEntries = headerStream->loadU32(); 73 for(uint32_t i = 0; i < numIndexEntries; i ++) { 74 A3DIndexEntry *entry = new A3DIndexEntry(); 75 headerStream->loadString(&entry->mObjectName); 76 LOGE("Header data, entry name = %s", entry->mObjectName.string()); 77 entry->mType = (RsA3DClassID)headerStream->loadU32(); 78 if(mUse64BitOffsets){ 79 entry->mOffset = headerStream->loadOffset(); 80 entry->mLength = headerStream->loadOffset(); 81 } 82 else { 83 entry->mOffset = headerStream->loadU32(); 84 entry->mLength = headerStream->loadU32(); 85 } 86 entry->mRsObj = NULL; 87 mIndex.push(entry); 88 } 89} 90 91bool FileA3D::load(const void *data, size_t length) 92{ 93 LOGE("Loading data. Size: %u", length); 94 const uint8_t *localData = (const uint8_t *)data; 95 96 size_t lengthRemaining = length; 97 size_t magicStrLen = 12; 98 if ((length < magicStrLen) || 99 memcmp(data, "Android3D_ff", magicStrLen)) { 100 return false; 101 } 102 103 localData += magicStrLen; 104 lengthRemaining -= magicStrLen; 105 106 // Next we get our header size 107 uint64_t headerSize = 0; 108 if(lengthRemaining < sizeof(headerSize)) { 109 return false; 110 } 111 112 memcpy(&headerSize, localData, sizeof(headerSize)); 113 localData += sizeof(headerSize); 114 lengthRemaining -= sizeof(headerSize); 115 116 LOGE("Loading data, headerSize = %lli", headerSize); 117 118 if(lengthRemaining < headerSize) { 119 return false; 120 } 121 122 uint8_t *headerData = (uint8_t *)malloc(headerSize); 123 if(!headerData) { 124 return false; 125 } 126 127 memcpy(headerData, localData, headerSize); 128 129 // Now open the stream to parse the header 130 IStream headerStream(headerData, false); 131 parseHeader(&headerStream); 132 133 free(headerData); 134 135 localData += headerSize; 136 lengthRemaining -= headerSize; 137 138 if(lengthRemaining < sizeof(mDataSize)) { 139 return false; 140 } 141 142 // Read the size of the data 143 memcpy(&mDataSize, localData, sizeof(mDataSize)); 144 localData += sizeof(mDataSize); 145 lengthRemaining -= sizeof(mDataSize); 146 147 LOGE("Loading data, mDataSize = %lli", mDataSize); 148 149 if(lengthRemaining < mDataSize) { 150 return false; 151 } 152 153 // We should know enough to read the file in at this point. 154 mAlloc = malloc(mDataSize); 155 if (!mAlloc) { 156 return false; 157 } 158 mData = (uint8_t *)mAlloc; 159 memcpy(mAlloc, localData, mDataSize); 160 161 mReadStream = new IStream(mData, mUse64BitOffsets); 162 163 return true; 164} 165 166bool FileA3D::load(FILE *f) 167{ 168 char magicString[12]; 169 size_t len; 170 171 LOGE("file open 1"); 172 len = fread(magicString, 1, 12, f); 173 if ((len != 12) || 174 memcmp(magicString, "Android3D_ff", 12)) { 175 return false; 176 } 177 178 // Next thing is the size of the header 179 uint64_t headerSize = 0; 180 len = fread(&headerSize, 1, sizeof(headerSize), f); 181 if (len != sizeof(headerSize) || headerSize == 0) { 182 return false; 183 } 184 185 uint8_t *headerData = (uint8_t *)malloc(headerSize); 186 if(!headerData) { 187 return false; 188 } 189 190 len = fread(headerData, 1, headerSize, f); 191 if (len != headerSize) { 192 return false; 193 } 194 195 // Now open the stream to parse the header 196 IStream headerStream(headerData, false); 197 parseHeader(&headerStream); 198 199 free(headerData); 200 201 // Next thing is the size of the header 202 len = fread(&mDataSize, 1, sizeof(mDataSize), f); 203 if (len != sizeof(mDataSize) || mDataSize == 0) { 204 return false; 205 } 206 207 LOGE("file open size = %lli", mDataSize); 208 209 // We should know enough to read the file in at this point. 210 mAlloc = malloc(mDataSize); 211 if (!mAlloc) { 212 return false; 213 } 214 mData = (uint8_t *)mAlloc; 215 len = fread(mAlloc, 1, mDataSize, f); 216 if (len != mDataSize) { 217 return false; 218 } 219 220 mReadStream = new IStream(mData, mUse64BitOffsets); 221 222 LOGE("Header is read an stream initialized"); 223 return true; 224} 225 226size_t FileA3D::getNumIndexEntries() const { 227 return mIndex.size(); 228} 229 230const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const { 231 if(index < mIndex.size()) { 232 return mIndex[index]; 233 } 234 return NULL; 235} 236 237ObjectBase *FileA3D::initializeFromEntry(size_t index) { 238 if(index >= mIndex.size()) { 239 return NULL; 240 } 241 242 FileA3D::A3DIndexEntry *entry = mIndex[index]; 243 if(!entry) { 244 return NULL; 245 } 246 247 if(entry->mRsObj) { 248 entry->mRsObj->incUserRef(); 249 return entry->mRsObj; 250 } 251 252 // Seek to the beginning of object 253 mReadStream->reset(entry->mOffset); 254 switch (entry->mType) { 255 case RS_A3D_CLASS_ID_UNKNOWN: 256 return NULL; 257 case RS_A3D_CLASS_ID_MESH: 258 entry->mRsObj = Mesh::createFromStream(mRSC, mReadStream); 259 break; 260 case RS_A3D_CLASS_ID_SIMPLE_MESH: 261 entry->mRsObj = SimpleMesh::createFromStream(mRSC, mReadStream); 262 break; 263 case RS_A3D_CLASS_ID_TYPE: 264 entry->mRsObj = Type::createFromStream(mRSC, mReadStream); 265 break; 266 case RS_A3D_CLASS_ID_ELEMENT: 267 entry->mRsObj = Element::createFromStream(mRSC, mReadStream); 268 break; 269 case RS_A3D_CLASS_ID_ALLOCATION: 270 entry->mRsObj = Allocation::createFromStream(mRSC, mReadStream); 271 break; 272 case RS_A3D_CLASS_ID_PROGRAM_VERTEX: 273 entry->mRsObj = ProgramVertex::createFromStream(mRSC, mReadStream); 274 break; 275 case RS_A3D_CLASS_ID_PROGRAM_RASTER: 276 entry->mRsObj = ProgramRaster::createFromStream(mRSC, mReadStream); 277 break; 278 case RS_A3D_CLASS_ID_PROGRAM_FRAGMENT: 279 entry->mRsObj = ProgramFragment::createFromStream(mRSC, mReadStream); 280 break; 281 case RS_A3D_CLASS_ID_PROGRAM_STORE: 282 entry->mRsObj = ProgramStore::createFromStream(mRSC, mReadStream); 283 break; 284 case RS_A3D_CLASS_ID_SAMPLER: 285 entry->mRsObj = Sampler::createFromStream(mRSC, mReadStream); 286 break; 287 case RS_A3D_CLASS_ID_ANIMATION: 288 entry->mRsObj = Animation::createFromStream(mRSC, mReadStream); 289 break; 290 case RS_A3D_CLASS_ID_LIGHT: 291 entry->mRsObj = Light::createFromStream(mRSC, mReadStream); 292 break; 293 case RS_A3D_CLASS_ID_ADAPTER_1D: 294 entry->mRsObj = Adapter1D::createFromStream(mRSC, mReadStream); 295 break; 296 case RS_A3D_CLASS_ID_ADAPTER_2D: 297 entry->mRsObj = Adapter2D::createFromStream(mRSC, mReadStream); 298 break; 299 case RS_A3D_CLASS_ID_SCRIPT_C: 300 return NULL; 301 } 302 if(entry->mRsObj) { 303 entry->mRsObj->incUserRef(); 304 } 305 return entry->mRsObj; 306} 307 308bool FileA3D::writeFile(const char *filename) 309{ 310 if(!mWriteStream) { 311 LOGE("No objects to write\n"); 312 return false; 313 } 314 if(mWriteStream->getPos() == 0) { 315 LOGE("No objects to write\n"); 316 return false; 317 } 318 319 FILE *writeHandle = fopen(filename, "wb"); 320 if(!writeHandle) { 321 LOGE("Couldn't open the file for writing\n"); 322 return false; 323 } 324 325 // Open a new stream to make writing the header easier 326 OStream headerStream(5*1024, false); 327 headerStream.addU32(mMajorVersion); 328 headerStream.addU32(mMinorVersion); 329 uint32_t is64Bit = 0; 330 headerStream.addU32(is64Bit); 331 332 uint32_t writeIndexSize = mWriteIndex.size(); 333 headerStream.addU32(writeIndexSize); 334 for(uint32_t i = 0; i < writeIndexSize; i ++) { 335 headerStream.addString(&mWriteIndex[i]->mObjectName); 336 headerStream.addU32((uint32_t)mWriteIndex[i]->mType); 337 if(mUse64BitOffsets){ 338 headerStream.addOffset(mWriteIndex[i]->mOffset); 339 headerStream.addOffset(mWriteIndex[i]->mLength); 340 } 341 else { 342 uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset; 343 headerStream.addU32(offset); 344 offset = (uint32_t)mWriteIndex[i]->mLength; 345 headerStream.addU32(offset); 346 } 347 } 348 349 // Write our magic string so we know we are reading the right file 350 String8 magicString(A3D_MAGIC_KEY); 351 fwrite(magicString.string(), sizeof(char), magicString.size(), writeHandle); 352 353 // Store the size of the header to make it easier to parse when we read it 354 uint64_t headerSize = headerStream.getPos(); 355 fwrite(&headerSize, sizeof(headerSize), 1, writeHandle); 356 357 // Now write our header 358 fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle); 359 360 // Now write the size of the data part of the file for easier parsing later 361 uint64_t fileDataSize = mWriteStream->getPos(); 362 fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle); 363 364 fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle); 365 366 int status = fclose(writeHandle); 367 368 if(status != 0) { 369 LOGE("Couldn't close file\n"); 370 return false; 371 } 372 373 return true; 374} 375 376void FileA3D::appendToFile(ObjectBase *obj) { 377 if(!obj) { 378 return; 379 } 380 if(!mWriteStream) { 381 const uint64_t initialStreamSize = 256*1024; 382 mWriteStream = new OStream(initialStreamSize, false); 383 } 384 A3DIndexEntry *indexEntry = new A3DIndexEntry(); 385 indexEntry->mObjectName.setTo(obj->getName()); 386 indexEntry->mType = obj->getClassId(); 387 indexEntry->mOffset = mWriteStream->getPos(); 388 indexEntry->mRsObj = obj; 389 mWriteIndex.push(indexEntry); 390 obj->serialize(mWriteStream); 391 indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset; 392 mWriteStream->align(4); 393} 394 395namespace android { 396namespace renderscript { 397 398void rsi_FileA3DGetNumIndexEntries(Context *rsc, int32_t *numEntries, RsFile file) 399{ 400 FileA3D *fa3d = static_cast<FileA3D *>(file); 401 402 if(fa3d) { 403 *numEntries = fa3d->getNumIndexEntries(); 404 } 405 else { 406 *numEntries = 0; 407 } 408} 409 410void rsi_FileA3DGetIndexEntries(Context *rsc, RsFileIndexEntry *fileEntries, uint32_t numEntries, RsFile file) 411{ 412 FileA3D *fa3d = static_cast<FileA3D *>(file); 413 414 if(!fa3d) { 415 LOGE("Can't load index entries. No valid file"); 416 return; 417 } 418 419 uint32_t numFileEntries = fa3d->getNumIndexEntries(); 420 if(numFileEntries != numEntries || numEntries == 0 || fileEntries == NULL) { 421 LOGE("Can't load index entries. Invalid number requested"); 422 return; 423 } 424 425 for(uint32_t i = 0; i < numFileEntries; i ++) { 426 const FileA3D::A3DIndexEntry *entry = fa3d->getIndexEntry(i); 427 fileEntries[i].classID = entry->getType(); 428 fileEntries[i].objectName = entry->getObjectName().string(); 429 } 430 431} 432 433RsObjectBase rsi_FileA3DGetEntryByIndex(Context *rsc, uint32_t index, RsFile file) 434{ 435 FileA3D *fa3d = static_cast<FileA3D *>(file); 436 if(!fa3d) { 437 LOGE("Can't load entry. No valid file"); 438 return NULL; 439 } 440 441 ObjectBase *obj = fa3d->initializeFromEntry(index); 442 LOGE("Returning object with name %s", obj->getName()); 443 444 return obj; 445} 446 447RsFile rsi_FileA3DCreateFromAssetStream(Context *rsc, const void *data, uint32_t len) 448{ 449 if (data == NULL) { 450 LOGE("File load failed. Asset stream is NULL"); 451 return NULL; 452 } 453 454 FileA3D *fa3d = new FileA3D(rsc); 455 456 fa3d->load(data, len); 457 fa3d->incUserRef(); 458 459 return fa3d; 460} 461 462 463RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len) 464{ 465 FileA3D *fa3d = new FileA3D(rsc); 466 467 FILE *f = fopen("/sdcard/test.a3d", "rb"); 468 if (f) { 469 fa3d->load(f); 470 fclose(f); 471 fa3d->incUserRef(); 472 return fa3d; 473 } 474 delete fa3d; 475 return NULL; 476} 477 478 479} 480} 481