Ptex
PtexReader.cpp
Go to the documentation of this file.
1/*
2PTEX SOFTWARE
3Copyright 2014 Disney Enterprises, Inc. All rights reserved
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
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
22Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
23CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
25FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
26IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
27CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
31THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33OF 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
48namespace {
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
62PtexTexture* 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)),
88 _opens(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 }
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
141bool 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 }
176 if (!(_header.meshtype == mt_triangle || _header.meshtype == mt_quad)) {
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 }
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));
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;
238 pos += sizeof(uint64_t); // compatibility barrier
240 _lmddatapos = pos; pos += _extheader.lmddatasize;
241
242 // read basic file info
243 readFaceInfo();
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();
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);
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);
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];
380 increaseMemUsed(size);
381 }
382}
383
384
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
447
448 // read large meta data headers
452
453 // store meta data
454 AtomicStore(&_metadata, newmeta);
455 increaseMemUsed(newmeta->selfDataSize() + metaDataMemUsed);
456}
457
458
459void 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
485void 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
514bool 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
528bool 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
547void 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
607void 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
621void 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())
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
691void 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
698void 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
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
873void 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
906void 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
940void 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
1136void 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
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
AutoLock< Mutex > AutoMutex
Definition PtexMutex.h:51
Platform-specific classes, functions, and includes.
off_t FilePos
PTEX_INLINE void AtomicStore(T volatile *target, T value)
PTEX_INLINE bool AtomicCompareAndSwap(T volatile *target, T oldvalue, T newvalue)
void ConvertToFloat(float *dst, const void *src, DataType dt, int numChannels)
#define PTEX_NAMESPACE_END
Definition PtexVersion.h:62
Public API classes for reading, writing, caching, and filtering Ptex files.
bool trylock()
void unlock()
Custom handler interface redirecting Ptex error messages.
Definition Ptexture.h:667
Per-face texture data accessor.
Definition Ptexture.h:409
virtual PtexFaceData * getTile(int tile)=0
Access a tile from the data block.
virtual bool isConstant()=0
True if this data block is constant.
virtual void * getData()=0
Access the data from this data block.
Value get(Key &key) const
Value tryInsert(Key &key, Value value, size_t &newMemUsed)
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
ConstDataPtr(void *data, int pixelsize)
Definition PtexReader.h:350
ConstantFace(int pixelsize)
Definition PtexReader.h:406
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)=0
FaceData(Res resArg)
Definition PtexReader.h:370
Level(int nfaces)
Definition PtexReader.h:529
std::vector< FilePos > offsets
Definition PtexReader.h:526
std::vector< FaceDataHeader > fdh
Definition PtexReader.h:525
std::vector< FaceData * > faces
Definition PtexReader.h:527
void addEntry(uint8_t keysize, const char *key, uint8_t datatype, uint32_t datasize, const void *data, size_t &metaDataMemUsed)
Definition PtexReader.h:249
MetaData(PtexReader *reader)
Definition PtexReader.h:125
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)
std::vector< Entry * > _entries
Definition PtexReader.h:344
PackedFace(Res resArg, int pixelsize, int size)
Definition PtexReader.h:382
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)
std::vector< FaceData * > _tiles
Definition PtexReader.h:469
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)
virtual void * getData()
Access the data from this data block.
Definition PtexReader.h:443
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition PtexReader.h:440
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
TiledFace(PtexReader *reader, Res resArg, Res tileresArg, int levelid)
Definition PtexReader.h:475
void readTile(int tile, FaceData *&data)
std::vector< FilePos > _offsets
Definition PtexReader.h:497
TiledFaceBase * _parentface
Definition PtexReader.h:518
virtual PtexFaceData * getTile(int tile)
Access a tile from the data block.
PtexUtils::ReduceFn * _reducefn
Definition PtexReader.h:519
TiledReducedFace(PtexReader *reader, Res resArg, Res tileresArg, TiledFaceBase *parentface, PtexUtils::ReduceFn reducefn)
Definition PtexReader.h:503
void readLevelInfo()
ReductionMap _reductions
Definition PtexReader.h:703
bool reopenFP()
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)
virtual void * getConstantData(int faceid) final
Access the constant (or average) data value for a given face.
Definition PtexReader.h:108
void readFaceInfo()
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 .
void setIOError(const char *error)
Definition PtexReader.h:564
volatile size_t _opens
Definition PtexReader.h:709
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
FaceData * getFace(int levelid, Level *level, int faceid, Res res)
Definition PtexReader.h:591
FilePos tell()
Definition PtexReader.h:569
Level * getLevel(int levelid)
Definition PtexReader.h:584
FaceData * errorData(bool deleteOnRelease=false)
Definition PtexReader.h:608
virtual ~PtexReader()
bool _needToOpen
Definition PtexReader.h:651
void readConstData()
virtual PtexMetaData * getMetaData()
Access meta data.
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.
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)
PtexReader(bool premultiply, PtexInputHandler *inputHandler, PtexErrorHandler *errorHandler)
PtexInputHandler * _io
Definition PtexReader.h:647
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
FilePos _metadatapos
Definition PtexReader.h:662
void readLargeMetaDataHeaders(MetaData *metadata, FilePos pos, int zipsize, int memsize, size_t &metaDataMemUsed)
void closeFP()
bool _pendingPurge
Definition PtexReader.h:652
Mutex readlock
Definition PtexReader.h:645
void setError(const char *error, bool ioError=false)
Definition PtexReader.h:549
void readFace(int levelid, Level *level, int faceid, Res res)
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
std::vector< uint32_t > _rfaceids
Definition PtexReader.h:670
volatile size_t _memUsed
Definition PtexReader.h:708
DefaultInputHandler _defaultIo
Definition PtexReader.h:646
volatile size_t _blockReads
Definition PtexReader.h:710
Header _header
Definition PtexReader.h:656
void readFaceData(FilePos pos, FaceDataHeader fdh, Res res, int levelid, FaceData *&face)
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
int pixelsize() const
Definition PtexReader.h:118
PtexInputHandler::Handle _fp
Definition PtexReader.h:653
bool readZipBlock(void *data, int zipsize, int unzipsize)
void getCompressedData(int faceid, int level, FaceDataHeader &fdh, std::vector< std::byte > &data)
void readMetaData()
void logOpen()
Definition PtexReader.h:73
void readLevel(int levelid, Level *&level)
std::vector< char > _errorPixel
Definition PtexReader.h:704
FilePos _pos
Definition PtexReader.h:654
bool open(const char *path, Ptex::String &error)
bool tryClose()
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.
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)
void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
void reduceu(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
void reducev(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
void fill(const void *src, void *dst, int dstride, int ures, int vres, int pixelsize)
void reduceTri(const void *src, int sstride, int w, int, void *dst, int dstride, DataType dt, int nchan)
void copy(const void *src, int sstride, void *dst, int dstride, int vres, int rowlen)
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)
void interleave(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
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
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
uint32_t datatype
Definition PtexIO.h:48
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
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