blob: 23c0cf5b9364c61bae06911eb5c221cd308bc5c7 [file] [log] [blame]
Jason Samsa5597fc2009-07-08 18:01:53 -07001
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
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -070018#ifndef ANDROID_RS_BUILD_FOR_HOST
Jason Samsa5597fc2009-07-08 18:01:53 -070019#include "rsContext.h"
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -070020#else
21#include "rsContextHostStub.h"
22#endif
Jason Samsa5597fc2009-07-08 18:01:53 -070023
Jason Samsa5597fc2009-07-08 18:01:53 -070024#include "rsFileA3D.h"
25
26#include "rsMesh.h"
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -070027#include "rsAnimation.h"
Jason Samsa5597fc2009-07-08 18:01:53 -070028
29using namespace android;
30using namespace android::renderscript;
31
Alex Sakhartchoukb825f672010-06-04 10:06:50 -070032FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc)
Jason Samsa5597fc2009-07-08 18:01:53 -070033{
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -070034 mAlloc = NULL;
35 mData = NULL;
36 mWriteStream = NULL;
37 mReadStream = NULL;
38
39 mMajorVersion = 0;
40 mMinorVersion = 1;
41 mDataSize = 0;
Jason Samsa5597fc2009-07-08 18:01:53 -070042}
43
44FileA3D::~FileA3D()
45{
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -070046 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 }
Jason Samsa5597fc2009-07-08 18:01:53 -070061}
62
Alex Sakhartchoukb825f672010-06-04 10:06:50 -070063void 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)
Jason Samsa5597fc2009-07-08 18:01:53 -0700167{
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
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700178 // 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) {
Jason Samsa5597fc2009-07-08 18:01:53 -0700182 return false;
183 }
184
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700185 uint8_t *headerData = (uint8_t *)malloc(headerSize);
186 if(!headerData) {
Jason Samsa5597fc2009-07-08 18:01:53 -0700187 return false;
188 }
189
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700190 len = fread(headerData, 1, headerSize, f);
191 if (len != headerSize) {
Jason Samsa5597fc2009-07-08 18:01:53 -0700192 return false;
193 }
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700194
195 // Now open the stream to parse the header
196 IStream headerStream(headerData, false);
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700197 parseHeader(&headerStream);
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700198
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700199 free(headerData);
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700200
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;
Jason Samsa5597fc2009-07-08 18:01:53 -0700205 }
206
207 LOGE("file open size = %lli", mDataSize);
208
209 // We should know enough to read the file in at this point.
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700210 mAlloc = malloc(mDataSize);
Jason Samsa5597fc2009-07-08 18:01:53 -0700211 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
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700220 mReadStream = new IStream(mData, mUse64BitOffsets);
221
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700222 LOGE("Header is read an stream initialized");
223 return true;
Jason Samsa5597fc2009-07-08 18:01:53 -0700224}
225
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700226size_t FileA3D::getNumIndexEntries() const {
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700227 return mIndex.size();
228}
Jason Samsa5597fc2009-07-08 18:01:53 -0700229
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700230const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const {
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700231 if(index < mIndex.size()) {
232 return mIndex[index];
Jason Samsa5597fc2009-07-08 18:01:53 -0700233 }
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700234 return NULL;
Jason Samsa5597fc2009-07-08 18:01:53 -0700235}
236
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700237ObjectBase *FileA3D::initializeFromEntry(size_t index) {
238 if(index >= mIndex.size()) {
239 return NULL;
240 }
241
242 FileA3D::A3DIndexEntry *entry = mIndex[index];
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700243 if(!entry) {
244 return NULL;
245 }
246
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700247 if(entry->mRsObj) {
248 entry->mRsObj->incUserRef();
249 return entry->mRsObj;
250 }
251
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700252 // Seek to the beginning of object
253 mReadStream->reset(entry->mOffset);
254 switch (entry->mType) {
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700255 case RS_A3D_CLASS_ID_UNKNOWN:
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700256 return NULL;
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700257 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:
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700300 return NULL;
301 }
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700302 if(entry->mRsObj) {
303 entry->mRsObj->incUserRef();
304 }
305 return entry->mRsObj;
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700306}
307
308bool FileA3D::writeFile(const char *filename)
Jason Samsa5597fc2009-07-08 18:01:53 -0700309{
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700310 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 }
Jason Samsa5597fc2009-07-08 18:01:53 -0700318
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700319 FILE *writeHandle = fopen(filename, "wb");
320 if(!writeHandle) {
321 LOGE("Couldn't open the file for writing\n");
322 return false;
323 }
Jason Samsa5597fc2009-07-08 18:01:53 -0700324
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700325 // 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);
Jason Samsa5597fc2009-07-08 18:01:53 -0700331
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700332 uint32_t writeIndexSize = mWriteIndex.size();
333 headerStream.addU32(writeIndexSize);
334 for(uint32_t i = 0; i < writeIndexSize; i ++) {
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700335 headerStream.addString(&mWriteIndex[i]->mObjectName);
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700336 headerStream.addU32((uint32_t)mWriteIndex[i]->mType);
337 if(mUse64BitOffsets){
338 headerStream.addOffset(mWriteIndex[i]->mOffset);
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700339 headerStream.addOffset(mWriteIndex[i]->mLength);
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700340 }
341 else {
342 uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset;
343 headerStream.addU32(offset);
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700344 offset = (uint32_t)mWriteIndex[i]->mLength;
345 headerStream.addU32(offset);
Jason Samsa5597fc2009-07-08 18:01:53 -0700346 }
347 }
348
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700349 // 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);
Jason Samsa5597fc2009-07-08 18:01:53 -0700352
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700353 // 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);
Jason Samsa5597fc2009-07-08 18:01:53 -0700356
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700357 // Now write our header
358 fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle);
Jason Samsa5597fc2009-07-08 18:01:53 -0700359
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700360 // 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;
Jason Samsa5597fc2009-07-08 18:01:53 -0700371 }
372
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700373 return true;
Jason Samsa5597fc2009-07-08 18:01:53 -0700374}
375
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700376void FileA3D::appendToFile(ObjectBase *obj) {
377 if(!obj) {
378 return;
Jason Samsa5597fc2009-07-08 18:01:53 -0700379 }
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700380 if(!mWriteStream) {
381 const uint64_t initialStreamSize = 256*1024;
382 mWriteStream = new OStream(initialStreamSize, false);
Jason Samsa5597fc2009-07-08 18:01:53 -0700383 }
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700384 A3DIndexEntry *indexEntry = new A3DIndexEntry();
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700385 indexEntry->mObjectName.setTo(obj->getName());
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700386 indexEntry->mType = obj->getClassId();
387 indexEntry->mOffset = mWriteStream->getPos();
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700388 indexEntry->mRsObj = obj;
Alex Sakhartchoukfb6b6142010-05-21 12:53:13 -0700389 mWriteIndex.push(indexEntry);
390 obj->serialize(mWriteStream);
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700391 indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset;
392 mWriteStream->align(4);
Jason Samsa5597fc2009-07-08 18:01:53 -0700393}
394
395namespace android {
396namespace renderscript {
397
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700398void 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
Jason Samsa5597fc2009-07-08 18:01:53 -0700462
463RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len)
464{
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700465 FileA3D *fa3d = new FileA3D(rsc);
Jason Samsa5597fc2009-07-08 18:01:53 -0700466
467 FILE *f = fopen("/sdcard/test.a3d", "rb");
468 if (f) {
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700469 fa3d->load(f);
Jason Samsa5597fc2009-07-08 18:01:53 -0700470 fclose(f);
Alex Sakhartchoukb825f672010-06-04 10:06:50 -0700471 fa3d->incUserRef();
Jason Samsa5597fc2009-07-08 18:01:53 -0700472 return fa3d;
473 }
474 delete fa3d;
475 return NULL;
476}
477
478
479}
480}