42#include <libdeflate.h>
53 virtual void reportError(
const char* error) {
56 const std::string& getErrorString()
const {
return _error; }
101 for (std::vector<Level*>::iterator i =
_levels.begin(); i !=
_levels.end(); ++i) {
110 for (std::vector<Level*>::iterator i =
_levels.begin(); i !=
_levels.end(); ++i) {
111 if (*i) {
delete *i; *i = 0; }
127 std::vector<Level*>().swap(
_levels);
143 auto openError = [&](
const std::string& msg) ->
bool {
151 error =
"Ptex library doesn't currently support big-endian cpu's";
157 std::string errstr =
"Can't open ptex file: ";
158 errstr += pathArg; errstr +=
"\n"; errstr +=
_io->
lastError();
159 error = errstr.c_str();
166 return openError(std::string(
"Not a ptex file: ") + pathArg);
170 s <<
"Unsupported ptex file version (" <<
_header.
version <<
"): " << pathArg;
171 return openError(s.str());
176 return openError(s.str());
181 return openError(s.str());
184 return openError(std::string(
"Invalid number of channels (0): ") + pathArg);
187 return openError(std::string(
"Invalid number of faces (0): ") + pathArg);
190 return openError(std::string(
"Invalid number of levels (0): ") + pathArg);
193 return openError(std::string(
"Invalid face info size (0): ") + pathArg);
196 return openError(std::string(
"Inconsistent level info size: ") + pathArg);
203 static const uint64_t MaxDeflateExpansion = 1032;
207 return openError(std::string(
"Unreasonable face count: ") + pathArg);
211 return openError(std::string(
"Unreasonable constdata size: ") + pathArg);
215 return openError(std::string(
"Unreasonable metadata size: ") + pathArg);
220 TempErrorHandler tempErr;
235 pos +=
sizeof(uint64_t);
250 error = tempErr.getErrorString();
280 if (
_fp)
return true;
292 memset(&extheaderval, 0,
sizeof(extheaderval));
294 if (0 != memcmp(&headerval, &
_header,
sizeof(headerval)) ||
295 0 != memcmp(&extheaderval, &
_extheader,
sizeof(extheaderval)))
297 setError(
"Header mismatch on reopen of");
307 if (faceid >= 0 && uint32_t(faceid) <
_faceinfo.size())
321 int64_t faceInfoSize64 = (int64_t)
sizeof(FaceInfo) * nfaces;
322 if (faceInfoSize64 > INT_MAX) {
323 setError(
"PtexReader error: faceinfo size overflow");
331 std::vector<uint32_t> faceids_r(nfaces);
367 if (size64 > INT_MAX) {
368 setError(
"PtexReader error: constdata size overflow");
371 int size = (int)size64;
392 if (index < 0 || index >=
int(
_entries.size())) {
438 size_t metaDataMemUsed =
sizeof(
MetaData);
461 char* buff = useNew ?
new char[memsize] : (
char*)alloca(memsize);
466 char* end = ptr + memsize;
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);
478 if (useNew)
delete [] buff;
487 char* buff = useNew ?
new char [memsize] : (
char*)alloca(memsize);
494 char* end = ptr + memsize;
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);
507 if (useNew)
delete [] buff;
513 assert(
_fp && size >= 0);
514 if (!
_fp || size < 0)
return false;
516 if (result == size) {
527 if (!
_ok || zipsize < 0 || unzipsize < 0)
return false;
528 std::vector<std::byte> compressedBuffer(zipsize);
529 if (!
readBlock(compressedBuffer.data(), compressedBuffer.size())) {
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))
537 setError(
"PtexReader error: unzip failed, file corrupt");
563 std::vector<uint32_t> largeFaces;
565 for (uint32_t f = 0; f < l.
nfaces; f++) {
567 if (!newlevel->
fdh[f].isLargeFace()) {
568 offset += newlevel->
fdh[f].blocksize();
571 largeFaces.push_back(f);
576 if (!largeFaces.empty()) {
577 int nlarge = int(largeFaces.size());
579 std::vector<size_t> largeFaceHeader(nlarge);
580 size_t largeFaceHeaderSize =
sizeof(size_t) * nlarge;
581 readBlock(largeFaceHeader.data(), largeFaceHeaderSize);
584 size_t extraOffset = largeFaceHeaderSize;
586 for (
int i = 0; i < nlarge; i++) {
587 uint32_t lf = largeFaces[i];
589 newlevel->
offsets[f++] += extraOffset;
591 extraOffset += largeFaceHeader[i];
594 newlevel->
offsets[f++] += extraOffset;
628 size_t newMemUsed = 0;
647 uint32_t tileheadersize;
648 readBlock(&tileheadersize,
sizeof(tileheadersize));
659 int uw = res.u(), vw = res.v();
660 int npixels = uw * vw;
664 newMemUsed =
sizeof(
PackedFace) + unpackedSize;
666 char* tmp = useNew ?
new char [unpackedSize] : (
char*) alloca(unpackedSize);
676 if (useNew)
delete [] tmp;
691 getData(faceid, buffer, stride, f.res);
703 int resu = res.u(), resv = res.v();
705 if (stride == 0) stride = rowlen;
708 if (d->isConstant()) {
713 else if (d->isTiled()) {
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();
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++) {
732 tilevres, tilerowlen);
733 dsttile += tilerowlen;
735 dsttilerow += stride * tilevres;
751 if (fi.isConstant() || fi.res == 0) {
769 if (fi.isConstant() || res == 0) {
774 int redu = fi.res.ulog2 - res.ulog2, redv = fi.res.vlog2 - res.vlog2;
776 if (redu == 0 && redv == 0) {
787 if (
size_t(levelid) <
_levels.size()) {
795 if (
size_t(rfaceid) < level->
faces.size()) {
796 face =
getFace(levelid, level, rfaceid, res);
813 size_t newMemUsed = 0;
815 if (res.ulog2 < 0 || res.vlog2 < 0) {
816 std::cerr <<
"PtexReader::getData - reductions below 1 pixel not supported" << std::endl;
819 else if (redu < 0 || redv < 0) {
820 std::cerr <<
"PtexReader::getData - enlargements not supported" << std::endl;
826 std::cerr <<
"PtexReader::getData - anisotropic reductions not supported for triangle mesh" << std::endl;
840 blendu = (res.ulog2 & 1);
842 else blendu = redu > redv;
858 size_t tableNewMemUsed = 0;
860 if (face != newface) {
871 float* result,
int firstchan,
int nchannelsArg)
873 memset(result, 0,
sizeof(*result)*nchannelsArg);
877 if (nchannelsArg <= 0)
return;
887 data->getPixel(u, v, pixel);
891 int datasize = DataSize(
datatype());
893 pixel = (
char*) pixel + datasize * firstchan;
897 memcpy(result, pixel, datasize * nchannelsArg);
904 float* result,
int firstchan,
int nchannelsArg,
907 memset(result, 0,
sizeof(*result)*nchannelsArg);
911 if (nchannelsArg <= 0)
return;
921 data->getPixel(u, v, pixel);
925 int datasize = DataSize(
datatype());
927 pixel = (
char*) pixel + datasize * firstchan;
931 memcpy(result, pixel, datasize * nchannelsArg);
944 int rfaceid = levelid == 0 ? faceid :
_rfaceids[faceid];
945 fdh = level->
fdh[rfaceid];
954 Res level_res(fi.res.ulog2 - levelid, fi.res.vlog2 - levelid);
957 uint32_t tileheadersize;
958 readBlock(&tileheadersize,
sizeof(tileheadersize));
959 int ntiles = level_res.ntiles(tileres);
960 std::vector<FaceDataHeader> tiledFace_fdh(ntiles);
964 size =
sizeof(tileres) +
sizeof(tileheadersize) + tileheadersize;
965 for (
auto fdh : tiledFace_fdh) {
1030 newtileres = newres;
1036 if (newtileres.ulog2 > newres.ulog2) newtileres.ulog2 = newres.ulog2;
1037 if (newtileres.vlog2 > newres.vlog2) newtileres.vlog2 = newres.vlog2;
1042 int newntiles = newres.ntiles(newtileres);
1044 if (newntiles == 1) {
1048 bool allConstant =
true;
1049 for (
int i = 0; i <
_ntiles; i++) {
1051 allConstant = (allConstant && tile->
isConstant() &&
1061 else if (isTriangle) {
1068 int dstepv = dstride * tilevres - sstride*(
_ntilesu-1);
1072 for (
int i = 0; i <
_ntiles;) {
1080 tmpptr += (i%
_ntilesu) ? sstride : dstepv;
1106 char* dst = (
char*) newface->
getData();
1107 for (
int i = 0; i <
_ntiles;) {
1114 reducefn(tile->
getData(), sstride, tileures, tilevres,
1117 dst += (i%
_ntilesu) ? dstepu : dstepv;
1138 tile->getPixel(ui - (tileu<<
_tileres.ulog2),
1139 vi - (tilev<<
_tileres.vlog2), result);
1158 int ntilesval = nu*nv;
1160 bool allConstant =
true;
1162 for (
int i = 0; i < ntilesval;) {
1164 allConstant = (allConstant && tileval->
isConstant() &&
1168 ptile += (i%nu)? 1 : pntilesu - nu + 1;
1172 size_t newMemUsed = 0;
1190 int dstepu = dstride/nu;
1191 int dstepv = dstride*
_tileres.v()/nv - dstepu*(nu-1);
1193 char* dst = (
char*) newface->
getData();
1194 for (
int i = 0; i < ntilesval;) {
1204 dst += (i%nu) ? dstepu : dstepv;
1212 _reader->increaseMemUsed(newMemUsed);
const int FaceDataHeaderSize
AutoLock< Mutex > AutoMutex
void ConvertToFloat(float *dst, const void *src, DataType dt, int numChannels)
#define PTEX_NAMESPACE_END
Public API classes for reading, writing, caching, and filtering Ptex files.
Custom handler interface redirecting Ptex error messages.
Per-face texture data accessor.
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)
Smart-pointer for acquiring and releasing API objects.
T * get() const
Get pointer value.
ConstDataPtr(void *data, int pixelsize)
ConstantFace(int pixelsize)
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
std::vector< FaceDataHeader > fdh
std::vector< FaceData * > faces
PackedFace(Res resArg, int pixelsize, int size)
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)
std::vector< FaceData * > _tiles
virtual FaceData * reduce(PtexReader *, Res newres, PtexUtils::ReduceFn, size_t &newMemUsed)
virtual void * getData()
Access the data from this data block.
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
virtual void getPixel(int u, int v, void *result)
Read a single texel from the data block.
std::vector< FaceDataHeader > _fdh
TiledFace(PtexReader *reader, Res resArg, Res tileresArg, int levelid)
void readTile(int tile, FaceData *&data)
std::vector< FilePos > _offsets
TiledFaceBase * _parentface
virtual PtexFaceData * getTile(int tile)
Access a tile from the data block.
PtexUtils::ReduceFn * _reducefn
TiledReducedFace(PtexReader *reader, Res resArg, Res tileresArg, TiledFaceBase *parentface, PtexUtils::ReduceFn reducefn)
DataType datatype() const
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.
std::vector< FilePos > _levelpos
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)
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
void increaseMemUsed(size_t amount)
void computeFaceTileOffsets(FilePos pos, int noffsets, const FaceDataHeader *fdh, FilePos *offsets)
FaceData * getFace(int levelid, Level *level, int faceid, Res res)
Level * getLevel(int levelid)
FaceData * errorData(bool deleteOnRelease=false)
virtual PtexMetaData * getMetaData()
Access meta data.
virtual void getData(int faceid, void *buffer, int stride)
Access texture data for a face at highest-resolution.
std::vector< LevelInfo > _levelinfo
bool readBlock(void *data, int size)
PtexReader(bool premultiply, PtexInputHandler *inputHandler, PtexErrorHandler *errorHandler)
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
void readLargeMetaDataHeaders(MetaData *metadata, FilePos pos, int zipsize, int memsize, size_t &metaDataMemUsed)
void setError(const char *error, bool ioError=false)
void readFace(int levelid, Level *level, int faceid, Res res)
std::vector< uint32_t > _rfaceids
DefaultInputHandler _defaultIo
volatile size_t _blockReads
void readFaceData(FilePos pos, FaceDataHeader fdh, Res res, int levelid, FaceData *&face)
libdeflate_decompressor * _decompressor
std::vector< Level * > _levels
std::vector< FaceInfo > _faceinfo
PtexInputHandler::Handle _fp
bool readZipBlock(void *data, int zipsize, int unzipsize)
void getCompressedData(int faceid, int level, FaceDataHeader &fdh, std::vector< std::byte > &data)
void readLevel(int levelid, Level *&level)
std::vector< char > _errorPixel
bool open(const char *path, Ptex::String &error)
Interface for reading data from a ptex file.
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.
const char * c_str() const
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)
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)
Information about a face, as stored in the Ptex file header.
Pixel resolution of a given texture.