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