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