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,
284 if (mt == mt_triangle)
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;
363 addMetaData(key, mdt_string, value,
int(strlen(value)+1));
375 addMetaData(key, mdt_int16, value, count*(
int)
sizeof(int16_t));
381 addMetaData(key, mdt_int32, value, count*(
int)
sizeof(int32_t));
387 addMetaData(key, mdt_float, value, count*(
int)
sizeof(
float));
393 addMetaData(key, mdt_double, value, count*(
int)
sizeof(
double));
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);
616 bool diff = (
datatype() == dt_uint8 ||
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--) {
1095 int min = face.isConstant() ? 1 :
PtexUtils::min(res.ulog2, res.vlog2);
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);
const int MetaDataThreshold
#define PTEX_NAMESPACE_END
#define PtexFileMinorVersion
#define PtexFileMajorVersion
Public API classes for reading, writing, caching, and filtering Ptex files.
Automatically acquire and release lock within enclosing scope.
virtual bool close(Ptex::String &error)
Close the file.
PtexIncrWriter(const char *path, FILE *fp, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces)
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
virtual ~PtexIncrWriter()
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
void generateReductions()
std::vector< uint8_t > _constdata
std::vector< uint32_t > _rfaceids
virtual bool close(Ptex::String &error)
Close the file.
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
std::vector< uint32_t > _faceids_r
void storeConstValue(int faceid, const void *data, int stride, Res res)
std::vector< FaceInfo > _faceinfo
void writeMetaData(FILE *fp)
virtual ~PtexMainWriter()
static const int MinReductionLog2
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
PtexMainWriter(const char *path, PtexTexture *tex, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool genmipmaps)
std::vector< FilePos > _rpos
std::vector< LevelRec > _levels
void flagConstantNeighorhoods()
Smart-pointer for acquiring and releasing API objects.
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
virtual PtexMetaData * getMetaData()
Access meta data.
virtual void getData(int faceid, void *buffer, int stride)
Access texture data for a face at highest-resolution.
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
virtual bool hasEdits()
True if the file has edit blocks.
Interface for reading data from a ptex file.
virtual Ptex::MeshType meshType()=0
Type of mesh for which texture data is defined.
virtual Ptex::BorderMode uBorderMode()=0
Mode for filtering texture access beyond mesh border.
virtual bool hasMipMaps()=0
True if the file has mipmaps.
virtual int numFaces()=0
Number of faces stored in file.
virtual Ptex::DataType dataType()=0
Type of data stored in file.
virtual int alphaChannel()=0
Index of alpha channel (if any).
virtual Ptex::EdgeFilterMode edgeFilterMode()=0
Mode for filtering textures across edges.
static PtexTexture * open(const char *path, Ptex::String &error, bool premultiply=0)
Open a ptex file for reading.
virtual bool hasEdits()=0
True if the file has edit blocks.
virtual Ptex::BorderMode vBorderMode()=0
Mode for filtering texture access beyond mesh border.
virtual int numChannels()=0
Number of channels stored in file.
std::map< std::string, int > _metamap
DataType datatype() const
int writeBlank(FILE *fp, int size)
virtual void setEdgeFilterMode(Ptex::EdgeFilterMode edgeFilterMode)
Set edge filter mode.
int copyBlock(FILE *dst, FILE *src, FilePos pos, int size)
void setError(const std::string &error)
int writeZipBlock(FILE *fp, const void *data, int size, bool finish=true)
virtual void writeMeta(const char *key, const char *value)
Write a string as meta data.
virtual void addMetaData(const char *key, MetaDataType t, const void *value, int size)
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
int writeBlock(FILE *fp, const void *data, int size)
virtual bool close(Ptex::String &error)
Close the file.
void writeFaceData(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
int readBlock(FILE *fp, void *data, int size)
std::vector< MetaEntry > _metadata
void writeConstFaceBlock(FILE *fp, const void *data, FaceDataHeader &fdh)
int writeMetaDataBlock(FILE *fp, MetaEntry &val)
PtexUtils::ReduceFn * _reduceFn
void writeReduction(FILE *fp, const void *data, int stride, Res res)
bool storeFaceInfo(int faceid, FaceInfo &dest, const FaceInfo &src, int flags=0)
virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode)
Set border modes.
virtual ~PtexWriterBase()
void getError(Ptex::String &error)
PtexWriterBase(const char *path, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool compress)
bool ok(Ptex::String &error)
void writeFaceBlock(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
Res calcTileRes(Res faceres)
Interface for writing data to a ptex file.
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.
static bool applyEdits(const char *path, Ptex::String &error)
Apply edits to a file.
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.
const char * c_str() const
bool checkFormat(Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, Ptex::String &error)
FILE * OpenTempFile(std::string &tmppath)
std::string fileError(const char *message, const char *path)
void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
bool isConstant(const void *data, int stride, int ures, int vres, int pixelSize)
void divalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
void encodeDifference(void *data, int size, DataType dt)
void reduce(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
void deinterleave(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
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)
uint32_t floor_log2(uint32_t x)
void multalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
void average(const void *src, int sstride, int uw, int vw, void *dst, DataType dt, int nchan)
DataType
Type of data stored in texture file.
@ dt_float
Single-precision (32-bit) floating point.
MeshType
Type of base mesh for which the textures are defined.
@ mt_quad
Mesh is quad-based.
@ m_clamp
texel access is clamped to border
std::vector< FilePos > pos
std::vector< FaceDataHeader > fdh
std::vector< uint8_t > data
Information about a face, as stored in the Ptex file header.
Res res
Resolution of face.
bool isConstant() const
Determine if face is constant (by checking a flag).
Pixel resolution of a given texture.
int size() const
Total size of specified texture in texels (u * v).
int u() const
U resolution in texels.