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);
146 auto openError = [&](
const std::string& msg) ->
bool {
154 error =
"Ptex library doesn't currently support big-endian cpu's";
160 std::string errstr =
"Can't open ptex file: ";
161 errstr += pathArg; errstr +=
"\n"; errstr +=
_io->
lastError();
162 error = errstr.c_str();
169 return openError(std::string(
"Not a ptex file: ") + pathArg);
173 s <<
"Unsupported ptex file version (" <<
_header.
version <<
"): " << pathArg;
174 return openError(s.str());
179 return openError(s.str());
184 return openError(s.str());
187 return openError(std::string(
"Invalid number of channels (0): ") + pathArg);
190 return openError(std::string(
"Invalid number of faces (0): ") + pathArg);
193 return openError(std::string(
"Invalid number of levels (0): ") + pathArg);
196 return openError(std::string(
"Invalid face info size (0): ") + pathArg);
199 return openError(std::string(
"Inconsistent level info size: ") + pathArg);
206 static const uint64_t MaxDeflateExpansion = 1032;
210 return openError(std::string(
"Unreasonable face count: ") + pathArg);
214 return openError(std::string(
"Unreasonable constdata size: ") + pathArg);
218 return openError(std::string(
"Unreasonable metadata size: ") + pathArg);
223 TempErrorHandler tempErr;
238 pos +=
sizeof(uint64_t);
253 error = tempErr.getErrorString();
283 if (
_fp)
return true;
295 memset(&extheaderval, 0,
sizeof(extheaderval));
297 if (0 != memcmp(&headerval, &
_header,
sizeof(headerval)) ||
298 0 != memcmp(&extheaderval, &
_extheader,
sizeof(extheaderval)))
300 setError(
"Header mismatch on reopen of");
310 if (faceid >= 0 && uint32_t(faceid) <
_faceinfo.size())
324 int64_t faceInfoSize64 = (int64_t)
sizeof(FaceInfo) * nfaces;
325 if (faceInfoSize64 > INT_MAX) {
326 setError(
"PtexReader error: faceinfo size overflow");
334 std::vector<uint32_t> faceids_r(nfaces);
370 if (size64 > INT_MAX) {
371 setError(
"PtexReader error: constdata size overflow");
374 int size = (int)size64;
395 if (index < 0 || index >=
int(
_entries.size())) {
441 size_t metaDataMemUsed =
sizeof(
MetaData);
464 char* buff = useNew ?
new char[memsize] : (
char*)alloca(memsize);
469 char* end = ptr + memsize;
471 uint8_t keysize = *ptr++;
472 char* key = (
char*)ptr; ptr += keysize;
473 key[keysize-1] =
'\0';
474 uint8_t datatypeval = *ptr++;
475 uint32_t datasize; memcpy(&datasize, ptr,
sizeof(datasize));
476 ptr +=
sizeof(datasize);
477 char* data = ptr; ptr += datasize;
478 metadata->
addEntry((uint8_t)(keysize-1), key, datatypeval, datasize, data, metaDataMemUsed);
481 if (useNew)
delete [] buff;
490 char* buff = useNew ?
new char [memsize] : (
char*)alloca(memsize);
497 char* end = ptr + memsize;
499 uint8_t keysize = *ptr++;
500 char* key = (
char*)ptr; ptr += keysize;
501 uint8_t datatypeval = *ptr++;
502 uint32_t datasize; memcpy(&datasize, ptr,
sizeof(datasize));
503 ptr +=
sizeof(datasize);
504 uint32_t zipsizeval; memcpy(&zipsizeval, ptr,
sizeof(zipsizeval));
505 ptr +=
sizeof(zipsizeval);
506 metadata->
addLmdEntry((uint8_t)(keysize-1), key, datatypeval, datasize, pos, zipsizeval, metaDataMemUsed);
510 if (useNew)
delete [] buff;
516 assert(
_fp && size >= 0);
517 if (!
_fp || size < 0)
return false;
519 if (result == size) {
530 if (!
_ok || zipsize < 0 || unzipsize < 0)
return false;
531 std::vector<std::byte> compressedBuffer(zipsize);
532 if (!
readBlock(compressedBuffer.data(), compressedBuffer.size())) {
535 size_t bytesDecompressed{0};
536 if (libdeflate_zlib_decompress(
_decompressor, compressedBuffer.data(), compressedBuffer.size(),
537 data, unzipsize, &bytesDecompressed) != 0 ||
538 bytesDecompressed !=
size_t(unzipsize))
540 setError(
"PtexReader error: unzip failed, file corrupt");
566 std::vector<uint32_t> largeFaces;
568 for (uint32_t f = 0; f < l.
nfaces; f++) {
570 if (!newlevel->
fdh[f].isLargeFace()) {
571 offset += newlevel->
fdh[f].blocksize();
574 largeFaces.push_back(f);
579 if (!largeFaces.empty()) {
580 int nlarge = int(largeFaces.size());
582 std::vector<size_t> largeFaceHeader(nlarge);
583 size_t largeFaceHeaderSize =
sizeof(size_t) * nlarge;
584 readBlock(largeFaceHeader.data(), largeFaceHeaderSize);
587 size_t extraOffset = largeFaceHeaderSize;
589 for (
int i = 0; i < nlarge; i++) {
590 uint32_t lf = largeFaces[i];
592 newlevel->
offsets[f++] += extraOffset;
594 extraOffset += largeFaceHeader[i];
597 newlevel->
offsets[f++] += extraOffset;
631 size_t newMemUsed = 0;
650 uint32_t tileheadersize;
651 readBlock(&tileheadersize,
sizeof(tileheadersize));
662 int uw = res.u(), vw = res.v();
663 int npixels = uw * vw;
667 newMemUsed =
sizeof(
PackedFace) + unpackedSize;
669 char* tmp = useNew ?
new char [unpackedSize] : (
char*) alloca(unpackedSize);
679 if (useNew)
delete [] tmp;
694 getData(faceid, buffer, stride, f.res);
706 int resu = res.u(), resv = res.v();
708 if (stride == 0) stride = rowlen;
711 if (d->isConstant()) {
716 else if (d->isTiled()) {
718 Res tileres = d->tileRes();
719 int ntilesu = res.ntilesu(tileres);
720 int ntilesv = res.ntilesv(tileres);
721 int tileures = tileres.u();
722 int tilevres = tileres.v();
725 char* dsttilerow = (
char*) buffer;
726 for (
int i = 0; i < ntilesv; i++) {
727 char* dsttile = dsttilerow;
728 for (
int j = 0; j < ntilesu; j++) {
735 tilevres, tilerowlen);
736 dsttile += tilerowlen;
738 dsttilerow += stride * tilevres;
754 if (fi.isConstant() || fi.res == 0) {
772 if (fi.isConstant() || res == 0) {
777 int redu = fi.res.ulog2 - res.ulog2, redv = fi.res.vlog2 - res.vlog2;
779 if (redu == 0 && redv == 0) {
790 if (
size_t(levelid) <
_levels.size()) {
798 if (
size_t(rfaceid) < level->
faces.size()) {
799 face =
getFace(levelid, level, rfaceid, res);
816 size_t newMemUsed = 0;
818 if (res.ulog2 < 0 || res.vlog2 < 0) {
819 std::cerr <<
"PtexReader::getData - reductions below 1 pixel not supported" << std::endl;
822 else if (redu < 0 || redv < 0) {
823 std::cerr <<
"PtexReader::getData - enlargements not supported" << std::endl;
829 std::cerr <<
"PtexReader::getData - anisotropic reductions not supported for triangle mesh" << std::endl;
843 blendu = (res.ulog2 & 1);
845 else blendu = redu > redv;
861 size_t tableNewMemUsed = 0;
863 if (face != newface) {
874 float* result,
int firstchan,
int nchannelsArg)
876 memset(result, 0,
sizeof(*result)*nchannelsArg);
880 if (nchannelsArg <= 0)
return;
890 data->getPixel(u, v, pixel);
894 int datasize = DataSize(
datatype());
896 pixel = (
char*) pixel + datasize * firstchan;
900 memcpy(result, pixel, datasize * nchannelsArg);
907 float* result,
int firstchan,
int nchannelsArg,
910 memset(result, 0,
sizeof(*result)*nchannelsArg);
914 if (nchannelsArg <= 0)
return;
924 data->getPixel(u, v, pixel);
928 int datasize = DataSize(
datatype());
930 pixel = (
char*) pixel + datasize * firstchan;
934 memcpy(result, pixel, datasize * nchannelsArg);
947 int rfaceid = levelid == 0 ? faceid :
_rfaceids[faceid];
948 fdh = level->
fdh[rfaceid];
957 Res level_res(fi.res.ulog2 - levelid, fi.res.vlog2 - levelid);
960 uint32_t tileheadersize;
961 readBlock(&tileheadersize,
sizeof(tileheadersize));
962 int ntiles = level_res.ntiles(tileres);
963 std::vector<FaceDataHeader> tiledFace_fdh(ntiles);
967 size =
sizeof(tileres) +
sizeof(tileheadersize) + tileheadersize;
968 for (
auto fdh : tiledFace_fdh) {
1033 newtileres = newres;
1039 if (newtileres.ulog2 > newres.ulog2) newtileres.ulog2 = newres.ulog2;
1040 if (newtileres.vlog2 > newres.vlog2) newtileres.vlog2 = newres.vlog2;
1045 int newntiles = newres.ntiles(newtileres);
1047 if (newntiles == 1) {
1051 bool allConstant =
true;
1052 for (
int i = 0; i <
_ntiles; i++) {
1054 allConstant = (allConstant && tile->
isConstant() &&
1064 else if (isTriangle) {
1071 int dstepv = dstride * tilevres - sstride*(
_ntilesu-1);
1075 for (
int i = 0; i <
_ntiles;) {
1083 tmpptr += (i%
_ntilesu) ? sstride : dstepv;
1109 char* dst = (
char*) newface->
getData();
1110 for (
int i = 0; i <
_ntiles;) {
1117 reducefn(tile->
getData(), sstride, tileures, tilevres,
1120 dst += (i%
_ntilesu) ? dstepu : dstepv;
1141 tile->getPixel(ui - (tileu<<
_tileres.ulog2),
1142 vi - (tilev<<
_tileres.vlog2), result);
1161 int ntilesval = nu*nv;
1163 bool allConstant =
true;
1165 for (
int i = 0; i < ntilesval;) {
1167 allConstant = (allConstant && tileval->
isConstant() &&
1171 ptile += (i%nu)? 1 : pntilesu - nu + 1;
1175 size_t newMemUsed = 0;
1193 int dstepu = dstride/nu;
1194 int dstepv = dstride*
_tileres.v()/nv - dstepu*(nu-1);
1196 char* dst = (
char*) newface->
getData();
1197 for (
int i = 0; i < ntilesval;) {
1207 dst += (i%nu) ? dstepu : dstepv;
1215 _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.