41#include <libdeflate.h>
52 virtual void reportError(
const char* error) {
55 const std::string& getErrorString()
const {
return _error; }
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;
172 if (!(
_header.meshtype == mt_triangle ||
_header.meshtype == mt_quad)) {
174 s <<
"Invalid mesh type (" <<
_header.meshtype <<
"): " << pathArg;
184 TempErrorHandler tempErr;
199 pos +=
sizeof(uint64_t);
214 error = tempErr.getErrorString();
225 if (!
readlock.trylock())
return false;
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);
312 for (
int i = 0; i <
_header.nlevels; i++) {
347 if (index < 0 || index >=
int(
_entries.size())) {
393 size_t metaDataMemUsed =
sizeof(
MetaData);
398 _header.metadatazipsize,
_header.metadatamemsize, metaDataMemUsed);
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;
470 int result = (int)
_io->read(data, size,
_fp);
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;
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);
652 if (!
_ok || faceid < 0 ||
size_t(faceid) >=
_header.nfaces) {
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;
701 if (!
_ok || faceid < 0 ||
size_t(faceid) >=
_header.nfaces) {
706 if (fi.isConstant() || fi.res == 0) {
719 if (!
_ok || faceid < 0 ||
size_t(faceid) >=
_header.nfaces) {
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;
778 else if (
_header.meshtype == mt_triangle)
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;
814 face =
_reductions.tryInsert(key, newface, tableNewMemUsed);
815 if (face != newface) {
826 float* result,
int firstchan,
int nchannelsArg)
828 memset(result, 0,
sizeof(*result)*nchannelsArg);
831 nchannelsArg = std::min(nchannelsArg,
_header.nchannels-firstchan);
832 if (nchannelsArg <= 0)
return;
836 if (faceid >= 0 &&
size_t(faceid) <
_header.nfaces &&
_faceinfo[faceid].isConstant()) {
842 data->getPixel(u, v, pixel);
846 int datasize = DataSize(
datatype());
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);
865 nchannelsArg = std::min(nchannelsArg,
_header.nchannels-firstchan);
866 if (nchannelsArg <= 0)
return;
870 if (faceid >= 0 &&
size_t(faceid) <
_header.nfaces &&
_faceinfo[faceid].isConstant()) {
876 data->getPixel(u, v, pixel);
880 int datasize = DataSize(
datatype());
882 pixel = (
char*) pixel + datasize * firstchan;
886 memcpy(result, pixel, datasize * nchannelsArg);
894 if (!
_ok || faceid < 0 ||
size_t(faceid) >=
_header.nfaces ||
size_t(levelid) >=
_levels.size()) {
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) {
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) {
1023 int dstepv = dstride * tilevres - sstride*(
_ntilesu-1);
1027 for (
int i = 0; i <
_ntiles;) {
1035 tmpptr += (i%
_ntilesu) ? sstride : dstepv;
1061 char* dst = (
char*) newface->
getData();
1062 for (
int i = 0; i <
_ntiles;) {
1069 reducefn(tile->
getData(), sstride, tileures, tilevres,
1072 dst += (i%
_ntilesu) ? dstepu : dstepv;
1093 tile->getPixel(ui - (tileu<<
_tileres.ulog2),
1094 vi - (tilev<<
_tileres.vlog2), result);
1113 int ntilesval = nu*nv;
1115 bool allConstant =
true;
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;
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;) {
1159 dst += (i%nu) ? dstepu : dstepv;
1167 _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.
Smart-pointer for acquiring and releasing API objects.
T * get() const
Get pointer value.
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 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
TiledFaceBase * _parentface
virtual PtexFaceData * getTile(int tile)
Access a tile from the data block.
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.
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.