Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 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 | #include "rsContext.h" |
| 19 | |
| 20 | |
| 21 | #include <utils/String8.h> |
| 22 | #include "rsFileA3D.h" |
| 23 | |
| 24 | #include "rsMesh.h" |
| 25 | |
| 26 | using namespace android; |
| 27 | using namespace android::renderscript; |
| 28 | |
| 29 | |
| 30 | |
| 31 | FileA3D::FileA3D() |
| 32 | { |
| 33 | mRsc = NULL; |
| 34 | } |
| 35 | |
| 36 | FileA3D::~FileA3D() |
| 37 | { |
| 38 | } |
| 39 | |
| 40 | bool FileA3D::load(Context *rsc, FILE *f) |
| 41 | { |
| 42 | char magicString[12]; |
| 43 | size_t len; |
| 44 | |
| 45 | LOGE("file open 1"); |
| 46 | len = fread(magicString, 1, 12, f); |
| 47 | if ((len != 12) || |
| 48 | memcmp(magicString, "Android3D_ff", 12)) { |
| 49 | return false; |
| 50 | } |
| 51 | |
| 52 | LOGE("file open 2"); |
| 53 | len = fread(&mMajorVersion, 1, sizeof(mMajorVersion), f); |
| 54 | if (len != sizeof(mMajorVersion)) { |
| 55 | return false; |
| 56 | } |
| 57 | |
| 58 | LOGE("file open 3"); |
| 59 | len = fread(&mMinorVersion, 1, sizeof(mMinorVersion), f); |
| 60 | if (len != sizeof(mMinorVersion)) { |
| 61 | return false; |
| 62 | } |
| 63 | |
| 64 | LOGE("file open 4"); |
| 65 | uint32_t flags; |
| 66 | len = fread(&flags, 1, sizeof(flags), f); |
| 67 | if (len != sizeof(flags)) { |
| 68 | return false; |
| 69 | } |
| 70 | mUse64BitOffsets = (flags & 1) != 0; |
| 71 | |
| 72 | LOGE("file open 64bit = %i", mUse64BitOffsets); |
| 73 | |
| 74 | if (mUse64BitOffsets) { |
| 75 | len = fread(&mDataSize, 1, sizeof(mDataSize), f); |
| 76 | if (len != sizeof(mDataSize)) { |
| 77 | return false; |
| 78 | } |
| 79 | } else { |
| 80 | uint32_t tmp; |
| 81 | len = fread(&tmp, 1, sizeof(tmp), f); |
| 82 | if (len != sizeof(tmp)) { |
| 83 | return false; |
| 84 | } |
| 85 | mDataSize = tmp; |
| 86 | } |
| 87 | |
| 88 | LOGE("file open size = %lli", mDataSize); |
| 89 | |
| 90 | // We should know enough to read the file in at this point. |
| 91 | fseek(f, SEEK_SET, 0); |
| 92 | mAlloc= malloc(mDataSize); |
| 93 | if (!mAlloc) { |
| 94 | return false; |
| 95 | } |
| 96 | mData = (uint8_t *)mAlloc; |
| 97 | len = fread(mAlloc, 1, mDataSize, f); |
| 98 | if (len != mDataSize) { |
| 99 | return false; |
| 100 | } |
| 101 | |
| 102 | LOGE("file start processing"); |
| 103 | return process(rsc); |
| 104 | } |
| 105 | |
| 106 | bool FileA3D::processIndex(Context *rsc, A3DIndexEntry *ie) |
| 107 | { |
| 108 | bool ret = false; |
| 109 | IO io(mData + ie->mOffset, mUse64BitOffsets); |
| 110 | |
| 111 | LOGE("process index, type %i", ie->mType); |
| 112 | |
| 113 | switch(ie->mType) { |
| 114 | case CHUNK_ELEMENT: |
| 115 | processChunk_Element(rsc, &io, ie); |
| 116 | break; |
| 117 | case CHUNK_ELEMENT_SOURCE: |
| 118 | processChunk_ElementSource(rsc, &io, ie); |
| 119 | break; |
| 120 | case CHUNK_VERTICIES: |
| 121 | processChunk_Verticies(rsc, &io, ie); |
| 122 | break; |
| 123 | case CHUNK_MESH: |
| 124 | processChunk_Mesh(rsc, &io, ie); |
| 125 | break; |
| 126 | case CHUNK_PRIMITIVE: |
| 127 | processChunk_Primitive(rsc, &io, ie); |
| 128 | break; |
| 129 | default: |
| 130 | LOGE("FileA3D Unknown chunk type"); |
| 131 | break; |
| 132 | } |
| 133 | return (ie->mRsObj != NULL); |
| 134 | } |
| 135 | |
| 136 | bool FileA3D::process(Context *rsc) |
| 137 | { |
| 138 | LOGE("process"); |
| 139 | IO io(mData + 12, mUse64BitOffsets); |
| 140 | bool ret = true; |
| 141 | |
| 142 | // Build the index first |
| 143 | LOGE("process 1"); |
| 144 | io.loadU32(); // major version, already loaded |
| 145 | io.loadU32(); // minor version, already loaded |
| 146 | LOGE("process 2"); |
| 147 | |
| 148 | io.loadU32(); // flags |
| 149 | io.loadOffset(); // filesize, already loaded. |
| 150 | LOGE("process 4"); |
| 151 | uint64_t mIndexOffset = io.loadOffset(); |
| 152 | uint64_t mStringOffset = io.loadOffset(); |
| 153 | |
| 154 | LOGE("process mIndexOffset= 0x%016llx", mIndexOffset); |
| 155 | LOGE("process mStringOffset= 0x%016llx", mStringOffset); |
| 156 | |
| 157 | IO index(mData + mIndexOffset, mUse64BitOffsets); |
| 158 | IO stringTable(mData + mStringOffset, mUse64BitOffsets); |
| 159 | |
| 160 | uint32_t stringEntryCount = stringTable.loadU32(); |
| 161 | LOGE("stringEntryCount %i", stringEntryCount); |
| 162 | mStrings.setCapacity(stringEntryCount); |
| 163 | mStringIndexValues.setCapacity(stringEntryCount); |
| 164 | if (stringEntryCount) { |
| 165 | uint32_t stringType = stringTable.loadU32(); |
| 166 | LOGE("stringType %i", stringType); |
| 167 | rsAssert(stringType==0); |
| 168 | for (uint32_t ct = 0; ct < stringEntryCount; ct++) { |
| 169 | uint64_t offset = stringTable.loadOffset(); |
| 170 | LOGE("string offset 0x%016llx", offset); |
| 171 | IO tmp(mData + offset, mUse64BitOffsets); |
| 172 | String8 s; |
| 173 | tmp.loadString(&s); |
| 174 | LOGE("string %s", s.string()); |
| 175 | mStrings.push(s); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | LOGE("strings done"); |
| 180 | uint32_t indexEntryCount = index.loadU32(); |
| 181 | LOGE("index count %i", indexEntryCount); |
| 182 | mIndex.setCapacity(indexEntryCount); |
| 183 | for (uint32_t ct = 0; ct < indexEntryCount; ct++) { |
| 184 | A3DIndexEntry e; |
| 185 | uint32_t stringIndex = index.loadU32(); |
| 186 | LOGE("index %i", ct); |
| 187 | LOGE(" string index %i", stringIndex); |
| 188 | e.mType = (A3DChunkType)index.loadU32(); |
| 189 | LOGE(" type %i", e.mType); |
| 190 | e.mOffset = index.loadOffset(); |
| 191 | LOGE(" offset 0x%016llx", e.mOffset); |
| 192 | |
| 193 | if (stringIndex && (stringIndex < mStrings.size())) { |
| 194 | e.mID = mStrings[stringIndex]; |
| 195 | mStringIndexValues.editItemAt(stringIndex) = ct; |
| 196 | LOGE(" id %s", e.mID.string()); |
| 197 | } |
| 198 | |
| 199 | mIndex.push(e); |
| 200 | } |
| 201 | LOGE("index done"); |
| 202 | |
| 203 | // At this point the index should be fully populated. |
| 204 | // We can now walk though it and load all the objects. |
| 205 | for (uint32_t ct = 0; ct < indexEntryCount; ct++) { |
| 206 | LOGE("processing index entry %i", ct); |
| 207 | processIndex(rsc, &mIndex.editItemAt(ct)); |
| 208 | } |
| 209 | |
| 210 | return ret; |
| 211 | } |
| 212 | |
| 213 | |
| 214 | FileA3D::IO::IO(const uint8_t *buf, bool use64) |
| 215 | { |
| 216 | mData = buf; |
| 217 | mPos = 0; |
| 218 | mUse64 = use64; |
| 219 | } |
| 220 | |
| 221 | uint64_t FileA3D::IO::loadOffset() |
| 222 | { |
| 223 | uint64_t tmp; |
| 224 | if (mUse64) { |
| 225 | mPos = (mPos + 7) & (~7); |
| 226 | tmp = reinterpret_cast<const uint64_t *>(&mData[mPos])[0]; |
| 227 | mPos += sizeof(uint64_t); |
| 228 | return tmp; |
| 229 | } |
| 230 | return loadU32(); |
| 231 | } |
| 232 | |
| 233 | void FileA3D::IO::loadString(String8 *s) |
| 234 | { |
| 235 | LOGE("loadString"); |
| 236 | uint32_t len = loadU32(); |
| 237 | LOGE("loadString len %i", len); |
| 238 | s->setTo((const char *)&mData[mPos], len); |
| 239 | mPos += len; |
| 240 | } |
| 241 | |
| 242 | |
| 243 | void FileA3D::processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie) |
| 244 | { |
Jason Sams | e514b45 | 2009-09-25 14:51:22 -0700 | [diff] [blame] | 245 | Mesh * m = new Mesh(rsc); |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 246 | |
| 247 | m->mPrimitivesCount = io->loadU32(); |
| 248 | m->mPrimitives = new Mesh::Primitive_t *[m->mPrimitivesCount]; |
| 249 | |
| 250 | for (uint32_t ct = 0; ct < m->mPrimitivesCount; ct++) { |
| 251 | uint32_t index = io->loadU32(); |
| 252 | |
| 253 | m->mPrimitives[ct] = (Mesh::Primitive_t *)mIndex[index].mRsObj; |
| 254 | } |
| 255 | ie->mRsObj = m; |
| 256 | } |
| 257 | |
| 258 | void FileA3D::processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie) |
| 259 | { |
| 260 | Mesh::Primitive_t * p = new Mesh::Primitive_t; |
| 261 | |
| 262 | p->mIndexCount = io->loadU32(); |
| 263 | uint32_t vertIdx = io->loadU32(); |
Jason Sams | b80dfa7 | 2009-07-10 17:32:40 -0700 | [diff] [blame] | 264 | p->mRestartCounts = io->loadU16(); |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 265 | uint32_t bits = io->loadU8(); |
| 266 | p->mType = (RsPrimitive)io->loadU8(); |
| 267 | |
Jason Sams | b80dfa7 | 2009-07-10 17:32:40 -0700 | [diff] [blame] | 268 | LOGE("processChunk_Primitive count %i, bits %i", p->mIndexCount, bits); |
| 269 | |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 270 | p->mVerticies = (Mesh::Verticies_t *)mIndex[vertIdx].mRsObj; |
| 271 | |
| 272 | p->mIndicies = new uint16_t[p->mIndexCount]; |
| 273 | for (uint32_t ct = 0; ct < p->mIndexCount; ct++) { |
| 274 | switch(bits) { |
| 275 | case 8: |
| 276 | p->mIndicies[ct] = io->loadU8(); |
| 277 | break; |
| 278 | case 16: |
| 279 | p->mIndicies[ct] = io->loadU16(); |
| 280 | break; |
| 281 | case 32: |
| 282 | p->mIndicies[ct] = io->loadU32(); |
| 283 | break; |
| 284 | } |
Jason Sams | b80dfa7 | 2009-07-10 17:32:40 -0700 | [diff] [blame] | 285 | LOGE(" idx %i", p->mIndicies[ct]); |
| 286 | } |
| 287 | |
| 288 | if (p->mRestartCounts) { |
| 289 | p->mRestarts = new uint16_t[p->mRestartCounts]; |
| 290 | for (uint32_t ct = 0; ct < p->mRestartCounts; ct++) { |
| 291 | switch(bits) { |
| 292 | case 8: |
| 293 | p->mRestarts[ct] = io->loadU8(); |
| 294 | break; |
| 295 | case 16: |
| 296 | p->mRestarts[ct] = io->loadU16(); |
| 297 | break; |
| 298 | case 32: |
| 299 | p->mRestarts[ct] = io->loadU32(); |
| 300 | break; |
| 301 | } |
| 302 | LOGE(" idx %i", p->mRestarts[ct]); |
| 303 | } |
| 304 | } else { |
| 305 | p->mRestarts = NULL; |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 306 | } |
| 307 | |
| 308 | ie->mRsObj = p; |
| 309 | } |
| 310 | |
| 311 | void FileA3D::processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie) |
| 312 | { |
| 313 | Mesh::Verticies_t *cv = new Mesh::Verticies_t; |
| 314 | cv->mAllocationCount = io->loadU32(); |
| 315 | cv->mAllocations = new Allocation *[cv->mAllocationCount]; |
Jason Sams | b80dfa7 | 2009-07-10 17:32:40 -0700 | [diff] [blame] | 316 | LOGE("processChunk_Verticies count %i", cv->mAllocationCount); |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 317 | for (uint32_t ct = 0; ct < cv->mAllocationCount; ct++) { |
| 318 | uint32_t i = io->loadU32(); |
| 319 | cv->mAllocations[ct] = (Allocation *)mIndex[i].mRsObj; |
Jason Sams | b80dfa7 | 2009-07-10 17:32:40 -0700 | [diff] [blame] | 320 | LOGE(" idx %i", i); |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 321 | } |
| 322 | ie->mRsObj = cv; |
| 323 | } |
| 324 | |
| 325 | void FileA3D::processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie) |
| 326 | { |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 327 | rsi_ElementBegin(rsc); |
| 328 | |
| 329 | uint32_t count = io->loadU32(); |
| 330 | LOGE("processChunk_Element count %i", count); |
| 331 | while (count--) { |
| 332 | RsDataKind dk = (RsDataKind)io->loadU8(); |
| 333 | RsDataType dt = (RsDataType)io->loadU8(); |
| 334 | uint32_t bits = io->loadU8(); |
| 335 | bool isNorm = io->loadU8() != 0; |
| 336 | LOGE(" %i %i %i %i", dk, dt, bits, isNorm); |
Jason Sams | 8b2c065 | 2009-08-12 17:54:11 -0700 | [diff] [blame] | 337 | rsi_ElementAdd(rsc, dk, dt, isNorm, bits, 0); |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 338 | } |
| 339 | LOGE("processChunk_Element create"); |
| 340 | ie->mRsObj = rsi_ElementCreate(rsc); |
| 341 | } |
| 342 | |
| 343 | void FileA3D::processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie) |
| 344 | { |
| 345 | uint32_t index = io->loadU32(); |
| 346 | uint32_t count = io->loadU32(); |
| 347 | |
Jason Sams | b80dfa7 | 2009-07-10 17:32:40 -0700 | [diff] [blame] | 348 | LOGE("processChunk_ElementSource count %i, index %i", count, index); |
| 349 | |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 350 | RsElement e = (RsElement)mIndex[index].mRsObj; |
| 351 | |
| 352 | RsAllocation a = rsi_AllocationCreateSized(rsc, e, count); |
| 353 | Allocation * alloc = static_cast<Allocation *>(a); |
| 354 | |
| 355 | float * data = (float *)alloc->getPtr(); |
| 356 | while(count--) { |
| 357 | *data = io->loadF(); |
Jason Sams | b80dfa7 | 2009-07-10 17:32:40 -0700 | [diff] [blame] | 358 | LOGE(" %f", *data); |
Jason Sams | a5597fc | 2009-07-08 18:01:53 -0700 | [diff] [blame] | 359 | data++; |
| 360 | } |
| 361 | ie->mRsObj = alloc; |
| 362 | } |
| 363 | |
| 364 | namespace android { |
| 365 | namespace renderscript { |
| 366 | |
| 367 | |
| 368 | RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len) |
| 369 | { |
| 370 | FileA3D *fa3d = new FileA3D; |
| 371 | |
| 372 | FILE *f = fopen("/sdcard/test.a3d", "rb"); |
| 373 | if (f) { |
| 374 | fa3d->load(rsc, f); |
| 375 | fclose(f); |
| 376 | return fa3d; |
| 377 | } |
| 378 | delete fa3d; |
| 379 | return NULL; |
| 380 | } |
| 381 | |
| 382 | |
| 383 | } |
| 384 | } |