41 #include <libdeflate.h>
55 const std::string& getErrorString()
const {
return _error; }
74 : _io(io ? io : &_defaultIo),
76 _premultiply(premultiply),
85 _baseMemUsed(sizeof(*this)),
86 _memUsed(_baseMemUsed),
100 for (std::vector<Level*>::iterator i =
_levels.begin(); i !=
_levels.end(); ++i) {
109 for (std::vector<Level*>::iterator i =
_levels.begin(); i !=
_levels.end(); ++i) {
110 if (*i) {
delete *i; *i = 0; }
126 std::vector<Level*>().swap(
_levels);
143 error =
"Ptex library doesn't currently support big-endian cpu's";
149 std::string errstr =
"Can't open ptex file: ";
150 errstr += pathArg; errstr +=
"\n"; errstr +=
_io->
lastError();
151 error = errstr.
c_str();
158 std::string errstr =
"Not a ptex file: "; errstr += pathArg;
159 error = errstr.
c_str();
166 s <<
"Unsupported ptex file version ("<<
_header.
version <<
"): " << pathArg;
184 TempErrorHandler tempErr;
199 pos +=
sizeof(uint64_t);
214 error = tempErr.getErrorString();
244 if (
_fp)
return true;
256 memset(&extheaderval, 0,
sizeof(extheaderval));
258 if (0 != memcmp(&headerval, &
_header,
sizeof(headerval)) ||
259 0 != memcmp(&extheaderval, &
_extheader,
sizeof(extheaderval)))
261 setError(
"Header mismatch on reopen of");
271 if (faceid >= 0 && uint32_t(faceid) <
_faceinfo.size())
287 (
int)(
sizeof(FaceInfo)*nfaces));
291 std::vector<uint32_t> faceids_r(nfaces);
347 if (index < 0 || index >=
int(
_entries.size())) {
393 size_t metaDataMemUsed =
sizeof(
MetaData);
416 char* buff = useNew ?
new char[memsize] : (
char*)alloca(memsize);
421 char* end = ptr + memsize;
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);
433 if (useNew)
delete [] buff;
442 char* buff = useNew ?
new char [memsize] : (
char*)alloca(memsize);
449 char* end = ptr + memsize;
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);
462 if (useNew)
delete [] buff;
468 assert(
_fp && size >= 0);
469 if (!
_fp || size < 0)
return false;
471 if (result == size) {
482 if (!
_ok || zipsize < 0 || unzipsize < 0)
return false;
483 std::vector<std::byte> compressedBuffer(zipsize);
484 if (!
readBlock(compressedBuffer.data(), compressedBuffer.size())) {
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))
492 setError(
"PtexReader error: unzip failed, file corrupt");
518 std::vector<uint32_t> largeFaces;
520 for (uint32_t f = 0; f < l.
nfaces; f++) {
522 if (!newlevel->
fdh[f].isLargeFace()) {
523 offset += newlevel->
fdh[f].blocksize();
526 largeFaces.push_back(f);
531 if (!largeFaces.empty()) {
532 int nlarge = int(largeFaces.size());
534 std::vector<size_t> largeFaceHeader(nlarge);
535 size_t largeFaceHeaderSize =
sizeof(size_t) * nlarge;
536 readBlock(largeFaceHeader.data(), largeFaceHeaderSize);
539 size_t extraOffset = largeFaceHeaderSize;
541 for (
int i = 0; i < nlarge; i++) {
542 uint32_t lf = largeFaces[i];
544 newlevel->
offsets[f++] += extraOffset;
546 extraOffset += largeFaceHeader[i];
549 newlevel->
offsets[f++] += extraOffset;
569 _reader->readFaceData(_offsets[tile], _fdh[tile], _tileres, _levelid, data);
583 size_t newMemUsed = 0;
602 uint32_t tileheadersize;
603 readBlock(&tileheadersize,
sizeof(tileheadersize));
614 int uw = res.u(), vw = res.v();
615 int npixels = uw * vw;
619 newMemUsed =
sizeof(
PackedFace) + unpackedSize;
621 char* tmp = useNew ?
new char [unpackedSize] : (
char*) alloca(unpackedSize);
631 if (useNew)
delete [] tmp;
646 getData(faceid, buffer, stride, f.res);
658 int resu = res.u(), resv = res.v();
660 if (stride == 0) stride = rowlen;
663 if (d->isConstant()) {
668 else if (d->isTiled()) {
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();
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++) {
687 tilevres, tilerowlen);
688 dsttile += tilerowlen;
690 dsttilerow += stride * tilevres;
706 if (fi.isConstant() || fi.res == 0) {
724 if (fi.isConstant() || res == 0) {
729 int redu = fi.res.ulog2 - res.ulog2, redv = fi.res.vlog2 - res.vlog2;
731 if (redu == 0 && redv == 0) {
742 if (
size_t(levelid) <
_levels.size()) {
750 if (
size_t(rfaceid) < level->
faces.size()) {
751 face =
getFace(levelid, level, rfaceid, res);
768 size_t newMemUsed = 0;
770 if (res.ulog2 < 0 || res.vlog2 < 0) {
771 std::cerr <<
"PtexReader::getData - reductions below 1 pixel not supported" << std::endl;
774 else if (redu < 0 || redv < 0) {
775 std::cerr <<
"PtexReader::getData - enlargements not supported" << std::endl;
781 std::cerr <<
"PtexReader::getData - anisotropic reductions not supported for triangle mesh" << std::endl;
795 blendu = (res.ulog2 & 1);
797 else blendu = redu > redv;
813 size_t tableNewMemUsed = 0;
815 if (face != newface) {
826 float* result,
int firstchan,
int nchannelsArg)
828 memset(result, 0,
sizeof(*result)*nchannelsArg);
832 if (nchannelsArg <= 0)
return;
842 data->getPixel(u, v, pixel);
848 pixel = (
char*) pixel + datasize * firstchan;
852 memcpy(result, pixel, datasize * nchannelsArg);
859 float* result,
int firstchan,
int nchannelsArg,
862 memset(result, 0,
sizeof(*result)*nchannelsArg);
866 if (nchannelsArg <= 0)
return;
876 data->getPixel(u, v, pixel);
882 pixel = (
char*) pixel + datasize * firstchan;
886 memcpy(result, pixel, datasize * nchannelsArg);
899 int rfaceid = levelid == 0 ? faceid :
_rfaceids[faceid];
900 fdh = level->
fdh[rfaceid];
909 Res level_res(fi.res.ulog2 - levelid, fi.res.vlog2 - levelid);
912 uint32_t tileheadersize;
913 readBlock(&tileheadersize,
sizeof(tileheadersize));
914 int ntiles = level_res.ntiles(tileres);
915 std::vector<FaceDataHeader> tiledFace_fdh(ntiles);
919 size =
sizeof(tileres) +
sizeof(tileheadersize) + tileheadersize;
920 for (
auto fdh : tiledFace_fdh) {
943 reducefn(_data,
_pixelsize * _res.u(), _res.u(), _res.v(),
989 newtileres = _tileres;
991 if (newtileres.ulog2 > newres.ulog2) newtileres.ulog2 = newres.ulog2;
992 if (newtileres.vlog2 > newres.vlog2) newtileres.vlog2 = newres.vlog2;
997 int newntiles = newres.ntiles(newtileres);
999 if (newntiles == 1) {
1003 bool allConstant =
true;
1004 for (
int i = 0; i < _ntiles; i++) {
1006 allConstant = (allConstant && tile->
isConstant() &&
1016 else if (isTriangle) {
1019 int tileures = _tileres.u();
1020 int tilevres = _tileres.v();
1022 int dstride = sstride * _ntilesu;
1023 int dstepv = dstride * tilevres - sstride*(_ntilesu-1);
1025 char* tmp =
new char [_ntiles * _tileres.size64() *
_pixelsize];
1027 for (
int i = 0; i < _ntiles;) {
1035 tmpptr += (i%_ntilesu) ? sstride : dstepv;
1043 reducefn(tmp,
_pixelsize * _res.u(), _res.u(), _res.v(),
1054 int tileures = _tileres.u();
1055 int tilevres = _tileres.v();
1058 int dstepu = dstride/_ntilesu;
1059 int dstepv = dstride*newres.v()/_ntilesv - dstepu*(_ntilesu-1);
1061 char* dst = (
char*) newface->
getData();
1062 for (
int i = 0; i < _ntiles;) {
1066 newres.u()/_ntilesu, newres.v()/_ntilesv,
1069 reducefn(tile->
getData(), sstride, tileures, tilevres,
1070 dst, dstride, _dt, _nchan);
1072 dst += (i%_ntilesu) ? dstepu : dstepv;
1076 for (
int i = 0; i < _ntiles; i++) tiles[i]->
release();
1090 int tileu = ui >> _tileres.ulog2;
1091 int tilev = vi >> _tileres.vlog2;
1093 tile->getPixel(ui - (tileu<<_tileres.ulog2),
1094 vi - (tilev<<_tileres.vlog2), result);
1108 int pntilesu = _parentface->ntilesu();
1109 int pntilesv = _parentface->ntilesv();
1110 int nu = pntilesu / _ntilesu;
1111 int nv = pntilesv / _ntilesv;
1113 int ntilesval = nu*nv;
1115 bool allConstant =
true;
1116 int ptile = (tile/_ntilesu) * nv * pntilesu + (tile%_ntilesu) * nu;
1117 for (
int i = 0; i < ntilesval;) {
1119 allConstant = (allConstant && tileval->
isConstant() &&
1123 ptile += (i%nu)? 1 : pntilesu - nu + 1;
1127 size_t newMemUsed = 0;
1141 int ptileures = _parentface->tileres().u();
1142 int ptilevres = _parentface->tileres().v();
1145 int dstepu = dstride/nu;
1146 int dstepv = dstride*_tileres.v()/nv - dstepu*(nu-1);
1148 char* dst = (
char*) newface->
getData();
1149 for (
int i = 0; i < ntilesval;) {
1153 _tileres.u()/nu, _tileres.v()/nv,
1156 _reducefn(tileval->
getData(), sstride, ptileures, ptilevres,
1157 dst, dstride, _dt, _nchan);
1159 dst += (i%nu) ? dstepu : dstepv;
1167 _reader->increaseMemUsed(newMemUsed);
const int FaceDataHeaderSize
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.
Automatically acquire and release lock within enclosing scope.
Custom handler interface redirecting Ptex error messages.
virtual void reportError(const char *error)=0
Per-face texture data accessor.
virtual void * getData()=0
Access the data from this data block.
virtual PtexFaceData * getTile(int tile)=0
Access a tile from the data block.
virtual bool isConstant()=0
True if this data block is constant.
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.
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
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
void readTile(int tile, FaceData *&data)
std::vector< FilePos > _offsets
virtual PtexFaceData * getTile(int tile)
Access a tile from the data block.
DataType datatype() const
void readMetaDataBlock(MetaData *metadata, FilePos pos, int zipsize, int memsize, size_t &metaDataMemUsed)
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)
FaceData * errorData(bool deleteOnRelease=false)
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)
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)
Level * getLevel(int levelid)
void readFace(int levelid, Level *level, int faceid, Res res)
std::vector< uint32_t > _rfaceids
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)
virtual void * getConstantData(int faceid) final
Access the constant (or average) data value for a given face.
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)
int DataSize(DataType dt)
Look up size of given data type (in bytes).
DataType
Type of data stored in texture file.
@ dt_float
Single-precision (32-bit) floating point.
@ mt_triangle
Mesh is triangle-based.
@ mt_quad
Mesh is quad-based.
Information about a face, as stored in the Ptex file header.
Pixel resolution of a given texture.