84 static std::string tmpdir;
85 static int initialized = 0;
88 #ifdef PTEX_PLATFORM_WINDOWS
90 DWORD result = ::GetTempPath(0, (LPTSTR) L
"");
92 std::vector<TCHAR> tempPath(result + 1);
93 result = ::GetTempPath(static_cast<DWORD>(tempPath.size()), &tempPath[0]);
94 if (result > 0 && result <= tempPath.size())
95 tmpdir = std::string(tempPath.begin(),
96 tempPath.begin() +
static_cast<std::size_t
>(result));
102 const char* t = getenv(
"TEMP");
103 if (!t) t = getenv(
"TMP");
111 #ifdef PTEX_PLATFORM_WINDOWS
114 static int count = 0;
115 s << tmpdir <<
"/" <<
"PtexTmp" << _getpid() <<
"_" << ++count;
117 return fopen((
char*) tmppath.c_str(),
"wb+");
120 tmppath = tmpdir +
"/PtexTmpXXXXXX";
121 int fd = mkstemp(&tmppath[0]);
122 return fdopen(fd,
"w+");
126 std::string
fileError(
const char* message,
const char* path)
128 std::stringstream str;
129 str << message << path <<
"\n" << strerror(errno);
138 error =
"PtexWriter doesn't currently support big-endian cpu's";
143 error =
"PtexWriter error: Invalid mesh type";
148 error =
"PtexWriter error: Invalid data type";
152 if (nchannels <= 0) {
153 error =
"PtexWriter error: Invalid number of channels";
157 if (alphachan != -1 && (alphachan < 0 || alphachan >= nchannels)) {
158 error =
"PtexWriter error: Invalid alpha channel";
169 int nchannels,
int alphachan,
int nfaces,
172 if (!
checkFormat(mt, dt, nchannels, alphachan, error))
176 mt, dt, nchannels, alphachan, nfaces,
188 int nchannels,
int alphachan,
int nfaces,
191 if (!
checkFormat(mt, dt, nchannels, alphachan, error))
195 FILE* fp = fopen(path,
"rb+");
196 if (!fp && errno != ENOENT) {
197 error =
fileError(
"Can't open ptex file for update: ", path).c_str();
202 if (incremental && fp) {
203 w =
new PtexIncrWriter(path, fp, mt, dt, nchannels, alphachan, nfaces);
217 bool headerMatch = (mt == tex->
meshType() &&
223 std::stringstream str;
224 str <<
"PtexWriter::edit error: header doesn't match existing file, "
225 <<
"conversions not currently supported";
226 error = str.str().
c_str();
255 if (!w->
close(error))
return 0;
263 int nchannels,
int alphachan,
int nfaces,
290 deflateInit(&
_zstream, compress ? Z_DEFAULT_COMPRESSION : 0);
306 std::cerr << error.
c_str() << std::endl;
332 setError(
"PtexWriter error: faceid out of range");
337 setError(
"PtexWriter error: asymmetric face res not supported for triangle textures");
352 f.flags &= FaceInfo::flag_subface;
356 f.flags |= (uint8_t)flags;
400 for (
int i = 0; i < nkeys; i++) {
403 data->
getKey(i, key, type);
422 const int16_t* val=0;
429 const int32_t* val=0;
454 const void* value,
int size)
456 if (strlen(key) > 255) {
457 std::stringstream str;
458 str <<
"PtexWriter error: meta data key too long (max=255) \"" << key <<
"\"";
463 std::stringstream str;
464 str <<
"PtexWriter error: meta data size <= 0 for \"" << key <<
"\"";
467 std::map<std::string,int>::iterator iter =
_metamap.find(key);
471 index = iter->second;
483 memcpy(&m.
data[0], value, size);
502 if (!fwrite(data, size, 1, fp)) {
503 setError(
"PtexWriter error: file write failed");
514 _zstream.next_in = (Bytef*) const_cast<void*>(data);
520 int zresult = deflate(&
_zstream, finishArg ? Z_FINISH : Z_NO_FLUSH);
522 if (sizeval > 0)
writeBlock(fp, buff, sizeval);
523 if (zresult == Z_STREAM_END)
break;
524 if (zresult != Z_OK) {
525 setError(
"PtexWriter error: data compression internal error");
528 if (!finishArg &&
_zstream.avail_out != 0)
533 if (!finishArg)
return 0;
535 int total = (int)
_zstream.total_out;
543 if (!fread(data, size, 1, fp)) {
544 setError(
"PtexWriter error: temp file read failed");
553 if (size <= 0)
return 0;
554 fseeko(src, pos, SEEK_SET);
559 if (!fread(buff, nbytes, 1, src)) {
560 setError(
"PtexWriter error: temp file read failed");
575 if (ntileslog2 == 0)
return faceres;
581 int n = faceres.ulog2 + faceres.vlog2 - ntileslog2;
586 tileres.ulog2 = (int8_t)
PtexUtils::min(
int((n+1)/2), int(faceres.ulog2));
587 tileres.vlog2 = (int8_t)
PtexUtils::min(
int(n - tileres.ulog2), int(faceres.vlog2));
607 int ures = res.u(), vres = res.v();
610 char* buff = useNew ?
new char [blockSize] : (
char*)alloca(blockSize);
625 if (useNew)
delete [] buff;
634 int ntilesu = res.ntilesu(tileres);
635 int ntilesv = res.ntilesv(tileres);
636 int ntiles = ntilesu * ntilesv;
645 std::vector<FaceDataHeader> tileHeader(ntiles);
646 int tileures = tileres.u();
647 int tilevres = tileres.v();
649 int tilevstride = tilevres*stride;
654 const char* rowp = (
const char*) data;
655 const char* rowpend = rowp + ntilesv * tilevstride;
656 for (; rowp != rowpend; rowp += tilevstride) {
657 const char* p = rowp;
658 const char* pend = p + ntilesu * tileustride;
659 for (; p != pend; tdh++, p += tileustride) {
676 totalsize +=
writeBlock(fp, &tileres,
sizeof(Res));
677 totalsize +=
writeBlock(fp, &tileheadersize,
sizeof(tileheadersize));
693 Ptex::Res newres((int8_t)(res.ulog2-1), (int8_t)(res.vlog2-1));
696 char* buff = useNew ?
new char [buffsize] : (
char*)alloca(buffsize);
702 if (useNew)
delete [] buff;
709 uint8_t keysize = uint8_t(val.
key.size()+1);
711 uint32_t datasize = uint32_t(val.
data.size());
717 int memsize = int(
sizeof(keysize) + (
size_t)keysize +
sizeof(datatype)
718 +
sizeof(datasize) + datasize);
725 int nchannels,
int alphachan,
int nfaces,
bool genmipmaps)
729 _genmipmaps(genmipmaps),
746 for (
int i = 0; i < nfaces; i++)
_faceinfo[i].flags = uint8_t(-1);
748 _levels.front().pos.resize(nfaces);
749 _levels.front().fdh.resize(nfaces);
750 _rpos.resize(nfaces);
796 unlink(
_path.c_str());
798 error =
fileError(
"Can't write to ptex file: ",
_path.c_str()).c_str();
811 if (stride == 0) stride = f.res.u()*
_pixelSize;
833 int rowlen = f.res.u() *
_pixelSize, nrows = f.res.v();
834 temp =
new uint8_t [rowlen * nrows];
857 if (temp)
delete [] temp;
908 char* data =
new char [size];
920 _faceinfo[i].flags = FaceInfo::flag_constant;
936 FILE* newfp = fopen(
_newpath.c_str(),
"wb+");
954 FilePos levelInfoPos = ftello(newfp);
963 int nfaces = int(level.
fdh.size());
970 for (
int fi = 0; fi < nfaces; fi++)
972 level.
fdh[fi].blocksize());
985 fseeko(newfp, levelInfoPos, SEEK_SET);
989 fseeko(newfp, 0, SEEK_SET);
999 for (
int faceid = 0, n =
int(
_faceinfo.size()); faceid < n; faceid++) {
1001 if (!f.isConstant())
continue;
1005 bool isConst =
true;
1007 int nedges = isTriangle ? 3 : 4;
1008 for (
int eid = 0; isConst && (eid < nedges); eid++) {
1009 bool prevWasSubface = f.isSubface();
1010 int prevFid = faceid;
1013 int afid = f.adjface(eid);
1014 int aeid = f.adjedge(eid);
1016 const int maxcount = 10;
1017 while (afid != faceid && afid >= 0 && ++count < maxcount) {
1020 if (!af.isConstant() ||
1022 { isConst =
false;
break; }
1025 bool isSubface = af.isSubface();
1026 bool isT = !isTriangle && prevWasSubface && !isSubface && af.adjface(aeid) == prevFid;
1028 prevWasSubface = isSubface;
1032 aeid = (aeid + 1) % nedges;
1033 afid = af.adjface(aeid);
1034 aeid = af.adjedge(aeid);
1045 aeid = (aeid - 1 + nedges) % nedges;
1046 afid = f.adjface(aeid);
1047 aeid = f.adjedge(aeid);
1049 while (afid != faceid && afid >= 0 && ++count < maxcount) {
1052 if (!af.isConstant() ||
1054 { isConst =
false;
break; }
1058 aeid = (aeid - 1 + nedges) % nedges;
1059 afid = af.adjface(aeid);
1060 aeid = af.adjedge(aeid);
1063 bool isSubface = af.isSubface();
1064 if (isSubface && !prevWasSubface) {
1065 aeid = (aeid + 3) % 4;
1066 afid = af.adjface(aeid);
1067 aeid = (af.adjedge(aeid) + 3) % 4;
1069 prevWasSubface = isSubface;
1074 if (isConst) f.flags |= FaceInfo::flag_nbconstant;
1091 for (
int rfaceid = nfaces-1, cutoffres =
MinReductionLog2; rfaceid >= 0; rfaceid--) {
1096 while (min > cutoffres) {
1098 int size = rfaceid+1;
1101 level.
pos.resize(size);
1102 level.
fdh.resize(size);
1110 for (
int i = 0; i < nfaces; i++)
1113 char* buff =
new char [buffsize];
1115 int nlevels = int(
_levels.size());
1116 for (
int i = 1; i < nlevels; i++) {
1118 int nextsize = (i+1 < nlevels)?
int(
_levels[i+1].fdh.size()) : 0;
1119 for (
int rfaceid = 0, size =
int(level.
fdh.size()); rfaceid < size; rfaceid++) {
1123 res.ulog2 = (int8_t)(res.ulog2 - i);
1124 res.vlog2 = (int8_t)(res.vlog2 - i);
1129 fseeko(
_tmpfp, 0, SEEK_END);
1135 if (rfaceid < nextsize) {
1145 fseeko(
_tmpfp, 0, SEEK_END);
1152 std::vector<MetaEntry*> lmdEntries;
1155 for (
int i = 0, n = (
int)
_metadata.size(); i < n; i++) {
1157 #ifndef PTEX_NO_LARGE_METADATA_BLOCKS
1160 lmdEntries.push_back(&e);
1178 int nLmd = (int)lmdEntries.size();
1181 std::vector<FilePos> lmdoffset(nLmd);
1182 std::vector<uint32_t> lmdzipsize(nLmd);
1183 for (
int i = 0; i < nLmd; i++) {
1185 lmdoffset[i] = ftello(
_tmpfp);
1190 for (
int i = 0; i < nLmd; i++) {
1192 uint8_t keysize = uint8_t(e->
key.size()+1);
1194 uint32_t datasize = (uint32_t)e->
data.size();
1195 uint32_t zipsize = lmdzipsize[i];
1203 (uint32_t)(
sizeof(keysize) + (size_t)keysize +
sizeof(datatype) +
1204 sizeof(datasize) +
sizeof(zipsize));
1209 for (
int i = 0; i < nLmd; i++) {
1219 int nchannels,
int alphachan,
int nfaces)
1232 std::stringstream str;
1233 str <<
"Not a ptex file: " << path;
1244 std::stringstream str;
1245 str <<
"PtexWriter::edit error: header doesn't match existing file, "
1246 <<
"conversions not currently supported";
1254 std::stringstream str;
1255 str <<
"Error reading extended header: " << path;
1261 fseeko(
_fp, 0, SEEK_END);
1272 if (stride == 0) stride = f.res.u()*
_pixelSize;
1290 writeBlank(
_fp,
sizeof(edittype) +
sizeof(editsize) +
sizeof(efdh));
1293 uint8_t* constval =
new uint8_t [
_pixelSize];
1298 int rowlen = f.res.u() *
_pixelSize, nrows = f.res.v();
1299 uint8_t* temp =
new uint8_t [rowlen * nrows];
1329 fseeko(
_fp, pos, SEEK_SET);
1333 fseeko(
_fp, 0, SEEK_END);
1346 editsize = (uint32_t)
sizeof(efdh) +
_pixelSize;
1373 writeBlank(
_fp,
sizeof(edittype) +
sizeof(editsize) +
sizeof(emdh));
1376 for (
size_t i = 0, n =
_metadata.size(); i < n; i++) {
1387 fseeko(
_fp, pos, SEEK_SET);
1391 fseeko(
_fp, 0, SEEK_END);
bool isConstant(const void *data, int stride, int ures, int vres, int pixelSize)
virtual Ptex::BorderMode vBorderMode()=0
Mode for filtering texture access beyond mesh border.
virtual int numChannels()=0
Number of channels stored in file.
Interface for writing data to a ptex file.
void getError(Ptex::String &error)
bool storeFaceInfo(int faceid, FaceInfo &dest, const FaceInfo &src, int flags=0)
virtual ~PtexWriterBase()
virtual bool close(Ptex::String &error)
Close the file.
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
void writeReduction(FILE *fp, const void *data, int stride, Res res)
DataType datatype() const
uint32_t floor_log2(uint32_t x)
virtual bool hasEdits()
True if the file has edit blocks.
const int MetaDataThreshold
bool isConstant() const
Determine if face is constant (by checking a flag).
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
virtual bool hasEdits()=0
True if the file has edit blocks.
std::vector< FaceDataHeader > fdh
PtexUtils::ReduceFn * _reduceFn
void writeFaceData(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
texel access is clamped to border
void writeMetaData(FILE *fp)
void deinterleave(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
bool ok(Ptex::String &error)
std::vector< uint32_t > _rfaceids
virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode)
Set border modes.
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
void storeConstValue(int faceid, const void *data, int stride, Res res)
Single-precision (32-bit) floating point.
virtual PtexMetaData * getMetaData()
Access meta data.
std::vector< FaceInfo > _faceinfo
void generateReductions()
virtual bool close(Ptex::String &error)
Close the file.
virtual int alphaChannel()=0
Index of alpha channel (if any).
static PtexWriter * open(const char *path, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, Ptex::String &error, bool genmipmaps=true)
Open a new texture file for writing.
void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
static const int MinReductionLog2
int writeMetaDataBlock(FILE *fp, MetaEntry &val)
void reduce(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
Double-precision (32-bit) floating point.
void setError(const std::string &error)
virtual Ptex::MeshType meshType()=0
Type of mesh for which texture data is defined.
void reduceTri(const void *src, int sstride, int w, int, void *dst, int dstride, DataType dt, int nchan)
int writeZipBlock(FILE *fp, const void *data, int size, bool finish=true)
int u() const
U resolution in texels.
static PtexTexture * open(const char *path, Ptex::String &error, bool premultiply=0)
Open a ptex file for reading.
void average(const void *src, int sstride, int uw, int vw, void *dst, DataType dt, int nchan)
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
FILE * OpenTempFile(std::string &tmppath)
MeshType
Type of base mesh for which the textures are defined.
Unsigned, 16-bit integer.
void encodeDifference(void *data, int size, DataType dt)
#define PtexFileMinorVersion
virtual bool hasMipMaps()=0
True if the file has mipmaps.
int copyBlock(FILE *dst, FILE *src, FilePos pos, int size)
PtexMainWriter(const char *path, PtexTexture *tex, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool genmipmaps)
std::string fileError(const char *message, const char *path)
int writeBlock(FILE *fp, const void *data, int size)
virtual ~PtexMainWriter()
int readBlock(FILE *fp, void *data, int size)
virtual void addMetaData(const char *key, MetaDataType t, const void *value, int size)
virtual int numFaces()=0
Number of faces stored in file.
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
virtual bool close(Ptex::String &error)
Close the file.
#define PtexFileMajorVersion
virtual void getData(int faceid, void *buffer, int stride)
Access texture data for a face at highest-resolution.
bool checkFormat(Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, Ptex::String &error)
int size() const
Total size of specified texture in texels (u * v).
PtexWriterBase(const char *path, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool compress)
virtual Ptex::DataType dataType()=0
Type of data stored in file.
std::vector< FilePos > _rpos
std::vector< FilePos > pos
Smart-pointer for acquiring and releasing API objects.
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
std::vector< LevelRec > _levels
void flagConstantNeighorhoods()
virtual ~PtexIncrWriter()
virtual Ptex::EdgeFilterMode edgeFilterMode()=0
Mode for filtering textures across edges.
void divalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Res calcTileRes(Res faceres)
Interface for reading data from a ptex file.
static bool applyEdits(const char *path, Ptex::String &error)
Apply edits to a file.
std::vector< uint32_t > _faceids_r
Pixel resolution of a given texture.
Automatically acquire and release lock within enclosing scope.
int writeBlank(FILE *fp, int size)
virtual Ptex::BorderMode uBorderMode()=0
Mode for filtering texture access beyond mesh border.
Single-precision (32-bit) floating point.
int DataSize(DataType dt)
Look up size of given data type (in bytes).
Res res
Resolution of face.
MetaDataType
Type of meta data entry.
void multalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Information about a face, as stored in the Ptex file header.
std::vector< MetaEntry > _metadata
virtual bool close(Ptex::String &error)=0
Close the file.
virtual void writeMeta(const char *key, const char *value)
Write a string as meta data.
PtexIncrWriter(const char *path, FILE *fp, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces)
std::map< std::string, int > _metamap
void writeConstFaceBlock(FILE *fp, const void *data, FaceDataHeader &fdh)
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
void writeFaceBlock(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
virtual void setEdgeFilterMode(Ptex::EdgeFilterMode edgeFilterMode)
Set edge filter mode.
DataType
Type of data stored in texture file.
std::vector< uint8_t > data
const char * c_str() const
#define PTEX_NAMESPACE_END
void copy(const void *src, int sstride, void *dst, int dstride, int vres, int rowlen)
Public API classes for reading, writing, caching, and filtering Ptex files.
std::vector< uint8_t > _constdata
static PtexWriter * edit(const char *path, bool incremental, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, Ptex::String &error, bool genmipmaps=true)
Open an existing texture file for writing.