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