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