Ptex
PtexReader.cpp
Go to the documentation of this file.
1 /*
2 PTEX SOFTWARE
3 Copyright 2009 Disney Enterprises, Inc. All rights reserved
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9  * Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11 
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in
14  the documentation and/or other materials provided with the
15  distribution.
16 
17  * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
18  Studios" or the names of its contributors may NOT be used to
19  endorse or promote products derived from this software without
20  specific prior written permission from Walt Disney Pictures.
21 
22 Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
23 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
25 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
26 IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
31 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34 */
35 
36 #include "PtexPlatform.h"
37 #include <iostream>
38 #include <sstream>
39 #include <stdio.h>
40 
41 #include "Ptexture.h"
42 #include "PtexUtils.h"
43 #include "PtexReader.h"
44 
45 
46 PtexTexture* PtexTexture::open(const char* path, Ptex::String& error, bool premultiply)
47 {
48  // create a private cache and use it to open the file
49  PtexCache* cache = PtexCache::create(1, 1024*1024, premultiply);
50  PtexTexture* file = cache->get(path, error);
51 
52  // make reader own the cache (so it will delete it later)
53  // Note: we know that we have a PtexReader because it came from the cache
54  PtexReader* reader = static_cast<PtexReader*> (file);
55  if (reader) reader->setOwnsCache();
56 
57  // and purge cache so cache doesn't try to hold reader open
58  cache->purgeAll();
59  return file;
60 }
61 
62 
63 bool PtexReader::open(const char* path, Ptex::String& error)
64 {
65  if (!LittleEndian()) {
66  error = "Ptex library doesn't currently support big-endian cpu's";
67  return 0;
68  }
69  _path = path;
70  _fp = _io->open(path);
71  if (!_fp) {
72  std::string errstr = "Can't open ptex file: ";
73  errstr += path; errstr += "\n"; errstr += _io->lastError();
74  error = errstr.c_str();
75  return 0;
76  }
78  if (_header.magic != Magic) {
79  std::string errstr = "Not a ptex file: "; errstr += path;
80  error = errstr.c_str();
81  return 0;
82  }
83  if (_header.version != 1) {
84  std::stringstream s;
85  s << "Unsupported ptex file version ("<< _header.version << "): " << path;
86  error = s.str();
87  return 0;
88  }
90 
91  // read extended header
92  memset(&_extheader, 0, sizeof(_extheader));
94 
95  // compute offsets of various blocks
97  _faceinfopos = pos; pos += _header.faceinfosize;
98  _constdatapos = pos; pos += _header.constdatasize;
99  _levelinfopos = pos; pos += _header.levelinfosize;
100  _leveldatapos = pos; pos += _header.leveldatasize;
101  _metadatapos = pos; pos += _header.metadatazipsize;
102  pos += sizeof(uint64_t); // compatibility barrier
104  _lmddatapos = pos; pos += _extheader.lmddatasize;
105 
106  // edit data may not start immediately if additional sections have been added
107  // use value from extheader if present (and > pos)
109 
110  // read basic file info
111  readFaceInfo();
112  readConstData();
113  readLevelInfo();
114  readEditData();
115 
116  // an error occurred while reading the file
117  if (!_ok) {
118  error = _error.c_str();
119  return 0;
120  }
121 
122  return 1;
123 }
124 
125 
126 PtexReader::PtexReader(void** parent, PtexCacheImpl* cache, bool premultiply,
127  PtexInputHandler* io)
128  : PtexCachedFile(parent, cache),
129  _io(io ? io : &_defaultIo),
130  _premultiply(premultiply),
131  _ownsCache(false),
132  _ok(true),
133  _fp(0),
134  _pos(0),
135  _pixelsize(0),
136  _constdata(0),
137  _metadata(0),
138  _hasEdits(false)
139 {
140  memset(&_header, 0, sizeof(_header));
141  memset(&_zstream, 0, sizeof(_zstream));
142  inflateInit(&_zstream);
143 }
144 
145 
147 {
148  if (_fp) _io->close(_fp);
149 
150  // we can free the const data directly since we own it (it doesn't go through the cache)
151  if (_constdata) free(_constdata);
152 
153  // the rest must be orphaned since there may still be references outstanding
155  for (ReductionMap::iterator i = _reductions.begin(); i != _reductions.end(); i++) {
156  FaceData* f = (*i).second;
157  if (f) f->orphan();
158  }
159  if (_metadata) {
160  _metadata->orphan();
161  _metadata = 0;
162  }
163 
164  inflateEnd(&_zstream);
165 
167 }
168 
169 
171 {
172  PtexCacheImpl* cache = _cache;
173  {
174  // create local scope for cache lock
175  AutoLockCache lock(cache->cachelock);
176  unref();
177  }
178  // If this reader owns the cache, then releasing it may cause deletion of the
179  // reader and thus flag the cache for pending deletion. Call the cache
180  // to handle the pending deletion.
181  cache->handlePendingDelete();
182 }
183 
184 
186 {
187  if (faceid >= 0 && uint32_t(faceid) < _faceinfo.size())
188  return _faceinfo[faceid];
189 
190  static Ptex::FaceInfo dummy;
191  return dummy;
192 }
193 
194 
196 {
197  if (_faceinfo.empty()) {
198  // read compressed face info block
200  int nfaces = _header.nfaces;
201  _faceinfo.resize(nfaces);
203  (int)(sizeof(FaceInfo)*nfaces));
204 
205  // generate rfaceids
206  _rfaceids.resize(nfaces);
207  std::vector<uint32_t> faceids_r(nfaces);
208  PtexUtils::genRfaceids(&_faceinfo[0], nfaces,
209  &_rfaceids[0], &faceids_r[0]);
210 
211  // store face res values indexed by rfaceid
212  _res_r.resize(nfaces);
213  for (int i = 0; i < nfaces; i++)
214  _res_r[i] = _faceinfo[faceids_r[i]].res;
215  }
216 }
217 
218 
219 
221 {
222  if (_levelinfo.empty()) {
223  // read level info block
225  _levelinfo.resize(_header.nlevels);
227 
228  // initialize related data
229  _levels.resize(_header.nlevels);
230  _levelpos.resize(_header.nlevels);
231  FilePos pos = _leveldatapos;
232  for (int i = 0; i < _header.nlevels; i++) {
233  _levelpos[i] = pos;
234  pos += _levelinfo[i].leveldatasize;
235  }
236  }
237 }
238 
239 
241 {
242  if (!_constdata) {
243  // read compressed constant data block
245  int size = _pixelsize * _header.nfaces;
246  _constdata = (uint8_t*) malloc(size);
248  if (_premultiply && _header.hasAlpha())
251  }
252 }
253 
254 
256 {
257  AutoLockCache locker(_cache->cachelock);
258  if (_metadata) _metadata->ref();
259  else readMetaData();
260  return _metadata;
261 }
262 
263 
266 {
267  MetaMap::iterator iter = _map.find(key);
268  if (iter == _map.end()) {
269  // not found
270  return 0;
271  }
272 
273  Entry* e = &iter->second;
274  if (!e->isLmd) {
275  // normal (small) meta data - just return directly
276  return e;
277  }
278 
279  // large meta data - may not be read in yet
281  if (e->lmdData) {
282  // already in memory, add a ref
283  e->lmdData->ref();
284  _lmdRefs.push_back(e->lmdData);
285  return e;
286  }
287  else {
288  // not present, must read from file
289  // temporarily release cache lock so other threads can proceed
291 
292  // get read lock and make sure we still need to read
293  AutoMutex locker(_reader->readlock);
294  if (e->lmdData) {
295  // another thread must have read it while we were waiting
296  _cache->cachelock.lock();
297 
298  // make sure it's still there now that we have the lock
299  if (e->lmdData) {
300  e->data = e->lmdData->data();
301  _lmdRefs.push_back(e->lmdData);
302  e->lmdData->ref();
303  return e;
304  }
305  }
306  // go ahead and read, keep local until finished
307  LargeMetaData*& parent = e->lmdData;
308  LargeMetaData* volatile lmdData = new LargeMetaData((void**)&parent, _cache, e->datasize);
309  e->data = lmdData->data();
310  _reader->seek(e->lmdPos);
312  // reacquire cache lock and update entry
313  _cache->cachelock.lock();
314  e->lmdData = lmdData;
315  return e;
316  }
317 }
318 
319 
321 {
322  // temporarily release cache lock so other threads can proceed
324 
325  // get read lock and make sure we still need to read
326  AutoMutex locker(readlock);
327  if (_metadata) {
328  // another thread must have read it while we were waiting
329  _cache->cachelock.lock();
330  // make sure it's still there now that we have the lock
331  if (_metadata) {
332  _metadata->ref();
333  return;
334  }
336  }
337 
338 
339  // compute total size (including edit blocks) for cache tracking
340  int totalsize = _header.metadatamemsize;
341  for (size_t i = 0, size = _metaedits.size(); i < size; i++)
342  totalsize += _metaedits[i].memsize;
343 
344  // allocate new meta data (keep local until fully initialized)
345  MetaData* volatile newmeta = new MetaData(&_metadata, _cache, totalsize, this);
346 
347  // read primary meta data blocks
351 
352  // read large meta data headers
356 
357  // read meta data edits
358  for (size_t i = 0, size = _metaedits.size(); i < size; i++)
359  readMetaDataBlock(newmeta, _metaedits[i].pos,
360  _metaedits[i].zipsize, _metaedits[i].memsize);
361 
362  // store meta data
363  _cache->cachelock.lock();
364  _metadata = newmeta;
365 
366  // clean up unused data
367  _cache->purgeData();
368 }
369 
370 
371 void PtexReader::readMetaDataBlock(MetaData* metadata, FilePos pos, int zipsize, int memsize)
372 {
373  seek(pos);
374  // read from file
375  bool useMalloc = memsize > AllocaMax;
376  char* buff = useMalloc ? (char*) malloc(memsize) : (char*)alloca(memsize);
377 
378  if (readZipBlock(buff, zipsize, memsize)) {
379  // unpack data entries
380  char* ptr = buff;
381  char* end = ptr + memsize;
382  while (ptr < end) {
383  uint8_t keysize = *ptr++;
384  char* key = (char*)ptr; ptr += keysize;
385  key[keysize-1] = '\0';
386  uint8_t datatype = *ptr++;
387  uint32_t datasize; memcpy(&datasize, ptr, sizeof(datasize));
388  ptr += sizeof(datasize);
389  char* data = ptr; ptr += datasize;
390  metadata->addEntry((uint8_t)(keysize-1), key, datatype, datasize, data);
391  }
392  }
393  if (useMalloc) free(buff);
394 }
395 
396 
397 void PtexReader::readLargeMetaDataHeaders(MetaData* metadata, FilePos pos, int zipsize, int memsize)
398 {
399  seek(pos);
400  // read from file
401  bool useMalloc = memsize > AllocaMax;
402  char* buff = useMalloc ? (char*) malloc(memsize) : (char*)alloca(memsize);
403 
404  if (readZipBlock(buff, zipsize, memsize)) {
405  pos += zipsize;
406 
407  // unpack data entries
408  char* ptr = buff;
409  char* end = ptr + memsize;
410  while (ptr < end) {
411  uint8_t keysize = *ptr++;
412  char* key = (char*)ptr; ptr += keysize;
413  uint8_t datatype = *ptr++;
414  uint32_t datasize; memcpy(&datasize, ptr, sizeof(datasize));
415  ptr += sizeof(datasize);
416  uint32_t zipsize; memcpy(&zipsize, ptr, sizeof(zipsize));
417  ptr += sizeof(zipsize);
418  metadata->addLmdEntry((uint8_t)(keysize-1), key, datatype, datasize, pos, zipsize);
419  pos += zipsize;
420  }
421  }
422  if (useMalloc) free(buff);
423 }
424 
426 {
427  // determine file range to scan for edits
428  FilePos pos = FilePos(_editdatapos), endpos;
429  if (_extheader.editdatapos > 0) {
430  // newer files record the edit data position and size in the extheader
431  // note: position will be non-zero even if size is zero
432  endpos = FilePos(pos + _extheader.editdatasize);
433  }
434  else {
435  // must have an older file, just read until EOF
436  endpos = FilePos((uint64_t)-1);
437  }
438 
439  while (pos < endpos) {
440  seek(pos);
441  // read the edit data header
442  uint8_t edittype = et_editmetadata;
443  uint32_t editsize;
444  if (!readBlock(&edittype, sizeof(edittype), /*reporterror*/ false)) break;
445  if (!readBlock(&editsize, sizeof(editsize), /*reporterror*/ false)) break;
446  if (!editsize) break;
447  _hasEdits = true;
448  pos = tell() + editsize;
449  switch (edittype) {
450  case et_editfacedata: readEditFaceData(); break;
451  case et_editmetadata: readEditMetaData(); break;
452  }
453  }
454 }
455 
456 
458 {
459  // read header
460  EditFaceDataHeader efdh;
461  if (!readBlock(&efdh, EditFaceDataHeaderSize)) return;
462 
463  // update face info
464  int faceid = efdh.faceid;
465  if (faceid < 0 || size_t(faceid) >= _header.nfaces) return;
466  FaceInfo& f = _faceinfo[faceid];
467  f = efdh.faceinfo;
469 
470  // read const value now
471  uint8_t* constdata = _constdata + _pixelsize * faceid;
472  if (!readBlock(constdata, _pixelsize)) return;
473  if (_premultiply && _header.hasAlpha())
474  PtexUtils::multalpha(constdata, 1, _header.datatype,
476 
477  // update header info for remaining data
478  if (!f.isConstant()) {
479  _faceedits.push_back(FaceEdit());
480  FaceEdit& e = _faceedits.back();
481  e.pos = tell();
482  e.faceid = faceid;
483  e.fdh = efdh.fdh;
484  }
485 }
486 
487 
489 {
490  // read header
491  EditMetaDataHeader emdh;
492  if (!readBlock(&emdh, EditMetaDataHeaderSize)) return;
493 
494  // record header info for later
495  _metaedits.push_back(MetaEdit());
496  MetaEdit& e = _metaedits.back();
497  e.pos = tell();
498  e.zipsize = emdh.metadatazipsize;
499  e.memsize = emdh.metadatamemsize;
500 }
501 
502 
503 bool PtexReader::readBlock(void* data, int size, bool reporterror)
504 {
505  int result = (int)_io->read(data, size, _fp);
506  if (result == size) {
507  _pos += size;
508  STATS_INC(nblocksRead);
509  STATS_ADD(nbytesRead, size);
510  return 1;
511  }
512  if (reporterror)
513  setError("PtexReader error: read failed (EOF)");
514  return 0;
515 }
516 
517 
518 bool PtexReader::readZipBlock(void* data, int zipsize, int unzipsize)
519 {
520  void* buff = alloca(BlockSize);
521  _zstream.next_out = (Bytef*) data;
522  _zstream.avail_out = unzipsize;
523 
524  while (1) {
525  int size = (zipsize < BlockSize) ? zipsize : BlockSize;
526  zipsize -= size;
527  if (!readBlock(buff, size)) break;
528  _zstream.next_in = (Bytef*) buff;
529  _zstream.avail_in = size;
530  int zresult = inflate(&_zstream, zipsize ? Z_NO_FLUSH : Z_FINISH);
531  if (zresult == Z_STREAM_END) break;
532  if (zresult != Z_OK) {
533  setError("PtexReader error: unzip failed, file corrupt");
534  inflateReset(&_zstream);
535  return 0;
536  }
537  }
538 
539  int total = (int)_zstream.total_out;
540  inflateReset(&_zstream);
541  return total == unzipsize;
542 }
543 
544 
545 void PtexReader::readLevel(int levelid, Level*& level)
546 {
547  // temporarily release cache lock so other threads can proceed
549 
550  // get read lock and make sure we still need to read
551  AutoMutex locker(readlock);
552  if (level) {
553  // another thread must have read it while we were waiting
554  _cache->cachelock.lock();
555  // make sure it's still there now that we have the lock
556  if (level) {
557  level->ref();
558  return;
559  }
561  }
562 
563  // go ahead and read the level
564  LevelInfo& l = _levelinfo[levelid];
565 
566  // keep new level local until finished
567  Level* volatile newlevel = new Level((void**)&level, _cache, l.nfaces);
568  seek(_levelpos[levelid]);
570  computeOffsets(tell(), l.nfaces, &newlevel->fdh[0], &newlevel->offsets[0]);
571 
572  // apply edits (if any) to level 0
573  if (levelid == 0) {
574  for (size_t i = 0, size = _faceedits.size(); i < size; i++) {
575  FaceEdit& e = _faceedits[i];
576  newlevel->fdh[e.faceid] = e.fdh;
577  newlevel->offsets[e.faceid] = e.pos;
578  }
579  }
580 
581  // don't assign to result until level data is fully initialized
582  _cache->cachelock.lock();
583  level = newlevel;
584 
585  // clean up unused data
586  _cache->purgeData();
587 }
588 
589 
590 void PtexReader::readFace(int levelid, Level* level, int faceid)
591 {
592  // temporarily release cache lock so other threads can proceed
594 
595  // get read lock and make sure we still need to read
596  FaceData*& face = level->faces[faceid];
597  AutoMutex locker(readlock);
598 
599  if (face) {
600  // another thread must have read it while we were waiting
601  _cache->cachelock.lock();
602  // make sure it's still there now that we have the lock
603  if (face) {
604  face->ref();
605  return;
606  }
608  }
609 
610  // Go ahead and read the face, and read nearby faces if
611  // possible. The goal is to coalesce small faces into single
612  // runs of consecutive reads to minimize seeking and take
613  // advantage of read-ahead buffering.
614 
615  // Try to read as many faces as will fit in BlockSize. Use the
616  // in-memory size rather than the on-disk size to prevent flooding
617  // the memory cache. And don't coalesce w/ tiled faces as these
618  // are meant to be read individually.
619 
620  // scan both backwards and forwards looking for unread faces
621  int first = faceid, last = faceid;
622  int totalsize = 0;
623 
624  FaceDataHeader fdh = level->fdh[faceid];
625  if (fdh.encoding() != enc_tiled) {
626  totalsize += unpackedSize(fdh, levelid, faceid);
627 
628  int nfaces = int(level->fdh.size());
629  while (1) {
630  int f = first-1;
631  if (f < 0 || level->faces[f]) break;
632  fdh = level->fdh[f];
633  if (fdh.encoding() == enc_tiled) break;
634  int size = totalsize + unpackedSize(fdh, levelid, f);
635  if (size > BlockSize) break;
636  first = f;
637  totalsize = size;
638  }
639  while (1) {
640  int f = last+1;
641  if (f >= nfaces || level->faces[f]) break;
642  fdh = level->fdh[f];
643  if (fdh.encoding() == enc_tiled) break;
644  int size = totalsize + unpackedSize(fdh, levelid, f);
645  if (size > BlockSize) break;
646  last = f;
647  totalsize = size;
648  }
649  }
650 
651  // read all faces in range
652  // keep track of extra faces we read so we can add them to the cache later
653  std::vector<FaceData*> extraFaces;
654  extraFaces.reserve(last-first);
655 
656  for (int i = first; i <= last; i++) {
657  fdh = level->fdh[i];
658  // skip faces with zero size (which is true for level-0 constant faces)
659  if (fdh.blocksize()) {
660  FaceData*& face = level->faces[i];
661  readFaceData(level->offsets[i], fdh, getRes(levelid, i), levelid, face);
662  if (i != faceid) extraFaces.push_back(face);
663  }
664  }
665 
666  // reacquire cache lock, then unref extra faces to add them to the cache
667  _cache->cachelock.lock();
668  for (size_t i = 0, size = extraFaces.size(); i < size; i++)
669  extraFaces[i]->unref();
670 }
671 
672 
674 {
675  // temporarily release cache lock so other threads can proceed
677 
678  // get read lock and make sure we still need to read
679  AutoMutex locker(_reader->readlock);
680  if (data) {
681  // another thread must have read it while we were waiting
682  _cache->cachelock.lock();
683  // make sure it's still there now that we have the lock
684  if (data) {
685  data->ref();
686  return;
687  }
689  }
690 
691  // go ahead and read the face data
692  _reader->readFaceData(_offsets[tile], _fdh[tile], _tileres, _levelid, data);
693  _cache->cachelock.lock();
694 
695  // clean up unused data
696  _cache->purgeData();
697 }
698 
699 
700 void PtexReader::readFaceData(FilePos pos, FaceDataHeader fdh, Res res, int levelid,
701  FaceData*& face)
702 {
703  // keep new face local until fully initialized
704  FaceData* volatile newface = 0;
705 
706  seek(pos);
707  switch (fdh.encoding()) {
708  case enc_constant:
709  {
710  ConstantFace* pf = new ConstantFace((void**)&face, _cache, _pixelsize);
711  readBlock(pf->data(), _pixelsize);
712  if (levelid==0 && _premultiply && _header.hasAlpha())
715  newface = pf;
716  }
717  break;
718  case enc_tiled:
719  {
720  Res tileres;
721  readBlock(&tileres, sizeof(tileres));
722  uint32_t tileheadersize;
723  readBlock(&tileheadersize, sizeof(tileheadersize));
724  TiledFace* tf = new TiledFace((void**)&face, _cache, res, tileres, levelid, this);
725  readZipBlock(&tf->_fdh[0], tileheadersize, FaceDataHeaderSize * tf->_ntiles);
726  computeOffsets(tell(), tf->_ntiles, &tf->_fdh[0], &tf->_offsets[0]);
727  newface = tf;
728  }
729  break;
730  case enc_zipped:
731  case enc_diffzipped:
732  {
733  int uw = res.u(), vw = res.v();
734  int npixels = uw * vw;
735  int unpackedSize = _pixelsize * npixels;
736  PackedFace* pf = new PackedFace((void**)&face, _cache,
737  res, _pixelsize, unpackedSize);
738  bool useMalloc = unpackedSize > AllocaMax;
739  void* tmp = useMalloc ? malloc(unpackedSize) : alloca(unpackedSize);
740  readZipBlock(tmp, fdh.blocksize(), unpackedSize);
741  if (fdh.encoding() == enc_diffzipped)
742  PtexUtils::decodeDifference(tmp, unpackedSize, _header.datatype);
743  PtexUtils::interleave(tmp, uw * DataSize(_header.datatype), uw, vw,
744  pf->data(), uw * _pixelsize,
746  if (levelid==0 && _premultiply && _header.hasAlpha())
747  PtexUtils::multalpha(pf->data(), npixels, _header.datatype,
749  newface = pf;
750  if (useMalloc) free(tmp);
751  }
752  break;
753  }
754 
755  face = newface;
756 }
757 
758 
759 void PtexReader::getData(int faceid, void* buffer, int stride)
760 {
761  if (!_ok) return;
762  FaceInfo& f = _faceinfo[faceid];
763  getData(faceid, buffer, stride, f.res);
764 }
765 
766 
767 void PtexReader::getData(int faceid, void* buffer, int stride, Res res)
768 {
769  if (!_ok) return;
770 
771  // note - all locking is handled in called getData methods
772  int resu = res.u(), resv = res.v();
773  int rowlen = _pixelsize * resu;
774  if (stride == 0) stride = rowlen;
775 
776  PtexPtr<PtexFaceData> d ( getData(faceid, res) );
777  if (!d) return;
778  if (d->isConstant()) {
779  // fill dest buffer with pixel value
780  PtexUtils::fill(d->getData(), buffer, stride,
781  resu, resv, _pixelsize);
782  }
783  else if (d->isTiled()) {
784  // loop over tiles
785  Res tileres = d->tileRes();
786  int ntilesu = res.ntilesu(tileres);
787  int ntilesv = res.ntilesv(tileres);
788  int tileures = tileres.u();
789  int tilevres = tileres.v();
790  int tilerowlen = _pixelsize * tileures;
791  int tile = 0;
792  char* dsttilerow = (char*) buffer;
793  for (int i = 0; i < ntilesv; i++) {
794  char* dsttile = dsttilerow;
795  for (int j = 0; j < ntilesu; j++) {
796  PtexPtr<PtexFaceData> t ( d->getTile(tile++) );
797  if (!t) { i = ntilesv; break; }
798  if (t->isConstant())
799  PtexUtils::fill(t->getData(), dsttile, stride,
800  tileures, tilevres, _pixelsize);
801  else
802  PtexUtils::copy(t->getData(), tilerowlen, dsttile, stride,
803  tilevres, tilerowlen);
804  dsttile += tilerowlen;
805  }
806  dsttilerow += stride * tilevres;
807  }
808  }
809  else {
810  PtexUtils::copy(d->getData(), rowlen, buffer, stride, resv, rowlen);
811  }
812 }
813 
814 
816 {
817  if (faceid < 0 || size_t(faceid) >= _header.nfaces) return 0;
818  if (!_ok) return 0;
819 
820  FaceInfo& fi = _faceinfo[faceid];
821  if (fi.isConstant() || fi.res == 0) {
822  return new ConstDataPtr(getConstData() + faceid * _pixelsize, _pixelsize);
823  }
824 
825  // get level zero (full) res face
826  AutoLockCache locker(_cache->cachelock);
827  Level* level = getLevel(0);
828  FaceData* face = getFace(0, level, faceid);
829  level->unref();
830  return face;
831 }
832 
833 
835 {
836  if (!_ok) return 0;
837  if (faceid < 0 || size_t(faceid) >= _header.nfaces) return 0;
838 
839  FaceInfo& fi = _faceinfo[faceid];
840  if ((fi.isConstant() && res >= 0) || res == 0) {
841  return new ConstDataPtr(getConstData() + faceid * _pixelsize, _pixelsize);
842  }
843 
844  // lock cache (can't autolock since we might need to unlock early)
845  _cache->cachelock.lock();
846 
847 
848  // determine how many reduction levels are needed
849  int redu = fi.res.ulog2 - res.ulog2, redv = fi.res.vlog2 - res.vlog2;
850 
851  if (redu == 0 && redv == 0) {
852  // no reduction - get level zero (full) res face
853  Level* level = getLevel(0);
854  FaceData* face = getFace(0, level, faceid);
855  level->unref();
857  return face;
858  }
859 
860  if (redu == redv && !fi.hasEdits() && res >= 0) {
861  // reduction is symmetric and non-negative
862  // and face has no edits => access data from reduction level (if present)
863  int levelid = redu;
864  if (size_t(levelid) < _levels.size()) {
865  Level* level = getLevel(levelid);
866 
867  // get reduction face id
868  int rfaceid = _rfaceids[faceid];
869 
870  // get the face data (if present)
871  FaceData* face = 0;
872  if (size_t(rfaceid) < level->faces.size())
873  face = getFace(levelid, level, rfaceid);
874  level->unref();
875  if (face) {
877  return face;
878  }
879  }
880  }
881 
882  // dynamic reduction required - look in dynamic reduction cache
883  FaceData*& face = _reductions[ReductionKey(faceid, res)];
884  if (face) {
885  face->ref();
887  return face;
888  }
889 
890  // not found, generate new reduction
891  // unlock cache - getData and reduce will handle their own locking
893 
894  if (res.ulog2 < 0 || res.vlog2 < 0) {
895  std::cerr << "PtexReader::getData - reductions below 1 pixel not supported" << std::endl;
896  return 0;
897  }
898  if (redu < 0 || redv < 0) {
899  std::cerr << "PtexReader::getData - enlargements not supported" << std::endl;
900  return 0;
901  }
903  {
904  if (redu != redv) {
905  std::cerr << "PtexReader::getData - anisotropic reductions not supported for triangle mesh" << std::endl;
906  return 0;
907  }
908  PtexPtr<PtexFaceData> psrc ( getData(faceid, Res((int8_t)(res.ulog2+1), (int8_t)(res.vlog2+1))) );
909  FaceData* src = static_cast<FaceData*>(psrc.get());
910  assert(src);
911  if (src) src->reduce(face, this, res, PtexUtils::reduceTri);
912  return face;
913  }
914 
915  // determine which direction to blend
916  bool blendu;
917  if (redu == redv) {
918  // for symmetric face blends, alternate u and v blending
919  blendu = (res.ulog2 & 1);
920  }
921  else blendu = redu > redv;
922 
923  if (blendu) {
924  // get next-higher u-res and reduce in u
925  PtexPtr<PtexFaceData> psrc ( getData(faceid, Res((int8_t)(res.ulog2+1), (int8_t)res.vlog2)) );
926  FaceData* src = static_cast<FaceData*>(psrc.get());
927  assert(src);
928  if (src) src->reduce(face, this, res, PtexUtils::reduceu);
929  }
930  else {
931  // get next-higher v-res and reduce in v
932  PtexPtr<PtexFaceData> psrc ( getData(faceid, Res((int8_t)res.ulog2, (int8_t)(res.vlog2+1))) );
933  FaceData* src = static_cast<FaceData*>(psrc.get());
934  assert(src);
935  if (src) src->reduce(face, this, res, PtexUtils::reducev);
936  }
937 
938  return face;
939 }
940 
941 
942 void PtexReader::blendFaces(FaceData*& face, int faceid, Res res, bool blendu)
943 {
944  Res pres; // parent res, 1 higher in blend direction
945  int length; // length of blend edge (1xN or Nx1)
946  int e1, e2; // neighboring edge ids
947  if (blendu) {
948  assert(res.ulog2 < 0); // res >= 0 requires reduction, not blending
949  length = (res.vlog2 <= 0 ? 1 : res.v());
950  e1 = e_bottom; e2 = e_top;
951  pres = Res((int8_t)(res.ulog2+1), (int8_t)res.vlog2);
952  }
953  else {
954  assert(res.vlog2 < 0);
955  length = (res.ulog2 <= 0 ? 1 : res.u());
956  e1 = e_right; e2 = e_left;
957  pres = Res((int8_t)res.ulog2, (int8_t)(res.vlog2+1));
958  }
959 
960  // get neighbor face ids
961  FaceInfo& f = _faceinfo[faceid];
962  int nf1 = f.adjfaces[e1], nf2 = f.adjfaces[e2];
963 
964  // compute rotation of faces relative to current
965  int r1 = (f.adjedge(e1)-e1+2)&3;
966  int r2 = (f.adjedge(e2)-e2+2)&3;
967 
968  // swap u and v res for faces rotated +/- 90 degrees
969  Res pres1 = pres, pres2 = pres;
970  if (r1 & 1) pres1.swapuv();
971  if (r2 & 1) pres2.swapuv();
972 
973  // ignore faces that have insufficient res (unlikely, but possible)
974  if (nf1 >= 0 && !(_faceinfo[nf1].res >= pres)) nf1 = -1;
975  if (nf2 >= 0 && !(_faceinfo[nf2].res >= pres)) nf2 = -1;
976 
977  // get parent face data
978  int nf = 1; // number of faces to blend (1 to 3)
979  bool flip[3]; // true if long dimension needs to be flipped
980  PtexFaceData* psrc[3]; // the face data
981  psrc[0] = getData(faceid, pres);
982  flip[0] = 0; // don't flip main face
983  if (nf1 >= 0) {
984  // face must be flipped if rot is 1 or 2 for blendu, or 2 or 3 for blendv
985  // thus, just add the blendu bool val to align the ranges and check bit 1
986  // also, no need to flip if length is zero
987  flip[nf] = length ? (r1 + blendu) & 1 : 0;
988  psrc[nf++] = getData(nf1, pres1);
989  }
990  if (nf2 >= 0) {
991  flip[nf] = length ? (r2 + blendu) & 1 : 0;
992  psrc[nf++] = getData(nf2, pres2);
993  }
994 
995  // get reduce lock and make sure we still need to reduce
996  AutoMutex rlocker(reducelock);
997  if (face) {
998  // another thread must have generated it while we were waiting
999  AutoLockCache locker(_cache->cachelock);
1000  // make sure it's still there now that we have the lock
1001  if (face) {
1002  face->ref();
1003  // release parent data
1004  for (int i = 0; i < nf; i++) psrc[i]->release();
1005  return;
1006  }
1007  }
1008 
1009  // allocate a new face data (1 x N or N x 1)
1010  DataType dt = datatype();
1011  int nchan = nchannels();
1012  int size = _pixelsize * length;
1013  PackedFace* pf = new PackedFace((void**)&face, _cache, res,
1014  _pixelsize, size);
1015  void* data = pf->getData();
1016  if (nf == 1) {
1017  // no neighbors - just copy face
1018  memcpy(data, psrc[0]->getData(), size);
1019  }
1020  else {
1021  float weight = 1.0f / (float)nf;
1022  memset(data, 0, size);
1023  for (int i = 0; i < nf; i++)
1024  PtexUtils::blend(psrc[i]->getData(), weight, data, flip[i],
1025  length, dt, nchan);
1026  }
1027 
1028  {
1029  AutoLockCache clocker(_cache->cachelock);
1030  face = pf;
1031 
1032  // clean up unused data
1033  _cache->purgeData();
1034  }
1035 
1036  // release parent data
1037  for (int i = 0; i < nf; i++) psrc[i]->release();
1038 }
1039 
1040 
1041 void PtexReader::getPixel(int faceid, int u, int v,
1042  float* result, int firstchan, int nchannels)
1043 {
1044  memset(result, 0, sizeof(*result)*nchannels);
1045 
1046  // clip nchannels against actual number available
1047  nchannels = PtexUtils::min(nchannels,
1048  _header.nchannels-firstchan);
1049  if (nchannels <= 0) return;
1050 
1051  // get raw pixel data
1052  PtexPtr<PtexFaceData> data ( getData(faceid) );
1053  if (!data) return;
1054  void* pixel = alloca(_pixelsize);
1055  data->getPixel(u, v, pixel);
1056 
1057  // adjust for firstchan offset
1058  int datasize = DataSize(_header.datatype);
1059  if (firstchan)
1060  pixel = (char*) pixel + datasize * firstchan;
1061 
1062  // convert/copy to result as needed
1063  if (_header.datatype == dt_float)
1064  memcpy(result, pixel, datasize * nchannels);
1065  else
1066  ConvertToFloat(result, pixel, _header.datatype, nchannels);
1067 }
1068 
1069 
1070 void PtexReader::getPixel(int faceid, int u, int v,
1071  float* result, int firstchan, int nchannels,
1072  Ptex::Res res)
1073 {
1074  memset(result, 0, nchannels);
1075 
1076  // clip nchannels against actual number available
1077  nchannels = PtexUtils::min(nchannels,
1078  _header.nchannels-firstchan);
1079  if (nchannels <= 0) return;
1080 
1081  // get raw pixel data
1082  PtexPtr<PtexFaceData> data ( getData(faceid, res) );
1083  if (!data) return;
1084  void* pixel = alloca(_pixelsize);
1085  data->getPixel(u, v, pixel);
1086 
1087  // adjust for firstchan offset
1088  int datasize = DataSize(_header.datatype);
1089  if (firstchan)
1090  pixel = (char*) pixel + datasize * firstchan;
1091 
1092  // convert/copy to result as needed
1093  if (_header.datatype == dt_float)
1094  memcpy(result, pixel, datasize * nchannels);
1095  else
1096  ConvertToFloat(result, pixel, _header.datatype, nchannels);
1097 }
1098 
1099 
1101  Res newres, PtexUtils::ReduceFn reducefn)
1102 {
1103  // get reduce lock and make sure we still need to reduce
1104  AutoMutex rlocker(r->reducelock);
1105  if (face) {
1106  // another thread must have generated it while we were waiting
1107  AutoLockCache clocker(_cache->cachelock);
1108  // make sure it's still there now that we have the lock
1109  if (face) {
1110  face->ref();
1111  return;
1112  }
1113  }
1114 
1115  // allocate a new face and reduce image
1116  DataType dt = r->datatype();
1117  int nchan = r->nchannels();
1118  PackedFace* pf = new PackedFace((void**)&face, _cache, newres,
1119  _pixelsize, _pixelsize * newres.size());
1120  // reduce and copy into new face
1121  reducefn(_data, _pixelsize * _res.u(), _res.u(), _res.v(),
1122  pf->_data, _pixelsize * newres.u(), dt, nchan);
1123  AutoLockCache clocker(_cache->cachelock);
1124  face = pf;
1125 
1126  // clean up unused data
1127  _cache->purgeData();
1128 }
1129 
1130 
1131 
1134 {
1135  // get cache lock (just to protect the ref count)
1136  AutoLockCache locker(_cache->cachelock);
1137 
1138  // must make a new constant face (even though it's identical to this one)
1139  // because it will be owned by a different reduction level
1140  // and will therefore have a different parent
1141  ConstantFace* pf = new ConstantFace((void**)&face, _cache, _pixelsize);
1142  memcpy(pf->_data, _data, _pixelsize);
1143  face = pf;
1144 }
1145 
1146 
1148  Res newres, PtexUtils::ReduceFn reducefn)
1149 {
1150  // get reduce lock and make sure we still need to reduce
1151  AutoMutex rlocker(r->reducelock);
1152  if (face) {
1153  // another thread must have generated it while we were waiting
1154  AutoLockCache clocker(_cache->cachelock);
1155  // make sure it's still there now that we have the lock
1156  if (face) {
1157  face->ref();
1158  return;
1159  }
1160  }
1161 
1162  /* Tiled reductions should generally only be anisotropic (just u
1163  or v, not both) since isotropic reductions are precomputed and
1164  stored on disk. (This function should still work for isotropic
1165  reductions though.)
1166 
1167  In the anisotropic case, the number of tiles should be kept the
1168  same along the direction not being reduced in order to preserve
1169  the laziness of the file access. In contrast, if reductions
1170  were not tiled, then any reduction would read all the tiles and
1171  defeat the purpose of tiling.
1172  */
1173 
1174  // keep new face local until fully initialized
1175  FaceData* volatile newface = 0;
1176 
1177  // don't tile if either dimension is 1 (rare, would complicate blendFaces too much)
1178  // also, don't tile triangle reductions (too complicated)
1179  Res newtileres;
1180  bool isTriangle = r->_header.meshtype == mt_triangle;
1181  if (newres.ulog2 == 1 || newres.vlog2 == 1 || isTriangle) {
1182  newtileres = newres;
1183  }
1184  else {
1185  // propagate the tile res to the reduction
1186  newtileres = _tileres;
1187  // but make sure tile isn't larger than the new face!
1188  if (newtileres.ulog2 > newres.ulog2) newtileres.ulog2 = newres.ulog2;
1189  if (newtileres.vlog2 > newres.vlog2) newtileres.vlog2 = newres.vlog2;
1190  }
1191 
1192 
1193  // determine how many tiles we will have on the reduction
1194  int newntiles = newres.ntiles(newtileres);
1195 
1196  if (newntiles == 1) {
1197  // no need to keep tiling, reduce tiles into a single face
1198  // first, get all tiles and check if they are constant (with the same value)
1199  PtexFaceData** tiles = (PtexFaceData**) alloca(_ntiles * sizeof(PtexFaceData*));
1200  bool allConstant = true;
1201  for (int i = 0; i < _ntiles; i++) {
1202  PtexFaceData* tile = tiles[i] = getTile(i);
1203  allConstant = (allConstant && tile->isConstant() &&
1204  (i == 0 || (0 == memcmp(tiles[0]->getData(), tile->getData(),
1205  _pixelsize))));
1206  }
1207  if (allConstant) {
1208  // allocate a new constant face
1209  newface = new ConstantFace((void**)&face, _cache, _pixelsize);
1210  memcpy(newface->getData(), tiles[0]->getData(), _pixelsize);
1211  }
1212  else if (isTriangle) {
1213  // reassemble all tiles into temporary contiguous image
1214  // (triangle reduction doesn't work on tiles)
1215  int tileures = _tileres.u();
1216  int tilevres = _tileres.v();
1217  int sstride = _pixelsize * tileures;
1218  int dstride = sstride * _ntilesu;
1219  int dstepv = dstride * tilevres - sstride*(_ntilesu-1);
1220 
1221  char* tmp = (char*) malloc(_ntiles * _tileres.size() * _pixelsize);
1222  char* tmpptr = tmp;
1223  for (int i = 0; i < _ntiles;) {
1224  PtexFaceData* tile = tiles[i];
1225  if (tile->isConstant())
1226  PtexUtils::fill(tile->getData(), tmpptr, dstride,
1227  tileures, tilevres, _pixelsize);
1228  else
1229  PtexUtils::copy(tile->getData(), sstride, tmpptr, dstride, tilevres, sstride);
1230  i++;
1231  tmpptr += i%_ntilesu ? sstride : dstepv;
1232  }
1233 
1234  // allocate a new packed face
1235  newface = new PackedFace((void**)&face, _cache, newres,
1236  _pixelsize, _pixelsize * newres.size());
1237  // reduce and copy into new face
1238  reducefn(tmp, _pixelsize * _res.u(), _res.u(), _res.v(),
1239  newface->getData(), _pixelsize * newres.u(), _dt, _nchan);
1240 
1241  free(tmp);
1242  }
1243  else {
1244  // allocate a new packed face
1245  newface = new PackedFace((void**)&face, _cache, newres,
1246  _pixelsize, _pixelsize*newres.size());
1247 
1248  int tileures = _tileres.u();
1249  int tilevres = _tileres.v();
1250  int sstride = _pixelsize * tileures;
1251  int dstride = _pixelsize * newres.u();
1252  int dstepu = dstride/_ntilesu;
1253  int dstepv = dstride*newres.v()/_ntilesv - dstepu*(_ntilesu-1);
1254 
1255  char* dst = (char*) newface->getData();
1256  for (int i = 0; i < _ntiles;) {
1257  PtexFaceData* tile = tiles[i];
1258  if (tile->isConstant())
1259  PtexUtils::fill(tile->getData(), dst, dstride,
1260  newres.u()/_ntilesu, newres.v()/_ntilesv,
1261  _pixelsize);
1262  else
1263  reducefn(tile->getData(), sstride, tileures, tilevres,
1264  dst, dstride, _dt, _nchan);
1265  i++;
1266  dst += i%_ntilesu ? dstepu : dstepv;
1267  }
1268  }
1269  // release the tiles
1270  for (int i = 0; i < _ntiles; i++) tiles[i]->release();
1271  }
1272  else {
1273  // otherwise, tile the reduced face
1274  newface = new TiledReducedFace((void**)&face, _cache, newres, newtileres,
1275  _dt, _nchan, this, reducefn);
1276  }
1277  AutoLockCache clocker(_cache->cachelock);
1278  face = newface;
1279 
1280  // clean up unused data
1281  _cache->purgeData();
1282 }
1283 
1284 
1285 void PtexReader::TiledFaceBase::getPixel(int ui, int vi, void* result)
1286 {
1287  int tileu = ui >> _tileres.ulog2;
1288  int tilev = vi >> _tileres.vlog2;
1289  PtexPtr<PtexFaceData> tile ( getTile(tilev * _ntilesu + tileu) );
1290  tile->getPixel(ui - (tileu<<_tileres.ulog2),
1291  vi - (tilev<<_tileres.vlog2), result);
1292 }
1293 
1294 
1295 
1297 {
1298  _cache->cachelock.lock();
1299  FaceData*& face = _tiles[tile];
1300  if (face) {
1301  face->ref();
1302  _cache->cachelock.unlock();
1303  return face;
1304  }
1305 
1306  // first, get all parent tiles for this tile
1307  // and check if they are constant (with the same value)
1308  int pntilesu = _parentface->ntilesu();
1309  int pntilesv = _parentface->ntilesv();
1310  int nu = pntilesu / _ntilesu; // num parent tiles for this tile in u dir
1311  int nv = pntilesv / _ntilesv; // num parent tiles for this tile in v dir
1312 
1313  int ntiles = nu*nv; // num parent tiles for this tile
1314  PtexFaceData** tiles = (PtexFaceData**) alloca(ntiles * sizeof(PtexFaceData*));
1315  bool allConstant = true;
1316  int ptile = (tile/_ntilesu) * nv * pntilesu + (tile%_ntilesu) * nu;
1317  for (int i = 0; i < ntiles;) {
1318  // temporarily release cache lock while we get parent tile
1319  _cache->cachelock.unlock();
1320  PtexFaceData* tile = tiles[i] = _parentface->getTile(ptile);
1321  _cache->cachelock.lock();
1322  allConstant = (allConstant && tile->isConstant() &&
1323  (i==0 || (0 == memcmp(tiles[0]->getData(), tile->getData(),
1324  _pixelsize))));
1325  i++;
1326  ptile += i%nu? 1 : pntilesu - nu + 1;
1327  }
1328 
1329  // make sure another thread didn't make the tile while we were checking
1330  if (face) {
1331  face->ref();
1332  _cache->cachelock.unlock();
1333  // release the tiles
1334  for (int i = 0; i < ntiles; i++) tiles[i]->release();
1335  return face;
1336  }
1337 
1338  if (allConstant) {
1339  // allocate a new constant face
1340  face = new ConstantFace((void**)&face, _cache, _pixelsize);
1341  memcpy(face->getData(), tiles[0]->getData(), _pixelsize);
1342  }
1343  else {
1344  // allocate a new packed face for the tile
1345  face = new PackedFace((void**)&face, _cache, _tileres,
1346  _pixelsize, _pixelsize*_tileres.size());
1347 
1348  // generate reduction from parent tiles
1349  int ptileures = _parentface->tileres().u();
1350  int ptilevres = _parentface->tileres().v();
1351  int sstride = ptileures * _pixelsize;
1352  int dstride = _tileres.u() * _pixelsize;
1353  int dstepu = dstride/nu;
1354  int dstepv = dstride*_tileres.v()/nv - dstepu*(nu-1);
1355 
1356  char* dst = (char*) face->getData();
1357  for (int i = 0; i < ntiles;) {
1358  PtexFaceData* tile = tiles[i];
1359  if (tile->isConstant())
1360  PtexUtils::fill(tile->getData(), dst, dstride,
1361  _tileres.u()/nu, _tileres.v()/nv,
1362  _pixelsize);
1363  else
1364  _reducefn(tile->getData(), sstride, ptileures, ptilevres,
1365  dst, dstride, _dt, _nchan);
1366  i++;
1367  dst += i%nu ? dstepu : dstepv;
1368  }
1369  }
1370 
1371  _cache->cachelock.unlock();
1372 
1373  // release the tiles
1374  for (int i = 0; i < ntiles; i++) tiles[i]->release();
1375  return face;
1376 }
void handlePendingDelete()
Definition: PtexCache.h:220
FaceData * getFace(int levelid, Level *level, int faceid)
Definition: PtexReader.h:497
Left edge, from UV (0,1) to (0,0)
Definition: Ptexture.h:103
bool _ownsCache
Definition: PtexReader.h:574
ExtHeader _extheader
Definition: PtexReader.h:581
MeshType meshtype
Definition: PtexIO.h:45
virtual void reduce(FaceData *&, PtexReader *, Res newres, PtexUtils::ReduceFn)=0
uint64_t editdatapos
Definition: PtexIO.h:69
void setOwnsCache()
Definition: PtexReader.h:78
uint32_t nfaces
Definition: PtexIO.h:50
int ntiles(Res tileres) const
Determine the total number of tiles for the given tile res.
Definition: Ptexture.h:220
int ntilesv(Res tileres) const
Determine the number of tiles in the v direction for the given tile res.
Definition: Ptexture.h:217
uint32_t levelinfosize
Definition: PtexIO.h:54
std::string _error
Definition: PtexReader.h:576
safevector< LevelInfo > _levelinfo
Definition: PtexReader.h:598
static void multalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Definition: PtexUtils.cpp:562
std::vector< LargeMetaData * > _lmdRefs
Definition: PtexReader.h:266
Mutex reducelock
Definition: PtexReader.h:466
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition: PtexReader.cpp:170
PtexReader(void **parent, PtexCacheImpl *cache, bool premultiply, PtexInputHandler *handler)
Definition: PtexReader.cpp:126
PtexInputHandler * _io
Definition: PtexReader.h:572
bool isConstant() const
Determine if face is constant (by checking a flag).
Definition: Ptexture.h:270
uint16_t nlevels
Definition: PtexIO.h:49
void readFaceInfo()
Definition: PtexReader.cpp:195
static int DataSize(DataType dt)
Look up size of given data type (in bytes).
Definition: Ptexture.h:132
Memory-managed string.
Definition: Ptexture.h:303
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
Definition: PtexReader.cpp:185
void purgeData()
Definition: PtexCache.h:240
void readLevelInfo()
Definition: PtexReader.cpp:220
Entry * getEntry(const char *key)
Definition: PtexReader.cpp:265
Top edge, from UV (1,1) to (0,1)
Definition: Ptexture.h:102
uint32_t lmdheaderzipsize
Definition: PtexIO.h:65
static void reduceTri(const void *src, int sstride, int ures, int vres, void *dst, int dstride, DataType dt, int nchannels)
Definition: PtexUtils.cpp:389
static const int AllocaMax
Definition: PtexIO.h:111
safevector< FilePos > _levelpos
Definition: PtexReader.h:599
safevector< FilePos > _offsets
Definition: PtexReader.h:419
uint16_t nchannels
Definition: PtexIO.h:48
virtual PtexTexture * get(const char *path, Ptex::String &error)=0
Open a texture.
DataType
Type of data stored in texture file.
Definition: Ptexture.h:83
safevector< MetaEdit > _metaedits
Definition: PtexReader.h:608
static void blend(const void *src, float weight, void *dst, bool flip, int rowlen, DataType dt, int nchannels)
Definition: PtexUtils.cpp:463
FilePos _leveldatapos
Definition: PtexReader.h:585
uint32_t metadatamemsize
Definition: PtexIO.h:96
safevector< Level * > _levels
Definition: PtexReader.h:600
Meta data accessor.
Definition: Ptexture.h:337
static const int HeaderSize
Definition: PtexIO.h:100
uint8_t flags
Flags.
Definition: Ptexture.h:240
static T min(T a, T b)
Definition: PtexUtils.h:116
Mesh is triangle-based.
Definition: Ptexture.h:78
MetaData * _metadata
Definition: PtexReader.h:592
void unref()
Definition: PtexCache.h:272
uint32_t constdatasize
Definition: PtexIO.h:53
int pixelSize() const
Definition: PtexIO.h:59
File-handle and memory cache for reading ptex files.
Definition: Ptexture.h:634
void readConstData()
Definition: PtexReader.cpp:240
bool readBlock(void *data, int size, bool reportError=true)
Definition: PtexReader.cpp:503
virtual const char * path()
Path that file was opened with.
Definition: PtexReader.h:80
std::string _path
Definition: PtexReader.h:579
uint32_t faceinfosize
Definition: PtexIO.h:52
uint8_t * _constdata
Definition: PtexReader.h:591
static void copy(const void *src, int sstride, void *dst, int dstride, int nrows, int rowlen)
Definition: PtexUtils.cpp:421
static const int LevelInfoSize
Definition: PtexIO.h:102
void readLevel(int levelid, Level *&level)
Definition: PtexReader.cpp:545
virtual PtexMetaData * getMetaData()
Access meta data.
Definition: PtexReader.cpp:255
Platform-specific classes, functions, and includes.
static PtexCache * create(int maxFiles=0, int maxMem=0, bool premultiply=false, PtexInputHandler *handler=0)
Create a cache with the specified limits.
Definition: PtexCache.cpp:410
void setPendingDelete()
Definition: PtexCache.h:219
static const int EditMetaDataHeaderSize
Definition: PtexIO.h:105
int v() const
V resolution in texels.
Definition: Ptexture.h:181
virtual Handle open(const char *path)=0
Open a file in read mode.
uint32_t metadatazipsize
Definition: PtexIO.h:57
LargeMetaData * lmdData
Definition: PtexReader.h:224
#define STATS_INC(x)
Definition: PtexCache.h:97
Bottom edge, from UV (0,0) to (1,0)
Definition: Ptexture.h:100
PtexCacheImpl * _cache
Definition: PtexCache.h:275
ReductionMap _reductions
Definition: PtexReader.h:636
void unref()
Definition: PtexCache.h:289
virtual size_t read(void *buffer, size_t size, Handle handle)=0
Read a number of bytes from the file.
off_t FilePos
Definition: PtexPlatform.h:85
int32_t adjfaces[4]
Adjacent faces (-1 == no adjacent face).
Definition: Ptexture.h:241
uint32_t levelheadersize
Definition: PtexIO.h:73
uint32_t metadatazipsize
Definition: PtexIO.h:95
uint32_t lmdheadermemsize
Definition: PtexIO.h:66
safevector< FaceEdit > _faceedits
Definition: PtexReader.h:616
uint32_t blocksize() const
Definition: PtexIO.h:80
safevector< uint32_t > _rfaceids
Definition: PtexReader.h:596
static const int ExtHeaderSize
Definition: PtexIO.h:101
void blendFaces(FaceData *&face, int faceid, Res res, bool blendu)
Definition: PtexReader.cpp:942
z_stream_s _zstream
Definition: PtexReader.h:638
Per-face texture data accessor.
Definition: Ptexture.h:388
int u() const
U resolution in texels.
Definition: Ptexture.h:178
void readMetaDataBlock(MetaData *metadata, FilePos pos, int zipsize, int memsize)
Definition: PtexReader.cpp:371
Res getRes(int levelid, int faceid)
Definition: PtexReader.h:505
virtual void * getData()=0
Access the data from this data block.
int8_t vlog2
log base 2 of v resolution, in texels
Definition: Ptexture.h:163
virtual void reduce(FaceData *&, PtexReader *, Res newres, PtexUtils::ReduceFn)
FilePos _lmdheaderpos
Definition: PtexReader.h:587
static void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
Definition: PtexUtils.cpp:613
int ntilesu(Res tileres) const
Determine the number of tiles in the u direction for the given tile res.
Definition: Ptexture.h:214
virtual PtexFaceData * getTile(int tile)=0
Access a tile from the data block.
uint32_t version
Definition: PtexIO.h:44
virtual void reduce(FaceData *&, PtexReader *, Res newres, PtexUtils::ReduceFn)
Single-precision (32-bit) floating point.
Definition: Ptexture.h:87
uint32_t nfaces
Definition: PtexIO.h:74
safevector< FilePos > offsets
Definition: PtexReader.h:450
void readTile(int tile, FaceData *&data)
Definition: PtexReader.cpp:673
bool hasAlpha() const
Definition: PtexIO.h:60
void readMetaData()
Definition: PtexReader.cpp:320
DataType datatype
Definition: PtexIO.h:46
virtual ~PtexReader()
Definition: PtexReader.cpp:146
iterator end() const
Returns an iteraot referencing the location just beyond the table.
Definition: PtexHashMap.h:149
void computeOffsets(FilePos pos, int noffsets, const FaceDataHeader *fdh, FilePos *offsets)
Definition: PtexReader.h:538
void ReduceFn(const void *src, int sstride, int ures, int vres, void *dst, int dstride, DataType dt, int nchannels)
Definition: PtexUtils.h:132
bool hasEdits() const
Determine if face has edits in the file (by checking a flag).
Definition: Ptexture.h:276
Mutex readlock
Definition: PtexReader.h:465
safevector< FaceDataHeader > fdh
Definition: PtexReader.h:449
virtual void purgeAll()=0
Remove all texture files from the cache.
T * get()
Get pointer value.
Definition: Ptexture.h:971
bool _hasEdits
Definition: PtexReader.h:593
FilePos _faceinfopos
Definition: PtexReader.h:582
void setError(const char *error)
Definition: PtexReader.h:470
Encoding encoding() const
Definition: PtexIO.h:81
FilePos _editdatapos
Definition: PtexReader.h:589
static void orphanList(T &list)
Definition: PtexCache.h:116
PtexCacheImpl * _cache
Definition: PtexCache.h:293
virtual const char * lastError()=0
Return the last error message encountered.
safevector< Res > _res_r
Definition: PtexReader.h:597
bool readZipBlock(void *data, int zipsize, int unzipsize)
Definition: PtexReader.cpp:518
FilePos _levelinfopos
Definition: PtexReader.h:584
DataType datatype() const
Definition: PtexReader.h:103
static const uint32_t Magic
Definition: PtexIO.h:99
uint32_t magic
Definition: PtexIO.h:43
int32_t alphachan
Definition: PtexIO.h:47
virtual void getData(int faceid, void *buffer, int stride)
Access texture data for a face at highest-resolution.
Definition: PtexReader.cpp:759
bool _premultiply
Definition: PtexReader.h:573
static void fill(const void *src, void *dst, int dstride, int ures, int vres, int pixelsize)
Definition: PtexUtils.cpp:405
EdgeId adjedge(int eid) const
Access an adjacent edge id. The eid value must be 0..3.
Definition: Ptexture.h:264
virtual void getPixel(int u, int v, void *result)
Read a single texel from the data block.
FilePos _constdatapos
Definition: PtexReader.h:583
void readLargeMetaDataHeaders(MetaData *metadata, FilePos pos, int zipsize, int memsize)
Definition: PtexReader.cpp:397
Level * getLevel(int levelid)
Definition: PtexReader.h:488
PtexInputHandler::Handle _fp
Definition: PtexReader.h:577
int size() const
Total size of specified texture in texels (u * v).
Definition: Ptexture.h:190
virtual void getPixel(int faceid, int u, int v, float *result, int firstchan, int nchannels)
Access a single texel from the highest resolution texture .
int nchannels() const
Definition: PtexReader.h:104
static PtexTexture * open(const char *path, Ptex::String &error, bool premultiply=0)
Open a ptex file for reading.
Definition: PtexReader.cpp:46
void swapuv()
Swap the u and v resolution values in place.
Definition: Ptexture.h:205
void readFace(int levelid, Level *level, int faceid)
Definition: PtexReader.cpp:590
Smart-pointer for acquiring and releasing API objects.
Definition: Ptexture.h:955
virtual bool isTiled()=0
True if this data block is tiled.
FilePos _metadatapos
Definition: PtexReader.h:586
uint64_t lmddatasize
Definition: PtexIO.h:67
void readFaceData(FilePos pos, FaceDataHeader fdh, Res res, int levelid, FaceData *&face)
Definition: PtexReader.cpp:700
virtual void * getData()
Access the data from this data block.
Definition: PtexReader.h:313
Header _header
Definition: PtexReader.h:580
virtual bool isConstant()=0
True if this data block is constant.
uint32_t metadatamemsize
Definition: PtexIO.h:58
uint64_t editdatasize
Definition: PtexIO.h:68
int _pixelsize
Definition: PtexReader.h:590
int8_t ulog2
log base 2 of u resolution, in texels
Definition: Ptexture.h:162
virtual void getPixel(int u, int v, void *result)=0
Read a single texel from the data block.
uint32_t extheadersize
Definition: PtexIO.h:51
virtual PtexFaceData * getTile(int tile)
Access a tile from the data block.
FaceDataHeader fdh
Definition: PtexReader.h:614
Right edge, from UV (1,0) to (1,1)
Definition: Ptexture.h:101
Interface for reading data from a ptex file.
Definition: Ptexture.h:439
uint8_t * getConstData()
Definition: PtexReader.h:496
static const int BlockSize
Definition: PtexIO.h:109
safevector< FaceData * > faces
Definition: PtexReader.h:451
Pixel resolution of a given texture.
Definition: Ptexture.h:161
virtual void reduce(FaceData *&, PtexReader *, Res newres, PtexUtils::ReduceFn)
safevector< FaceDataHeader > _fdh
Definition: PtexReader.h:418
Cache entry for open file handle.
Definition: PtexCache.h:265
safevector< FaceInfo > _faceinfo
Definition: PtexReader.h:595
CacheLock cachelock
Definition: PtexCache.h:216
static void reduceu(const void *src, int sstride, int ures, int vres, void *dst, int dstride, DataType dt, int nchannels)
Definition: PtexUtils.cpp:316
static void interleave(const void *src, int sstride, int ures, int vres, void *dst, int dstride, DataType dt, int nchannels)
Definition: PtexUtils.cpp:171
static const int FaceDataHeaderSize
Definition: PtexIO.h:103
bool open(const char *path, Ptex::String &error)
Definition: PtexReader.cpp:63
Ptex cache implementation.
Definition: PtexCache.h:192
static void reducev(const void *src, int sstride, int ures, int vres, void *dst, int dstride, DataType dt, int nchannels)
Definition: PtexUtils.cpp:349
Res res
Resolution of face.
Definition: Ptexture.h:238
void orphan()
Definition: PtexCache.h:107
Automatically acquire and release lock within enclosing scope.
Definition: PtexMutex.h:58
Information about a face, as stored in the Ptex file header.
Definition: Ptexture.h:237
uint64_t leveldatasize
Definition: PtexIO.h:56
iterator begin() const
Returns an iterator referencing the beginning of the table.
Definition: PtexHashMap.h:136
#define STATS_ADD(x, y)
Definition: PtexCache.h:98
static void decodeDifference(void *data, int size, DataType dt)
Definition: PtexUtils.cpp:253
void addEntry(uint8_t keysize, const char *key, uint8_t datatype, uint32_t datasize, void *data)
Definition: PtexReader.h:188
void readEditFaceData()
Definition: PtexReader.cpp:457
void addLmdEntry(uint8_t keysize, const char *key, uint8_t datatype, uint32_t datasize, FilePos filepos, uint32_t zipsize)
Definition: PtexReader.h:196
void readEditData()
Definition: PtexReader.cpp:425
static void ConvertToFloat(float *dst, const void *src, Ptex::DataType dt, int numChannels)
Convert a number of data values from the given data type to float.
Definition: PtexUtils.cpp:107
void seek(FilePos pos)
Definition: PtexReader.h:477
static bool LittleEndian()
Definition: PtexIO.h:114
static const int EditFaceDataHeaderSize
Definition: PtexIO.h:104
const char * c_str() const
Definition: Ptexture.h:312
virtual bool close(Handle handle)=0
Close a file.
void readEditMetaData()
Definition: PtexReader.cpp:488
FilePos tell()
Definition: PtexReader.h:476
FaceDataHeader fdh
Definition: PtexIO.h:92
FilePos _pos
Definition: PtexReader.h:578
Public API classes for reading, writing, caching, and filtering Ptex files.
int unpackedSize(FaceDataHeader fdh, int levelid, int faceid)
Definition: PtexReader.h:516
PtexReader * _reader
Definition: PtexReader.h:262
Custom handler interface for intercepting and redirecting Ptex input stream calls.
Definition: Ptexture.h:585
FilePos _lmddatapos
Definition: PtexReader.h:588
virtual Ptex::Res tileRes()=0
Resolution of each tile in this data block.
static T max(T a, T b)
Definition: PtexUtils.h:119