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