Ptex
PtexReader.cpp
Go to the documentation of this file.
1 /*
2 PTEX SOFTWARE
3 Copyright 2014 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 <libdeflate.h>
42 
43 #include "Ptexture.h"
44 #include "PtexUtils.h"
45 #include "PtexReader.h"
46 
47 namespace {
48  class TempErrorHandler : public PtexErrorHandler
49  {
50  std::string _error;
51  public:
52  virtual void reportError(const char* error) {
53  _error += error;
54  }
55  const std::string& getErrorString() const { return _error; }
56  };
57 }
58 
60 
61 PtexTexture* PtexTexture::open(const char* path, Ptex::String& error, bool premultiply)
62 {
63  PtexReader* reader = new PtexReader(premultiply, (PtexInputHandler*) 0, (PtexErrorHandler*) 0);
64  bool ok = reader->open(path, error);
65  if (!ok) {
66  reader->release();
67  return 0;
68  }
69  return reader;
70 }
71 
72 
74  : _io(io ? io : &_defaultIo),
75  _err(err),
76  _premultiply(premultiply),
77  _ok(true),
78  _needToOpen(true),
79  _pendingPurge(false),
80  _fp(0),
81  _pos(0),
82  _pixelsize(0),
83  _constdata(0),
84  _metadata(0),
85  _baseMemUsed(sizeof(*this)),
86  _memUsed(_baseMemUsed),
87  _opens(0),
88  _blockReads(0)
89 {
90  _decompressor = libdeflate_alloc_decompressor();
91 }
92 
93 
95 {
96  closeFP();
97  if (_constdata) delete [] _constdata;
98  if (_metadata) delete _metadata;
99 
100  for (std::vector<Level*>::iterator i = _levels.begin(); i != _levels.end(); ++i) {
101  if (*i) delete *i;
102  }
103  libdeflate_free_decompressor(_decompressor);
104 }
105 
107 {
108  if (_metadata) { delete _metadata; _metadata = 0; }
109  for (std::vector<Level*>::iterator i = _levels.begin(); i != _levels.end(); ++i) {
110  if (*i) { delete *i; *i = 0; }
111  }
112  _reductions.clear();
114 }
115 
116 
118 {
119  // free all dynamic data
120  prune();
121  if (_constdata) {delete [] _constdata; _constdata = 0; }
122  std::vector<FaceInfo>().swap(_faceinfo);
123  std::vector<uint32_t>().swap(_rfaceids);
124  std::vector<LevelInfo>().swap(_levelinfo);
125  std::vector<FilePos>().swap(_levelpos);
126  std::vector<Level*>().swap(_levels);
127  closeFP();
128 
129  // reset initial state
130  _ok = true;
131  _needToOpen = true;
132  _pendingPurge = false;
133  _memUsed = _baseMemUsed = sizeof(*this);
134 }
135 
136 
137 bool PtexReader::open(const char* pathArg, Ptex::String& error)
138 {
139  AutoMutex locker(readlock);
140  if (!needToOpen()) return false;
141 
142  if (!LittleEndian()) {
143  error = "Ptex library doesn't currently support big-endian cpu's";
144  return 0;
145  }
146  _path = pathArg;
147  _fp = _io->open(pathArg);
148  if (!_fp) {
149  std::string errstr = "Can't open ptex file: ";
150  errstr += pathArg; errstr += "\n"; errstr += _io->lastError();
151  error = errstr.c_str();
152  _ok = 0;
153  return 0;
154  }
155  memset(&_header, 0, sizeof(_header));
157  if (_header.magic != Magic) {
158  std::string errstr = "Not a ptex file: "; errstr += pathArg;
159  error = errstr.c_str();
160  _ok = 0;
161  closeFP();
162  return 0;
163  }
164  if (_header.version != 1) {
165  std::stringstream s;
166  s << "Unsupported ptex file version ("<< _header.version << "): " << pathArg;
167  error = s.str();
168  _ok = 0;
169  closeFP();
170  return 0;
171  }
173  std::stringstream s;
174  s << "Invalid mesh type (" << _header.meshtype << "): " << pathArg;
175  error = s.str();
176  _ok = 0;
177  closeFP();
178  return 0;
179  }
181  _errorPixel.resize(_pixelsize);
182 
183  // install temp error handler to capture error (to return in error param)
184  TempErrorHandler tempErr;
185  PtexErrorHandler* prevErr = _err;
186  _err = &tempErr;
187 
188  // read extended header
189  memset(&_extheader, 0, sizeof(_extheader));
190  readBlock(&_extheader, std::min(uint32_t(ExtHeaderSize), _header.extheadersize));
191 
192  // compute offsets of various blocks
194  _faceinfopos = pos; pos += _header.faceinfosize;
195  _constdatapos = pos; pos += _header.constdatasize;
196  _levelinfopos = pos; pos += _header.levelinfosize;
197  _leveldatapos = pos; pos += _header.leveldatasize;
198  _metadatapos = pos; pos += _header.metadatazipsize;
199  pos += sizeof(uint64_t); // compatibility barrier
201  _lmddatapos = pos; pos += _extheader.lmddatasize;
202 
203  // read basic file info
204  readFaceInfo();
205  readConstData();
206  readLevelInfo();
208 
209  // restore error handler
210  _err = prevErr;
211 
212  // an error occurred while reading the file
213  if (!_ok) {
214  error = tempErr.getErrorString();
215  closeFP();
216  return 0;
217  }
218  AtomicStore(&_needToOpen, false);
219  return true;
220 }
221 
223 {
224  if (_fp) {
225  if (!readlock.trylock()) return false;
226  closeFP();
227  readlock.unlock();
228  }
229  return true;
230 }
231 
232 
234 {
235  if (_fp) {
236  _io->close(_fp);
237  _fp = 0;
238  }
239 }
240 
241 
243 {
244  if (_fp) return true;
245 
246  // we assume this is called lazily in a scope where readlock is already held
247  _fp = _io->open(_path.c_str());
248  if (!_fp) {
249  setIOError("Can't reopen");
250  return false;
251  }
252  _pos = 0;
253  Header headerval;
254  ExtHeader extheaderval;
255  readBlock(&headerval, HeaderSize);
256  memset(&extheaderval, 0, sizeof(extheaderval));
257  readBlock(&extheaderval, std::min(uint32_t(ExtHeaderSize), headerval.extheadersize));
258  if (0 != memcmp(&headerval, &_header, sizeof(headerval)) ||
259  0 != memcmp(&extheaderval, &_extheader, sizeof(extheaderval)))
260  {
261  setError("Header mismatch on reopen of");
262  return false;
263  }
264  logOpen();
265  return true;
266 }
267 
268 
270 {
271  if (faceid >= 0 && uint32_t(faceid) < _faceinfo.size())
272  return _faceinfo[faceid];
273 
274  static Ptex::FaceInfo dummy;
275  return dummy;
276 }
277 
278 
280 {
281  if (_faceinfo.empty()) {
282  // read compressed face info block
284  int nfaces = _header.nfaces;
285  _faceinfo.resize(nfaces);
287  (int)(sizeof(FaceInfo)*nfaces));
288 
289  // generate rfaceids
290  _rfaceids.resize(nfaces);
291  std::vector<uint32_t> faceids_r(nfaces);
292  PtexUtils::genRfaceids(&_faceinfo[0], nfaces,
293  &_rfaceids[0], &faceids_r[0]);
294  increaseMemUsed(nfaces * (sizeof(_faceinfo[0]) + sizeof(_rfaceids[0])));
295  }
296 }
297 
298 
299 
301 {
302  if (_levelinfo.empty()) {
303  // read level info block
305  _levelinfo.resize(_header.nlevels);
307 
308  // initialize related data
309  _levels.resize(_header.nlevels);
310  _levelpos.resize(_header.nlevels);
311  FilePos pos = _leveldatapos;
312  for (int i = 0; i < _header.nlevels; i++) {
313  _levelpos[i] = pos;
314  pos += _levelinfo[i].leveldatasize;
315  }
316  increaseMemUsed(_header.nlevels * sizeof(_levelinfo[0]) + sizeof(_levels[0]) + sizeof(_levelpos[0]));
317  }
318 }
319 
320 
322 {
323  if (!_constdata) {
324  // read compressed constant data block
326  int size = _pixelsize * _header.nfaces;
327  _constdata = new uint8_t[size];
329  if (_premultiply && _header.hasAlpha())
332  increaseMemUsed(size);
333  }
334 }
335 
336 
338 {
339  if (!_metadata) readMetaData();
340  return _metadata;
341 }
342 
343 
346 {
347  if (index < 0 || index >= int(_entries.size())) {
348  return 0;
349  }
350 
351  Entry* e = _entries[index];
352  if (!e->isLmd) {
353  // normal (small) meta data - just return directly
354  return e;
355  }
356 
357  // large meta data - may not be read in yet
358  if (e->lmdData) {
359  // already in memory
360  return e;
361  }
362  else {
363  // not present, must read from file
364 
365  // get read lock and make sure we still need to read
366  AutoMutex locker(_reader->readlock);
367  if (e->lmdData) {
368  return e;
369  }
370  // go ahead and read, keep local until finished
371  LargeMetaData* lmdData = new LargeMetaData(e->datasize);
372  e->data = (char*) lmdData->data();
374  _reader->seek(e->lmdPos);
376  // update entry
377  e->lmdData = lmdData;
378  return e;
379  }
380 }
381 
382 
384 {
385  // get read lock and make sure we still need to read
386  AutoMutex locker(readlock);
387  if (_metadata) {
388  return;
389  }
390 
391  // allocate new meta data (keep local until fully initialized)
392  MetaData* newmeta = new MetaData(this);
393  size_t metaDataMemUsed = sizeof(MetaData);
394 
395  // read primary meta data blocks
398  _header.metadatazipsize, _header.metadatamemsize, metaDataMemUsed);
399 
400  // read large meta data headers
404 
405  // store meta data
406  AtomicStore(&_metadata, newmeta);
407  increaseMemUsed(newmeta->selfDataSize() + metaDataMemUsed);
408 }
409 
410 
411 void PtexReader::readMetaDataBlock(MetaData* metadata, FilePos pos, int zipsize, int memsize, size_t& metaDataMemUsed)
412 {
413  seek(pos);
414  // read from file
415  bool useNew = memsize > AllocaMax;
416  char* buff = useNew ? new char[memsize] : (char*)alloca(memsize);
417 
418  if (readZipBlock(buff, zipsize, memsize)) {
419  // unpack data entries
420  char* ptr = buff;
421  char* end = ptr + memsize;
422  while (ptr < end) {
423  uint8_t keysize = *ptr++;
424  char* key = (char*)ptr; ptr += keysize;
425  key[keysize-1] = '\0';
426  uint8_t datatypeval = *ptr++;
427  uint32_t datasize; memcpy(&datasize, ptr, sizeof(datasize));
428  ptr += sizeof(datasize);
429  char* data = ptr; ptr += datasize;
430  metadata->addEntry((uint8_t)(keysize-1), key, datatypeval, datasize, data, metaDataMemUsed);
431  }
432  }
433  if (useNew) delete [] buff;
434 }
435 
436 
437 void PtexReader::readLargeMetaDataHeaders(MetaData* metadata, FilePos pos, int zipsize, int memsize, size_t& metaDataMemUsed)
438 {
439  seek(pos);
440  // read from file
441  bool useNew = memsize > AllocaMax;
442  char* buff = useNew ? new char [memsize] : (char*)alloca(memsize);
443 
444  if (readZipBlock(buff, zipsize, memsize)) {
445  pos += zipsize;
446 
447  // unpack data entries
448  char* ptr = buff;
449  char* end = ptr + memsize;
450  while (ptr < end) {
451  uint8_t keysize = *ptr++;
452  char* key = (char*)ptr; ptr += keysize;
453  uint8_t datatypeval = *ptr++;
454  uint32_t datasize; memcpy(&datasize, ptr, sizeof(datasize));
455  ptr += sizeof(datasize);
456  uint32_t zipsizeval; memcpy(&zipsizeval, ptr, sizeof(zipsizeval));
457  ptr += sizeof(zipsizeval);
458  metadata->addLmdEntry((uint8_t)(keysize-1), key, datatypeval, datasize, pos, zipsizeval, metaDataMemUsed);
459  pos += zipsizeval;
460  }
461  }
462  if (useNew) delete [] buff;
463 }
464 
465 
466 bool PtexReader::readBlock(void* data, int size)
467 {
468  assert(_fp && size >= 0);
469  if (!_fp || size < 0) return false;
470  int result = (int)_io->read(data, size, _fp);
471  if (result == size) {
472  _pos += size;
473  return true;
474  }
475  setIOError("PtexReader error: read failed");
476  return false;
477 }
478 
479 
480 bool PtexReader::readZipBlock(void* data, int zipsize, int unzipsize)
481 {
482  if (!_ok || zipsize < 0 || unzipsize < 0) return false;
483  std::vector<std::byte> compressedBuffer(zipsize);
484  if (!readBlock(compressedBuffer.data(), compressedBuffer.size())) {
485  return false;
486  }
487  size_t bytesDecompressed{0};
488  if (libdeflate_zlib_decompress(_decompressor, compressedBuffer.data(), compressedBuffer.size(),
489  data, unzipsize, &bytesDecompressed) != 0 ||
490  bytesDecompressed != size_t(unzipsize))
491  {
492  setError("PtexReader error: unzip failed, file corrupt");
493  return false;
494  }
495  return true;
496 }
497 
498 
499 void PtexReader::readLevel(int levelid, Level*& level)
500 {
501  // get read lock and make sure we still need to read
502  AutoMutex locker(readlock);
503  if (level) {
504  return;
505  }
506 
507  // go ahead and read the level
508  LevelInfo& l = _levelinfo[levelid];
509 
510  // keep new level local until finished
511  Level* newlevel = new Level(l.nfaces);
512 
513  // read level header
514  seek(_levelpos[levelid]);
516 
517  // compute face offsets
518  std::vector<uint32_t> largeFaces;
519  FilePos offset = tell();
520  for (uint32_t f = 0; f < l.nfaces; f++) {
521  newlevel->offsets[f] = offset;
522  if (!newlevel->fdh[f].isLargeFace()) {
523  offset += newlevel->fdh[f].blocksize();
524  } else {
525  // large faces have a 64-bit size, stored after the level header
526  largeFaces.push_back(f);
527  }
528  }
529 
530  // update offsets to account for large faces
531  if (!largeFaces.empty()) {
532  int nlarge = int(largeFaces.size());
533  // read large face header (64-bit sizes of large faces)
534  std::vector<size_t> largeFaceHeader(nlarge);
535  size_t largeFaceHeaderSize = sizeof(size_t) * nlarge;
536  readBlock(largeFaceHeader.data(), largeFaceHeaderSize);
537 
538  // update offsets
539  size_t extraOffset = largeFaceHeaderSize;
540  uint32_t f = 0;
541  for (int i = 0; i < nlarge; i++) {
542  uint32_t lf = largeFaces[i];
543  while (f <= lf) {
544  newlevel->offsets[f++] += extraOffset;
545  }
546  extraOffset += largeFaceHeader[i];
547  }
548  while (f < l.nfaces) {
549  newlevel->offsets[f++] += extraOffset;
550  }
551  }
552 
553  // don't assign to result until level data is fully initialized
554  AtomicStore(&level, newlevel);
555  increaseMemUsed(level->memUsed());
556 }
557 
558 
559 void PtexReader::readFace(int levelid, Level* level, int faceid, Ptex::Res res)
560 {
561  FaceData*& face = level->faces[faceid];
562  FaceDataHeader fdh = level->fdh[faceid];
563  readFaceData(level->offsets[faceid], fdh, res, levelid, face);
564 }
565 
566 
568 {
569  _reader->readFaceData(_offsets[tile], _fdh[tile], _tileres, _levelid, data);
570 }
571 
572 
573 void PtexReader::readFaceData(FilePos pos, FaceDataHeader fdh, Res res, int levelid,
574  FaceData*& face)
575 {
576  AutoMutex locker(readlock);
577  if (face) {
578  return;
579  }
580 
581  // keep new face local until fully initialized
582  FaceData* newface = 0;
583  size_t newMemUsed = 0;
584 
585  seek(pos);
586  switch (fdh.encoding()) {
587  case enc_constant:
588  {
590  newface = cf;
591  newMemUsed = sizeof(ConstantFace) + _pixelsize;
592  readBlock(cf->data(), _pixelsize);
593  if (levelid==0 && _premultiply && _header.hasAlpha())
594  PtexUtils::multalpha(cf->data(), 1, datatype(),
596  }
597  break;
598  case enc_tiled:
599  {
600  Res tileres;
601  readBlock(&tileres, sizeof(tileres));
602  uint32_t tileheadersize;
603  readBlock(&tileheadersize, sizeof(tileheadersize));
604  TiledFace* tf = new TiledFace(this, res, tileres, levelid);
605  newface = tf;
606  newMemUsed = tf->memUsed();
607  readZipBlock(&tf->_fdh[0], tileheadersize, FaceDataHeaderSize * tf->_ntiles);
608  computeFaceTileOffsets(tell(), tf->_ntiles, &tf->_fdh[0], &tf->_offsets[0]);
609  }
610  break;
611  case enc_zipped:
612  case enc_diffzipped:
613  {
614  int uw = res.u(), vw = res.v();
615  int npixels = uw * vw;
616  int unpackedSize = _pixelsize * npixels;
617  PackedFace* pf = new PackedFace(res, _pixelsize, unpackedSize);
618  newface = pf;
619  newMemUsed = sizeof(PackedFace) + unpackedSize;
620  bool useNew = unpackedSize > AllocaMax;
621  char* tmp = useNew ? new char [unpackedSize] : (char*) alloca(unpackedSize);
622  readZipBlock(tmp, fdh.blocksize(), unpackedSize);
623  if (fdh.encoding() == enc_diffzipped)
624  PtexUtils::decodeDifference(tmp, unpackedSize, datatype());
625  PtexUtils::interleave(tmp, uw * DataSize(datatype()), uw, vw,
626  pf->data(), uw * _pixelsize,
628  if (levelid==0 && _premultiply && _header.hasAlpha())
629  PtexUtils::multalpha(pf->data(), npixels, datatype(),
631  if (useNew) delete [] tmp;
632  }
633  break;
634  }
635 
636  if (!newface) newface = errorData();
637 
638  AtomicStore(&face, newface);
639  increaseMemUsed(newMemUsed);
640 }
641 
642 
643 void PtexReader::getData(int faceid, void* buffer, int stride)
644 {
645  const FaceInfo& f = getFaceInfo(faceid);
646  getData(faceid, buffer, stride, f.res);
647 }
648 
649 
650 void PtexReader::getData(int faceid, void* buffer, int stride, Res res)
651 {
652  if (!_ok || faceid < 0 || size_t(faceid) >= _header.nfaces) {
653  PtexUtils::fill(&_errorPixel[0], buffer, stride, res.u(), res.v(), _pixelsize);
654  return;
655  }
656 
657  // note - all locking is handled in called getData methods
658  int resu = res.u(), resv = res.v();
659  int rowlen = _pixelsize * resu;
660  if (stride == 0) stride = rowlen;
661 
662  PtexPtr<PtexFaceData> d ( getData(faceid, res) );
663  if (d->isConstant()) {
664  // fill dest buffer with pixel value
665  PtexUtils::fill(d->getData(), buffer, stride,
666  resu, resv, _pixelsize);
667  }
668  else if (d->isTiled()) {
669  // loop over tiles
670  Res tileres = d->tileRes();
671  int ntilesu = res.ntilesu(tileres);
672  int ntilesv = res.ntilesv(tileres);
673  int tileures = tileres.u();
674  int tilevres = tileres.v();
675  int tilerowlen = _pixelsize * tileures;
676  int tile = 0;
677  char* dsttilerow = (char*) buffer;
678  for (int i = 0; i < ntilesv; i++) {
679  char* dsttile = dsttilerow;
680  for (int j = 0; j < ntilesu; j++) {
681  PtexPtr<PtexFaceData> t ( d->getTile(tile++) );
682  if (t->isConstant())
683  PtexUtils::fill(t->getData(), dsttile, stride,
684  tileures, tilevres, _pixelsize);
685  else
686  PtexUtils::copy(t->getData(), tilerowlen, dsttile, stride,
687  tilevres, tilerowlen);
688  dsttile += tilerowlen;
689  }
690  dsttilerow += stride * tilevres;
691  }
692  }
693  else {
694  PtexUtils::copy(d->getData(), rowlen, buffer, stride, resv, rowlen);
695  }
696 }
697 
698 
700 {
701  if (!_ok || faceid < 0 || size_t(faceid) >= _header.nfaces) {
702  return errorData(/*deleteOnRelease*/ true);
703  }
704 
705  FaceInfo& fi = _faceinfo[faceid];
706  if (fi.isConstant() || fi.res == 0) {
707  return new ConstDataPtr(getConstantData(faceid), _pixelsize);
708  }
709 
710  // get level zero (full) res face
711  Level* level = getLevel(0);
712  FaceData* face = getFace(0, level, faceid, fi.res);
713  return face;
714 }
715 
716 
717 PtexFaceData* PtexReader::getData(int faceid, Res res)
718 {
719  if (!_ok || faceid < 0 || size_t(faceid) >= _header.nfaces) {
720  return errorData(/*deleteOnRelease*/ true);
721  }
722 
723  FaceInfo& fi = _faceinfo[faceid];
724  if (fi.isConstant() || res == 0) {
725  return new ConstDataPtr(getConstantData(faceid), _pixelsize);
726  }
727 
728  // determine how many reduction levels are needed
729  int redu = fi.res.ulog2 - res.ulog2, redv = fi.res.vlog2 - res.vlog2;
730 
731  if (redu == 0 && redv == 0) {
732  // no reduction - get level zero (full) res face
733  Level* level = getLevel(0);
734  FaceData* face = getFace(0, level, faceid, res);
735  return face;
736  }
737 
738  if (redu == redv) {
739  // reduction is symmetric and non-negative
740  // => access data from reduction level (if present)
741  int levelid = redu;
742  if (size_t(levelid) < _levels.size()) {
743  Level* level = getLevel(levelid);
744 
745  // get reduction face id
746  int rfaceid = _rfaceids[faceid];
747 
748  // get the face data (if present)
749  FaceData* face = 0;
750  if (size_t(rfaceid) < level->faces.size()) {
751  face = getFace(levelid, level, rfaceid, res);
752  }
753  if (face) {
754  return face;
755  }
756  }
757  }
758 
759  // dynamic reduction required - look in dynamic reduction cache
760  ReductionKey key(faceid, res);
761  FaceData* face = _reductions.get(key);
762  if (face) {
763  return face;
764  }
765 
766  // not found, generate new reduction
767  FaceData *newface = 0;
768  size_t newMemUsed = 0;
769 
770  if (res.ulog2 < 0 || res.vlog2 < 0) {
771  std::cerr << "PtexReader::getData - reductions below 1 pixel not supported" << std::endl;
772  newface = errorData();
773  }
774  else if (redu < 0 || redv < 0) {
775  std::cerr << "PtexReader::getData - enlargements not supported" << std::endl;
776  newface = errorData();
777  }
778  else if (_header.meshtype == mt_triangle)
779  {
780  if (redu != redv) {
781  std::cerr << "PtexReader::getData - anisotropic reductions not supported for triangle mesh" << std::endl;
782  newface = errorData();
783  }
784  else {
785  PtexPtr<PtexFaceData> psrc ( getData(faceid, Res((int8_t)(res.ulog2+1), (int8_t)(res.vlog2+1))) );
786  FaceData* src = static_cast<FaceData*>(psrc.get());
787  newface = src->reduce(this, res, PtexUtils::reduceTri, newMemUsed);
788  }
789  }
790  else {
791  // determine which direction to blend
792  bool blendu;
793  if (redu == redv) {
794  // for symmetric face blends, alternate u and v blending
795  blendu = (res.ulog2 & 1);
796  }
797  else blendu = redu > redv;
798 
799  if (blendu) {
800  // get next-higher u-res and reduce in u
801  PtexPtr<PtexFaceData> psrc ( getData(faceid, Res((int8_t)(res.ulog2+1), (int8_t)res.vlog2)) );
802  FaceData* src = static_cast<FaceData*>(psrc.get());
803  newface = src->reduce(this, res, PtexUtils::reduceu, newMemUsed);
804  }
805  else {
806  // get next-higher v-res and reduce in v
807  PtexPtr<PtexFaceData> psrc ( getData(faceid, Res((int8_t)res.ulog2, (int8_t)(res.vlog2+1))) );
808  FaceData* src = static_cast<FaceData*>(psrc.get());
809  newface = src->reduce(this, res, PtexUtils::reducev, newMemUsed);
810  }
811  }
812 
813  size_t tableNewMemUsed = 0;
814  face = _reductions.tryInsert(key, newface, tableNewMemUsed);
815  if (face != newface) {
816  delete newface;
817  }
818  else {
819  increaseMemUsed(newMemUsed + tableNewMemUsed);
820  }
821  return face;
822 }
823 
824 
825 void PtexReader::getPixel(int faceid, int u, int v,
826  float* result, int firstchan, int nchannelsArg)
827 {
828  memset(result, 0, sizeof(*result)*nchannelsArg);
829 
830  // clip nchannels against actual number available
831  nchannelsArg = std::min(nchannelsArg, _header.nchannels-firstchan);
832  if (nchannelsArg <= 0) return;
833 
834  // get raw pixel data
835  void* pixel;
836  if (faceid >= 0 && size_t(faceid) < _header.nfaces && _faceinfo[faceid].isConstant()) {
837  pixel = getConstantData(faceid);
838  }
839  else {
840  PtexPtr<PtexFaceData> data ( getData(faceid) );
841  pixel = alloca(_pixelsize);
842  data->getPixel(u, v, pixel);
843  }
844 
845  // adjust for firstchan offset
846  int datasize = DataSize(datatype());
847  if (firstchan)
848  pixel = (char*) pixel + datasize * firstchan;
849 
850  // convert/copy to result as needed
851  if (datatype() == dt_float)
852  memcpy(result, pixel, datasize * nchannelsArg);
853  else
854  ConvertToFloat(result, pixel, datatype(), nchannelsArg);
855 }
856 
857 
858 void PtexReader::getPixel(int faceid, int u, int v,
859  float* result, int firstchan, int nchannelsArg,
860  Ptex::Res res)
861 {
862  memset(result, 0, sizeof(*result)*nchannelsArg);
863 
864  // clip nchannels against actual number available
865  nchannelsArg = std::min(nchannelsArg, _header.nchannels-firstchan);
866  if (nchannelsArg <= 0) return;
867 
868  // get raw pixel data
869  void* pixel;
870  if (faceid >= 0 && size_t(faceid) < _header.nfaces && _faceinfo[faceid].isConstant()) {
871  pixel = getConstantData(faceid);
872  }
873  else {
874  PtexPtr<PtexFaceData> data ( getData(faceid, res) );
875  pixel = alloca(_pixelsize);
876  data->getPixel(u, v, pixel);
877  }
878 
879  // adjust for firstchan offset
880  int datasize = DataSize(datatype());
881  if (firstchan)
882  pixel = (char*) pixel + datasize * firstchan;
883 
884  // convert/copy to result as needed
885  if (datatype() == dt_float)
886  memcpy(result, pixel, datasize * nchannelsArg);
887  else
888  ConvertToFloat(result, pixel, datatype(), nchannelsArg);
889 }
890 
891 
892 void PtexReader::getCompressedData(int faceid, int levelid, FaceDataHeader& fdh, std::vector<std::byte>& data)
893 {
894  if (!_ok || faceid < 0 || size_t(faceid) >= _header.nfaces || size_t(levelid) >= _levels.size()) {
895  return;
896  }
897 
898  Level* level = getLevel(levelid);
899  int rfaceid = levelid == 0 ? faceid : _rfaceids[faceid];
900  fdh = level->fdh[rfaceid];
901  FilePos offset = level->offsets[rfaceid];
902  size_t size{0};
903  if (!fdh.isLargeFace()) {
904  size = fdh.blocksize();
905  } else if (fdh.encoding() == enc_tiled) {
906  // read tiled face header
907  seek(offset);
908  FaceInfo& fi = _faceinfo[faceid];
909  Res level_res(fi.res.ulog2 - levelid, fi.res.vlog2 - levelid);
910  Res tileres;
911  readBlock(&tileres, sizeof(tileres));
912  uint32_t tileheadersize;
913  readBlock(&tileheadersize, sizeof(tileheadersize));
914  int ntiles = level_res.ntiles(tileres);
915  std::vector<FaceDataHeader> tiledFace_fdh(ntiles);
916  readZipBlock(&tiledFace_fdh[0], tileheadersize, FaceDataHeaderSize * ntiles);
917 
918  // sum total size of header and tiles
919  size = sizeof(tileres) + sizeof(tileheadersize) + tileheadersize;
920  for (auto fdh : tiledFace_fdh) {
921  size += fdh.blocksize();
922  }
923  }
924 
925  // read compressed face data
926  seek(offset);
927  data.resize(size);
928  readBlock(data.data(), size);
929 }
930 
931 
934  size_t& newMemUsed)
935 {
936  // allocate a new face and reduce image
937  DataType dt = r->datatype();
938  int nchan = r->nchannels();
939  int memsize = _pixelsize * newres.size64();
940  PackedFace* pf = new PackedFace(newres, _pixelsize, memsize);
941  newMemUsed = sizeof(PackedFace) + memsize;
942  // reduce and copy into new face
943  reducefn(_data, _pixelsize * _res.u(), _res.u(), _res.v(),
944  pf->_data, _pixelsize * newres.u(), dt, nchan);
945  return pf;
946 }
947 
948 
949 
951 {
952  // must make a new constant face (even though it's identical to this one)
953  // because it will be owned by a different reduction level
954  // and will therefore have a different parent
956  newMemUsed = sizeof(ConstantFace) + _pixelsize;
957  memcpy(pf->_data, _data, _pixelsize);
958  return pf;
959 }
960 
961 
964  size_t& newMemUsed)
965 {
966  /* Tiled reductions should generally only be anisotropic (just u
967  or v, not both) since isotropic reductions are precomputed and
968  stored on disk. (This function should still work for isotropic
969  reductions though.)
970 
971  In the anisotropic case, the number of tiles should be kept the
972  same along the direction not being reduced in order to preserve
973  the laziness of the file access. In contrast, if reductions
974  were not tiled, then any reduction would read all the tiles and
975  defeat the purpose of tiling.
976  */
977 
978  // keep new face local until fully initialized
979  FaceData* newface = 0;
980 
981  // don't tile triangle reductions (too complicated)
982  Res newtileres;
983  bool isTriangle = r->_header.meshtype == mt_triangle;
984  if (isTriangle) {
985  newtileres = newres;
986  }
987  else {
988  // propagate the tile res to the reduction
989  newtileres = _tileres;
990  // but make sure tile isn't larger than the new face!
991  if (newtileres.ulog2 > newres.ulog2) newtileres.ulog2 = newres.ulog2;
992  if (newtileres.vlog2 > newres.vlog2) newtileres.vlog2 = newres.vlog2;
993  }
994 
995 
996  // determine how many tiles we will have on the reduction
997  int newntiles = newres.ntiles(newtileres);
998 
999  if (newntiles == 1) {
1000  // no need to keep tiling, reduce tiles into a single face
1001  // first, get all tiles and check if they are constant (with the same value)
1002  PtexFaceData** tiles = (PtexFaceData**) alloca(_ntiles * sizeof(PtexFaceData*));
1003  bool allConstant = true;
1004  for (int i = 0; i < _ntiles; i++) {
1005  PtexFaceData* tile = tiles[i] = getTile(i);
1006  allConstant = (allConstant && tile->isConstant() &&
1007  (i == 0 || (0 == memcmp(tiles[0]->getData(), tile->getData(),
1008  _pixelsize))));
1009  }
1010  if (allConstant) {
1011  // allocate a new constant face
1012  newface = new ConstantFace(_pixelsize);
1013  memcpy(newface->getData(), tiles[0]->getData(), _pixelsize);
1014  newMemUsed = sizeof(ConstantFace) + _pixelsize;
1015  }
1016  else if (isTriangle) {
1017  // reassemble all tiles into temporary contiguous image
1018  // (triangle reduction doesn't work on tiles)
1019  int tileures = _tileres.u();
1020  int tilevres = _tileres.v();
1021  int sstride = _pixelsize * tileures;
1022  int dstride = sstride * _ntilesu;
1023  int dstepv = dstride * tilevres - sstride*(_ntilesu-1);
1024 
1025  char* tmp = new char [_ntiles * _tileres.size64() * _pixelsize];
1026  char* tmpptr = tmp;
1027  for (int i = 0; i < _ntiles;) {
1028  PtexFaceData* tile = tiles[i];
1029  if (tile->isConstant())
1030  PtexUtils::fill(tile->getData(), tmpptr, dstride,
1031  tileures, tilevres, _pixelsize);
1032  else
1033  PtexUtils::copy(tile->getData(), sstride, tmpptr, dstride, tilevres, sstride);
1034  i++;
1035  tmpptr += (i%_ntilesu) ? sstride : dstepv;
1036  }
1037 
1038  // allocate a new packed face
1039  int memsize = _pixelsize * newres.size64();
1040  newface = new PackedFace(newres, _pixelsize, memsize);
1041  newMemUsed = sizeof(PackedFace) + memsize;
1042  // reduce and copy into new face
1043  reducefn(tmp, _pixelsize * _res.u(), _res.u(), _res.v(),
1044  newface->getData(), _pixelsize * newres.u(), _dt, _nchan);
1045 
1046  delete [] tmp;
1047  }
1048  else {
1049  // allocate a new packed face
1050  int memsize = _pixelsize * newres.size64();
1051  newface = new PackedFace(newres, _pixelsize, memsize);
1052  newMemUsed = sizeof(PackedFace) + memsize;
1053 
1054  int tileures = _tileres.u();
1055  int tilevres = _tileres.v();
1056  int sstride = _pixelsize * tileures;
1057  int dstride = _pixelsize * newres.u();
1058  int dstepu = dstride/_ntilesu;
1059  int dstepv = dstride*newres.v()/_ntilesv - dstepu*(_ntilesu-1);
1060 
1061  char* dst = (char*) newface->getData();
1062  for (int i = 0; i < _ntiles;) {
1063  PtexFaceData* tile = tiles[i];
1064  if (tile->isConstant())
1065  PtexUtils::fill(tile->getData(), dst, dstride,
1066  newres.u()/_ntilesu, newres.v()/_ntilesv,
1067  _pixelsize);
1068  else
1069  reducefn(tile->getData(), sstride, tileures, tilevres,
1070  dst, dstride, _dt, _nchan);
1071  i++;
1072  dst += (i%_ntilesu) ? dstepu : dstepv;
1073  }
1074  }
1075  // release the tiles
1076  for (int i = 0; i < _ntiles; i++) tiles[i]->release();
1077  }
1078  else {
1079  // otherwise, tile the reduced face
1080  TiledReducedFace* tf = new TiledReducedFace(_reader, newres, newtileres, this, reducefn);
1081  newface = tf;
1082  newMemUsed = tf->memUsed();
1083  }
1084  return newface;
1085 }
1086 
1087 
1088 void PtexReader::TiledFaceBase::getPixel(int ui, int vi, void* result)
1089 {
1090  int tileu = ui >> _tileres.ulog2;
1091  int tilev = vi >> _tileres.vlog2;
1092  PtexPtr<PtexFaceData> tile ( getTile(tilev * _ntilesu + tileu) );
1093  tile->getPixel(ui - (tileu<<_tileres.ulog2),
1094  vi - (tilev<<_tileres.vlog2), result);
1095 }
1096 
1097 
1098 
1100 {
1101  FaceData*& face = _tiles[tile];
1102  if (face) {
1103  return face;
1104  }
1105 
1106  // first, get all parent tiles for this tile
1107  // and check if they are constant (with the same value)
1108  int pntilesu = _parentface->ntilesu();
1109  int pntilesv = _parentface->ntilesv();
1110  int nu = pntilesu / _ntilesu; // num parent tiles for this tile in u dir
1111  int nv = pntilesv / _ntilesv; // num parent tiles for this tile in v dir
1112 
1113  int ntilesval = nu*nv; // num parent tiles for this tile
1114  PtexFaceData** tiles = (PtexFaceData**) alloca(ntilesval * sizeof(PtexFaceData*));
1115  bool allConstant = true;
1116  int ptile = (tile/_ntilesu) * nv * pntilesu + (tile%_ntilesu) * nu;
1117  for (int i = 0; i < ntilesval;) {
1118  PtexFaceData* tileval = tiles[i] = _parentface->getTile(ptile);
1119  allConstant = (allConstant && tileval->isConstant() &&
1120  (i==0 || (0 == memcmp(tiles[0]->getData(), tileval->getData(),
1121  _pixelsize))));
1122  i++;
1123  ptile += (i%nu)? 1 : pntilesu - nu + 1;
1124  }
1125 
1126  FaceData* newface = 0;
1127  size_t newMemUsed = 0;
1128  if (allConstant) {
1129  // allocate a new constant face
1130  newface = new ConstantFace(_pixelsize);
1131  newMemUsed = sizeof(ConstantFace) + _pixelsize;
1132  memcpy(newface->getData(), tiles[0]->getData(), _pixelsize);
1133  }
1134  else {
1135  // allocate a new packed face for the tile
1136  int memsize = _pixelsize*_tileres.size64();
1137  newface = new PackedFace(_tileres, _pixelsize, memsize);
1138  newMemUsed = sizeof(PackedFace) + memsize;
1139 
1140  // generate reduction from parent tiles
1141  int ptileures = _parentface->tileres().u();
1142  int ptilevres = _parentface->tileres().v();
1143  int sstride = ptileures * _pixelsize;
1144  int dstride = _tileres.u() * _pixelsize;
1145  int dstepu = dstride/nu;
1146  int dstepv = dstride*_tileres.v()/nv - dstepu*(nu-1);
1147 
1148  char* dst = (char*) newface->getData();
1149  for (int i = 0; i < ntilesval;) {
1150  PtexFaceData* tileval = tiles[i];
1151  if (tileval->isConstant())
1152  PtexUtils::fill(tileval->getData(), dst, dstride,
1153  _tileres.u()/nu, _tileres.v()/nv,
1154  _pixelsize);
1155  else
1156  _reducefn(tileval->getData(), sstride, ptileures, ptilevres,
1157  dst, dstride, _dt, _nchan);
1158  i++;
1159  dst += (i%nu) ? dstepu : dstepv;
1160  }
1161  }
1162 
1163  if (!AtomicCompareAndSwap(&face, (FaceData*)0, newface)) {
1164  delete newface;
1165  }
1166  else {
1167  _reader->increaseMemUsed(newMemUsed);
1168  }
1169 
1170  return face;
1171 }
1172 
const uint32_t Magic
Definition: PtexIO.h:99
const int FaceDataHeaderSize
Definition: PtexIO.h:103
const int ExtHeaderSize
Definition: PtexIO.h:101
const int AllocaMax
Definition: PtexIO.h:109
const int HeaderSize
Definition: PtexIO.h:100
const int LevelInfoSize
Definition: PtexIO.h:102
bool LittleEndian()
Definition: PtexIO.h:112
@ enc_diffzipped
Definition: PtexIO.h:81
@ enc_zipped
Definition: PtexIO.h:81
@ enc_constant
Definition: PtexIO.h:81
@ enc_tiled
Definition: PtexIO.h:81
Platform-specific classes, functions, and includes.
off_t FilePos
Definition: PtexPlatform.h:101
PTEX_INLINE void AtomicStore(T volatile *target, T value)
Definition: PtexPlatform.h:286
PTEX_INLINE bool AtomicCompareAndSwap(T volatile *target, T oldvalue, T newvalue)
Definition: PtexPlatform.h:280
void ConvertToFloat(float *dst, const void *src, DataType dt, int numChannels)
Definition: PtexUtils.cpp:123
#define PTEX_NAMESPACE_END
Definition: PtexVersion.h:62
Public API classes for reading, writing, caching, and filtering Ptex files.
Automatically acquire and release lock within enclosing scope.
Definition: PtexMutex.h:43
bool trylock()
Definition: PtexPlatform.h:144
void unlock()
Definition: PtexPlatform.h:145
Custom handler interface redirecting Ptex error messages.
Definition: Ptexture.h:667
virtual void reportError(const char *error)=0
Per-face texture data accessor.
Definition: Ptexture.h:409
virtual void * getData()=0
Access the data from this data block.
virtual PtexFaceData * getTile(int tile)=0
Access a tile from the data block.
virtual bool isConstant()=0
True if this data block is constant.
void clear()
Definition: PtexHashMap.h:187
Value get(Key &key) const
Definition: PtexHashMap.h:197
Value tryInsert(Key &key, Value value, size_t &newMemUsed)
Definition: PtexHashMap.h:220
Custom handler interface for intercepting and redirecting Ptex input stream calls.
Definition: Ptexture.h:628
virtual size_t read(void *buffer, size_t size, Handle handle)=0
Read a number of bytes from the file.
virtual const char * lastError()=0
Return the last error message encountered.
virtual Handle open(const char *path)=0
Open a file in read mode.
virtual bool close(Handle handle)=0
Close a file.
Meta data accessor.
Definition: Ptexture.h:331
Smart-pointer for acquiring and releasing API objects.
Definition: Ptexture.h:1067
T * get() const
Get pointer value.
Definition: Ptexture.h:1083
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)
Definition: PtexReader.cpp:950
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)=0
std::vector< FilePos > offsets
Definition: PtexReader.h:526
std::vector< FaceDataHeader > fdh
Definition: PtexReader.h:525
std::vector< FaceData * > faces
Definition: PtexReader.h:527
size_t memUsed()
Definition: PtexReader.h:540
void addEntry(uint8_t keysize, const char *key, uint8_t datatype, uint32_t datasize, const void *data, size_t &metaDataMemUsed)
Definition: PtexReader.h:249
PtexReader * _reader
Definition: PtexReader.h:341
void addLmdEntry(uint8_t keysize, const char *key, uint8_t datatype, uint32_t datasize, FilePos filepos, uint32_t zipsize, size_t &metaDataMemUsed)
Definition: PtexReader.h:258
Entry * getEntry(int index)
Definition: PtexReader.cpp:345
std::vector< Entry * > _entries
Definition: PtexReader.h:344
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)
Definition: PtexReader.cpp:933
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)
Definition: PtexReader.cpp:963
virtual void getPixel(int u, int v, void *result)
Read a single texel from the data block.
std::vector< FaceDataHeader > _fdh
Definition: PtexReader.h:496
void readTile(int tile, FaceData *&data)
Definition: PtexReader.cpp:567
std::vector< FilePos > _offsets
Definition: PtexReader.h:497
virtual PtexFaceData * getTile(int tile)
Access a tile from the data block.
void readLevelInfo()
Definition: PtexReader.cpp:300
ReductionMap _reductions
Definition: PtexReader.h:703
bool reopenFP()
Definition: PtexReader.cpp:242
DataType datatype() const
Definition: PtexReader.h:116
bool _premultiply
Definition: PtexReader.h:649
FilePos _constdatapos
Definition: PtexReader.h:659
void readMetaDataBlock(MetaData *metadata, FilePos pos, int zipsize, int memsize, size_t &metaDataMemUsed)
Definition: PtexReader.cpp:411
void readFaceInfo()
Definition: PtexReader.cpp:279
std::string _path
Definition: PtexReader.h:655
uint8_t * _constdata
Definition: PtexReader.h:666
std::vector< FilePos > _levelpos
Definition: PtexReader.h:672
virtual void getPixel(int faceid, int u, int v, float *result, int firstchan, int nchannels)
Access a single texel from the highest resolution texture .
Definition: PtexReader.cpp:825
void setIOError(const char *error)
Definition: PtexReader.h:564
FaceData * errorData(bool deleteOnRelease=false)
Definition: PtexReader.h:608
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition: PtexReader.h:57
void increaseMemUsed(size_t amount)
Definition: PtexReader.h:72
void computeFaceTileOffsets(FilePos pos, int noffsets, const FaceDataHeader *fdh, FilePos *offsets)
Definition: PtexReader.h:613
void purge()
Definition: PtexReader.cpp:117
FilePos tell()
Definition: PtexReader.h:569
virtual ~PtexReader()
Definition: PtexReader.cpp:94
FaceData * getFace(int levelid, Level *level, int faceid, Res res)
Definition: PtexReader.h:591
bool _needToOpen
Definition: PtexReader.h:651
void readConstData()
Definition: PtexReader.cpp:321
virtual PtexMetaData * getMetaData()
Access meta data.
Definition: PtexReader.cpp:337
bool needToOpen() const
Definition: PtexReader.h:58
ExtHeader _extheader
Definition: PtexReader.h:657
FilePos _leveldatapos
Definition: PtexReader.h:661
virtual void getData(int faceid, void *buffer, int stride)
Access texture data for a face at highest-resolution.
Definition: PtexReader.cpp:643
PtexErrorHandler * _err
Definition: PtexReader.h:648
FilePos _faceinfopos
Definition: PtexReader.h:658
std::vector< LevelInfo > _levelinfo
Definition: PtexReader.h:671
bool readBlock(void *data, int size)
Definition: PtexReader.cpp:466
PtexReader(bool premultiply, PtexInputHandler *inputHandler, PtexErrorHandler *errorHandler)
Definition: PtexReader.cpp:73
PtexInputHandler * _io
Definition: PtexReader.h:647
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
Definition: PtexReader.cpp:269
FilePos _metadatapos
Definition: PtexReader.h:662
void readLargeMetaDataHeaders(MetaData *metadata, FilePos pos, int zipsize, int memsize, size_t &metaDataMemUsed)
Definition: PtexReader.cpp:437
void closeFP()
Definition: PtexReader.cpp:233
int _pixelsize
Definition: PtexReader.h:665
bool _pendingPurge
Definition: PtexReader.h:652
Mutex readlock
Definition: PtexReader.h:645
void setError(const char *error, bool ioError=false)
Definition: PtexReader.h:549
Level * getLevel(int levelid)
Definition: PtexReader.h:584
void readFace(int levelid, Level *level, int faceid, Res res)
Definition: PtexReader.cpp:559
FilePos _levelinfopos
Definition: PtexReader.h:660
FilePos _lmdheaderpos
Definition: PtexReader.h:663
int nchannels() const
Definition: PtexReader.h:117
FilePos _lmddatapos
Definition: PtexReader.h:664
void prune()
Definition: PtexReader.cpp:106
std::vector< uint32_t > _rfaceids
Definition: PtexReader.h:670
volatile size_t _memUsed
Definition: PtexReader.h:708
Header _header
Definition: PtexReader.h:656
void readFaceData(FilePos pos, FaceDataHeader fdh, Res res, int levelid, FaceData *&face)
Definition: PtexReader.cpp:573
libdeflate_decompressor * _decompressor
Definition: PtexReader.h:706
void seek(FilePos pos)
Definition: PtexReader.h:570
MetaData * _metadata
Definition: PtexReader.h:667
std::vector< Level * > _levels
Definition: PtexReader.h:673
size_t _baseMemUsed
Definition: PtexReader.h:707
std::vector< FaceInfo > _faceinfo
Definition: PtexReader.h:669
PtexInputHandler::Handle _fp
Definition: PtexReader.h:653
bool readZipBlock(void *data, int zipsize, int unzipsize)
Definition: PtexReader.cpp:480
void getCompressedData(int faceid, int level, FaceDataHeader &fdh, std::vector< std::byte > &data)
Definition: PtexReader.cpp:892
void readMetaData()
Definition: PtexReader.cpp:383
void logOpen()
Definition: PtexReader.h:73
virtual void * getConstantData(int faceid) final
Access the constant (or average) data value for a given face.
Definition: PtexReader.h:108
void readLevel(int levelid, Level *&level)
Definition: PtexReader.cpp:499
std::vector< char > _errorPixel
Definition: PtexReader.h:704
FilePos _pos
Definition: PtexReader.h:654
bool open(const char *path, Ptex::String &error)
Definition: PtexReader.cpp:137
bool tryClose()
Definition: PtexReader.cpp:222
Interface for reading data from a ptex file.
Definition: Ptexture.h:460
virtual const char * path()=0
Path that file was opened with.
static PtexTexture * open(const char *path, Ptex::String &error, bool premultiply=0)
Open a ptex file for reading.
Definition: PtexReader.cpp:61
Memory-managed string.
Definition: Ptexture.h:299
const char * c_str() const
Definition: Ptexture.h:307
void decodeDifference(void *data, size_t size, DataType dt)
Definition: PtexUtils.cpp:271
void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
Definition: PtexUtils.cpp:630
void reduceu(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
Definition: PtexUtils.cpp:333
void reducev(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
Definition: PtexUtils.cpp:366
void fill(const void *src, void *dst, int dstride, int ures, int vres, int pixelsize)
Definition: PtexUtils.cpp:422
void reduceTri(const void *src, int sstride, int w, int, void *dst, int dstride, DataType dt, int nchan)
Definition: PtexUtils.cpp:406
void copy(const void *src, int sstride, void *dst, int dstride, int vres, int rowlen)
Definition: PtexUtils.cpp:438
void ReduceFn(const void *src, int sstride, int ures, int vres, void *dst, int dstride, DataType dt, int nchannels)
Definition: PtexUtils.h:167
void multalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Definition: PtexUtils.cpp:579
void interleave(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
Definition: PtexUtils.cpp:189
int DataSize(DataType dt)
Look up size of given data type (in bytes).
Definition: Ptexture.h:130
DataType
Type of data stored in texture file.
Definition: Ptexture.h:72
@ dt_float
Single-precision (32-bit) floating point.
Definition: Ptexture.h:76
@ mt_triangle
Mesh is triangle-based.
Definition: Ptexture.h:67
@ mt_quad
Mesh is quad-based.
Definition: Ptexture.h:68
uint64_t lmddatasize
Definition: PtexIO.h:71
uint32_t lmdheadermemsize
Definition: PtexIO.h:70
uint32_t lmdheaderzipsize
Definition: PtexIO.h:69
Encoding encoding() const
Definition: PtexIO.h:86
uint32_t blocksize() const
Definition: PtexIO.h:85
bool isLargeFace() const
Definition: PtexIO.h:94
Definition: PtexIO.h:44
uint32_t metadatamemsize
Definition: PtexIO.h:60
uint32_t faceinfosize
Definition: PtexIO.h:54
uint16_t nlevels
Definition: PtexIO.h:51
uint16_t nchannels
Definition: PtexIO.h:50
uint32_t meshtype
Definition: PtexIO.h:47
uint32_t constdatasize
Definition: PtexIO.h:55
uint32_t levelinfosize
Definition: PtexIO.h:56
uint32_t extheadersize
Definition: PtexIO.h:53
uint32_t metadatazipsize
Definition: PtexIO.h:59
int pixelSize() const
Definition: PtexIO.h:61
int32_t alphachan
Definition: PtexIO.h:49
uint32_t magic
Definition: PtexIO.h:45
uint32_t nfaces
Definition: PtexIO.h:52
uint64_t leveldatasize
Definition: PtexIO.h:58
uint32_t version
Definition: PtexIO.h:46
bool hasAlpha() const
Definition: PtexIO.h:62
uint32_t levelheadersize
Definition: PtexIO.h:77
uint32_t nfaces
Definition: PtexIO.h:78
LargeMetaData * lmdData
Definition: PtexReader.h:293
Information about a face, as stored in the Ptex file header.
Definition: Ptexture.h:232
Pixel resolution of a given texture.
Definition: Ptexture.h:159